字典树 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
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞