这是一个Trie树标准模版
By Leo
本人版权,请勿抄袭!!
先看教程:
1. 什么是trie树
1.Trie树 (特例结构树)
2. 三个基本特性:
3 .例子
和二叉查找树不同,在trie树中,每个结点上并非存储一个元素。trie树把要查找的关键词看作一个字符序列。并根据构成关键词字符的先后顺序构造用于检索的树结构。
在trie树上进行检索类似于查阅英语词典。
例如,电子英文词典,为了方便用户快速检索英语单词,可以建立一棵trie树。例如词典由下面的单词成:a、b、c、aa、ab、ac、ba、ca、aba、abc、baa、bab、bac、cab、abba、baba、caba、abaca、caaba
再举一个例子。给出一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie:
可以看出:
- 每条边对应一个字母。
- 每个节点对应一项前缀。叶节点对应最长前缀,即单词本身。
- 单词inn与单词int有共同的前缀“in”, 因此他们共享左边的一条分支,root->i->in。同理,ate, age, adv, 和ant共享前缀"a",所以他们共享从根节点到节点"a"的边。
查询操纵非常简单。比如要查找int,顺着路径i -> in -> int就找到了。
2. trie树的实现
1.插入过程
对于一个单词,从根开始,沿着单词的各个字母所对应的树中的节点分支向下走,直到单词遍历完,将最后的节点标记为红色,表示该单词已插入trie树。
2. 查找过程
其方法为:
(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
即从根开始按照单词的字母顺序向下遍历trie树,一旦发现某个节点标记不存在或者单词遍历完成而最后的节点未标记为红色,则表示该单词不存在,若最后的节点标记为红色,表示该单词存在。如下图中:trie树中存在的就是abc、d、da、dda四个单词。在实际的问题中可以将标记颜色的标志位改为数量count等其他符合题目要求的变量。
代码上有英文注释,请还是不懂的人看一看。。
再看不懂,本人也无能为力了~~~
代码:
/**
* Leolee 2017(C)
* Trie.cpp
* This is a standard Trie's template by Leolee
* The program has its copyright and you cannot copy it
* before the author allowed.
*/
//Define the TRIE Template here
#ifndef _TRIE_
#define _TRIE_
#include <iostream> //The standard IO stream
#include <sstream> //The standard String library and string stream
#include <cstring> //The C-style string library
#include <cassert> //The C-style assert library
#include <climits> //For using "INT_MIN"
#define MAXNUM 26 //The max num of the children of a node
using namespace std; //using the standard namespace "std"
//define the Trie node here
struct Trie_Node {
string word;//The word
int count; //The number of occurrences of a word
Trie_Node *Next_Branch[MAXNUM];//Pointer to a 26-character node
Trie_Node() : count(0)
{
word.empty();
memset(Next_Branch, NULL, sizeof(Trie_Node*) * MAXNUM);
}
~Trie_Node() {};
};
class Trie {
private:
Trie_Node* ROOT;
private:
void Reset(Trie_Node* Root); //Reset The trie tree
void Print(Trie_Node* Root);
public:
void Insert(string str); //Insert the string str
bool Search(string str, int& cnt); //Find the string str and return the number of occurrences
bool Remove(string str); //Delete the string str
void PrintALL(); //Prints all the nodes in the trie tree
bool PrintPre(string str); //Print a word prefixed with str
Trie() {
ROOT = new Trie_Node(); //Note that the root of the dictionary tree does not hold characters
};
~Trie() {
Reset(ROOT);
};
};
#endif //_TRIE_
//Insert a word
void Trie::Insert(string str)
{
if (str.empty()) return;
Trie_Node *NODE = ROOT;
int len = str.size();
for (int i = 0;i < len;i++)
{
int index = str.at(i) - 'a'; //Case sensitive
if (index < 0 || index > MAXNUM)//No insertion is performed
return;
if (NODE->Next_Branch[index] == NULL) //The prefix of the word does not exist and is to be generated for that node
NODE->Next_Branch[index] = new Trie_Node();
NODE = NODE->Next_Branch[index]; //Go to the next node
}
if (!NODE->word.empty()) //The word has already appeared
{
NODE->count++;
return;
}
else
//The word did not appear, and we should insert it
{
NODE->count++;
NODE->word = str;
}
}
//Find a word, if it appeared, then return the number of occurrences of the word.
//If not, it will return false
bool Trie::Search(string str, int& cnt)
{
assert(!str.empty());
int index = INT_MIN;
Trie_Node *NODE = ROOT;
int length = str.size();
int i = 0;
while (NODE && i < length)
{
index = str.at(i) - 'a'; //Case sensitive
if (index < 0 || index > MAXNUM) //No insertion is performed
return false;
NODE = NODE->Next_Branch[index];
i++;
}
if (NODE && !NODE->word.empty())
{
cnt = NODE->count;
return true;
}
return false;
}
bool Trie::Remove(string str)
{
assert(!str.empty());
int index = INT_MIN;
Trie_Node *NODE = ROOT;
int length = str.size();
int i = 0;
while (NODE && i < length)
{
index = str.at(i) - 'a'; //Case sensitive
if (index < 0 || index > MAXNUM) //No deletion is performed
return false;
NODE = NODE->Next_Branch[index];
i++;
}
if (NODE && !NODE->word.empty())
{
NODE->word.clear();
return true;
}
}
void Trie::PrintALL()
{
Print(ROOT);
}
bool Trie::PrintPre(string str)
{
assert(!str.empty());
int index = INT_MIN;
Trie_Node *NODE = ROOT;
int length = str.size();
int i = 0;
while (NODE && i < length)
{
index = str.at(i) - 'a'; //Case sensitive
if (index < 0 || index > MAXNUM)
return false;
NODE = NODE->Next_Branch[index];
i++;
}
if (NODE) //We can find the word
{
Print(NODE);
return true;
}
return false;
}
void Trie::Print(Trie_Node* Root)
{
if (Root == NULL)
return;
//Print the word
if (!Root->word.empty())
cout << Root->word << " " << Root->count << endl;
for (int i = 0;i < MAXNUM;i++)
Print(Root->Next_Branch[i]);//Print all the children of the node
}
//Rest trie tree
void Trie::Reset(Trie_Node* Root)
{
if (Root == NULL)
return;
for (int i = 0;i < MAXNUM;i++)
Reset(Root->Next_Branch[i]);
//Reset the word
if (!Root->word.empty())
Root->word.clear();
delete Root; //Delete the node
Root = NULL;
}
int NUM_TO_INSERT, NUM_TO_SEARCH, NUM_TO_DELETE, NUM_TO_SBF;
//Main Function
int main(int argc, char **argv)
{
ios::sync_with_stdio(false);
Trie TREE;
cout << "Input the number of words you want to insert:" << endl;
cin >> NUM_TO_INSERT;
for (int i = 0;i < NUM_TO_INSERT;i++)
{
string STRING;
cin >> STRING;
TREE.Insert(STRING);
}
cout << endl;
cout << "Input the number of words you want to search:" << endl;
cin >> NUM_TO_SEARCH;
for (int i = 0;i < NUM_TO_SEARCH;i++)
{
string STRING;
cin >> STRING;
int count = -1;
bool CanFind = TREE.Search(STRING, count);
if (CanFind)
cout << STRING << " exists, its number of occurrences is " << count << endl;
else
cout << STRING << " does not exists!" << endl;
}
cout << endl;
cout << "Here are all the nodes in the Trie tree:" << endl;
TREE.PrintALL();
cout << endl;
cout << "Input the number of words you want to delete:" << endl;
cin >> NUM_TO_DELETE;
for (int i = 0;i < NUM_TO_DELETE;i++)
{
string STRING;
cin >> STRING;
bool Is_Deleted = TREE.Remove(STRING);
if (Is_Deleted)
cout << STRING << " deleted!" << endl;
else
cout << "Failed to delete " << STRING << endl;
}
cout << endl;
cout << "Input the number of words you want to search by prefix:" << endl;
cin >> NUM_TO_SBF;
for (int i = 0;i < NUM_TO_SBF;i++)
{
string STRING;
cin >> STRING;
bool STATUS = TREE.PrintPre(STRING);
if (!STATUS)
cout << "There aren't any words begin with " << STRING << " !";
cout << endl;
}
cout << endl;
return 0;
}