字典树 trie树

本文地址:http://blog.csdn.net/spch2008/article/details/9138557

使用字典树来存储数据,数据是一个键值对,即键值-数值。

字典树允许数据键值共享相同的前缀。本文采用的键值为字符串,数据如下:

amy     56
ann     15
emma    30
rob     27
roger   52

首先存入amy, level 0表示根,不持有数据。其余每个节点持有一个字符;叶子节点持有数据,且持有的字符为’\0′

      .     <- level 0 (root)
      |
      a     <- level 1
      |
      m     <- level 2
      |
      y     <- level 3
      |
    \0 56   <- level 4

添加ann后,后缀树如下,二者共享前缀’a’

         .
         |
         a
       /   \
      m     n
      |     |
      y     n
      |     |
    \0 56 \0 15

下面加入emma,由于emma与之前添加的键值没有相同前缀,所以直接加入根节点下。

              .
          /       \
         a         e
       /   \       |
      m     n      m
      |     |      |
      y     n      m
      |     |      |
    \0 56 \0 15    a
                   |
                 \0 30

将rob与roger加入后,所得字典树如下:

                  .
          /       |      \
         a        e       r
       /   \      |       |
      m     n     m       o
      |     |     |     /   \
      y     n     m    b     g
      |     |     |    |     |
    \0 56 \0 15   a  \0 27   e
                  |          |
                \0 30        r
                             |
                           \0 52

现在有2个问题:

    如果继续添加anne为67,将出现什么状况?

    每个节点有多少个子节点?

解决办法:

    1. 每个节点存放一个数组,可以容纳所有键值中的字符

    2. 采用链表

    3. 左儿子右兄弟表示法

这里我们采用左孩子右兄弟的表示方法。上述数据可以表示为:     

       |
       a --------- e ----- r
       |           |       |
       m --- n     m       o
       |     |     |       |
       y     n     m       b ----- g
       |     |     |       |       |
     \0 56 \0 15   a     \0 27     e
                   |               |
                 \0 30             r
                                   |
                                 \0 52

.h

class TrieTree
{
private:
    struct Node
    {
        char key;
        int  val;
        Node *next, *child;

        Node(char k =' ', int v = 0)
        {
            key = k;
            val = v;
            next = child = NULL;
        }
    };

public:
    TrieTree(void);
    ~TrieTree(void);

    bool IsMember(char str[]);
    void Add(char str[], int val);
    void Remove(char str[]);
    int  GetVal(char str[]);
private:
    Node *root;


    Node* _Insert(Node* subtree, char *str, int val);
    Node* _CreateSubTree(char *str, int val);
    Node* _Delete(Node* subtree, char *str);
    Node* _Find(char *str);
    void  _Destroy(Node* subtree);
};

.cpp

TrieTree::TrieTree(void)
{
    root = new Node;
    root->next = root->child = NULL;
}


TrieTree::~TrieTree(void)
{
    _Destroy(root);
}


bool TrieTree::IsMember(char str[])
{
    Node *found = _Find(str);
    
    return found != NULL;
}



void TrieTree::Add(char str[], int val)
{
    root->next = _Insert(root->next, str, val);
}


void TrieTree::Remove(char str[])
{
    root->next = _Delete(root->next, str);
}


int TrieTree::GetVal(char str[])
{
    Node *found = _Find(str);

    if(found == NULL)
        return -1;
    else
        return found->val;
}

TrieTree::Node* TrieTree::_Insert(Node* subtree, char *str, int val)
{
    if(subtree == NULL)
    {
        subtree =  _CreateSubTree(str, val);
    }
    else if(subtree->key != str[0])
    {
        subtree->next =  _Insert(subtree->next, str, val);
    }
    else
    {
        if(str[0] == '\0')     //修改原值
            subtree->val = val;
        else
            subtree->child =  _Insert(subtree->child, &str[1], val);
    }
    return subtree;
}


void TrieTree::_Destroy(Node *subtree)
{
    if(subtree != NULL)
    {
        _Destroy(subtree->child);
        _Destroy(subtree->next);
        delete subtree;
    }
}

TrieTree::Node* TrieTree::_Find(char *str)
{
    int index = 0;
    Node *level = root->next;

    while(true)
    {
        Node *found = NULL;
        //当前层匹配
        for(Node *curr = level; curr != NULL; curr = curr->next)
        {
            if(curr->key == str[index])
            {
                found = curr;
                break;
            }
        }

        if(found == NULL)
            return NULL;

        //不能found->key == str[index]
        //str可以先匹配完成
        if(str[index] == '\0')
            return found;

        //匹配上后,向下在孩子中匹配
        level = found ->child;
        index += 1;
    }

    return NULL;
}


TrieTree::Node* TrieTree::_Delete(Node* subtree, char *str)
{
    if(subtree == NULL)
        return NULL;

    if(subtree->key != str[0])
    {
        subtree->next = _Delete(subtree->next, str);
    }
    else
    {
        if(subtree->key == '\0')
        {
            delete subtree;
            subtree = NULL;
        }
        else
        {
            subtree->child = _Delete(subtree->child, &str[1]);
            if(subtree->next == NULL && subtree->child == NULL)
            {
                delete subtree;
                subtree = NULL;
            }
        }
    }

    return subtree;
}



TrieTree::Node * TrieTree::_CreateSubTree(char *str, int val)
{
    Node *subtree = new Node('\0', val);
    for(int i = strlen(str) - 1; i >= 0; i--)
    {
        Node *node = new Node(str[i]);
        node->child = subtree;
        subtree = node;
    }

    return subtree;	
}

来自:http://www.cs.bu.edu/teaching/c/tree/trie/

    原文作者:Trie树
    原文地址: https://blog.csdn.net/spch2008/article/details/9138557
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞