Trie树的编程实现,用于计算字符串出现次数,求公共前缀字符串等问题

1. 什么是trie树

  1.Trie树 (特例结构树)  

      Trie树 ,又称 单词查找树、字典树 ,是一种 树形结构 ,是一种哈希树的变种,是一种用于快速检索的多叉树结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比 哈希表高。
     Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
     Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.

2.  三个基本特性:  

1)根节点不包含字符,除根节点外每一个节点都只包含一个字符。  
2)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。 
3)每个节点的所有子节点包含的字符都不相同。

3 .例子

       和二叉查找树不同,在trie树中,每个结点上并非存储一个元素。
       trie树把要查找的关键词看作一个字符序列。并根据构成关键词字符的先后顺序构造用于检索的树结构。
       在trie树上进行检索类似于查阅英语词典。
      一棵m度的trie树或者为空,或者由m棵m度的trie树构成。

     例如,电子英文词典,为了方便用户快速检索英语单词,可以建立一棵trie树。例如词典由下面的单词成:a、b、c、aa、ab、ac、ba、ca、aba、abc、baa、bab、bac、cab、abba、baba、caba、abaca、caaba



#include
#include
using namespace std;

struct TrieNode
{
	int freq; //记录字符串的出现次数
	char c;
	TrieNode* parent;
	TrieNode* child[26];
	TrieNode():freq(0), parent(NULL), c('*')
	{
		memset(child, NULL, 26*sizeof(TrieNode*));
	}
};

class TrieTree
{
private:
	TrieNode* root;
	void Traverse(TrieNode* root);
	void BackPrint(TrieNode* aNode);
	void ReleaseTree(TrieNode* root);

public:
	TrieTree()
	{
		root=new TrieNode;
	}
	~TrieTree();

	bool InsertStr(const char* str);
	void PrintWordByPrefix(const char* prefix);
};

TrieTree::~TrieTree()
{
	ReleaseTree(root);
}

void TrieTree::ReleaseTree(TrieNode* root)
{
	if(NULL==root) return;
	for(int i=0; i<26; i++)
		if(root->child[i]!=NULL)
		{
			ReleaseTree(root->child[i]);
		}
	delete root;
}

void TrieTree::BackPrint(TrieNode* aNode)
{
	if(aNode==NULL) return;
	TrieNode* current=aNode;
	vector strs;

	while(current!=NULL)
	{
		strs.push_back(current->c);
		current=current->parent;
	}

	vector::reverse_iterator  ita=strs.rbegin()+1;
	while(ita!=strs.rend())
	{
		printf("%c", *ita);  ita++;
	}
	printf("\n");
}

void TrieTree::Traverse(TrieNode* root)
{
	if(NULL==root) return;

	for(int i=0; i<26; i++)
	{
		if(root->child[i]!=NULL)
		{
			if(root->child[i]->freq>=1) BackPrint(root->child[i]);
			Traverse(root->child[i]);
		}
	}
}

bool TrieTree::InsertStr(const char* str)
{
	const char* ptr=str;
	TrieNode* currNode=root;
	
	while(*ptr!='\0' && currNode!=NULL)
	{
		if(*(ptr+1)=='\0' && currNode->child[*ptr-'a']!=NULL)
		{
			currNode->child[*ptr-'a']->freq++;
			break;
		}
		else if(*(ptr+1)!='\0' && currNode->child[*ptr-'a']!=NULL)
		{
			currNode=currNode->child[*ptr-'a'];
		}
		else if(*(ptr+1)=='\0' && currNode->child[*ptr-'a']==NULL)
		{
			currNode->child[*ptr-'a']=new TrieNode;
			currNode->child[*ptr-'a']->c=*ptr;
			currNode->child[*ptr-'a']->parent=currNode;
			currNode->child[*ptr-'a']->freq++;
			break;
		}
		else
		{
			currNode->child[*ptr-'a']=new TrieNode;
			currNode->child[*ptr-'a']->c=*ptr;
			currNode->child[*ptr-'a']->parent=currNode;
			currNode=currNode->child[*ptr-'a'];
		}

		ptr++;
	}
	return true;
}

void TrieTree::PrintWordByPrefix(const char* prefix)
{
	const char* ptr=prefix;
	TrieNode* currNode=root;

	while(*ptr!='\0' && currNode!=NULL)
	{
		currNode=currNode->child[*ptr-'a'];
		ptr++;
	}
	Traverse(currNode);
}

int main(int argc, char** argv)
{
	TrieTree aTree;

	aTree.InsertStr("nicoyan");
	aTree.InsertStr("dbdsbn");
	aTree.InsertStr("nica");
	aTree.InsertStr("nicdjrtuj");
	aTree.InsertStr("nicghrtjruktyil");
	aTree.InsertStr("nicktykrkrykyjtyigtktily");
	aTree.InsertStr("nicggggggggggggggggggggggggggggg");
	aTree.PrintWordByPrefix("nic");

	return 0;
}

Trie树的编程实现,用于计算字符串出现次数,求公共前缀字符串等问题_第1张图片

你可能感兴趣的:(算法)