所谓字典树,就是将一些单词利用树状图储存起来,然后可以进行一些快速的查找等功能
上图是一棵 Trie 树,表示了关键字集合{“a”, “to”, “tea”, “ted”, “ten”, “i”, “in”, “inn”} 。从上图可以归纳出Trie树的基本性质:
- 根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
- 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符互不相同。
这样的储存方式简单又快捷,而且时间复杂度大大降低。
那么,我们怎样来建立这样的一个字典树呢?别急,我们慢慢来
首先,我们要创建一个结构体:
typedef struct trie_node
{
int count;
trie_node *children[tree_size];
}*trie;
这个结构体里面的count表示在此结点的单词出现的次数(等下你就会知道),而下面那个
trie_node *children[tree_size];
表示这个结点连接下面的是哪一个字母,因为一共有26个字母,所以我们设定tree_size为26
下面我们要开始创建字典树了:
trie_node *creat_trie_node()
{
trie_node *pNode = new trie_node();
pNode->count = 0;
for (int i = 0; i < tree_size; i++)
pNode->children[i] = NULL;
return pNode;
}
我们来解析一下,我们首先创建了一个结构体指针pNode,令他的count为0,然后利用一个循环将这个结点指向的26个字母都为NULL,然后返回这个指针变量,这个指针变量就是下面的root
那么,我们要开始把一个个单词插入进去了
void trie_insert(trie_node *root, char *key)
{
trie_node *node = root;
char *p = key;
while (*p)
{
if (node->children[*p - 'a'] == NULL)
{
node->children[*p - 'a'] = creat_trie_node();
}
node = node->children[*p - 'a'];
p++;
}
node->count += 1;
}
这里的
node->children[*p - 'a']
意思就是跟结点指向的这个字母有没有出现过,出现过就把这个指针指向当前节点,然后将node
向下移,p++进行这个单词往后数,最后count+1表示这个单词出现过一次了
然后我们要怎样检查一个单词有没有出现过呢?
int trie_search(trie_node *root, char *key)
{
trie_node *node = root;
char *p = key;
while (*p&&node != NULL)
{
node = node->children[*p - 'a'];
++p;
}
if (node == NULL)
return 0;
else
return node->count;
}
*key指向单词,我们沿着创建后的树由root开始寻找,一个个往下,直到查找完了,那么返回count,如果没有这个单词就会返回0,所以下面如果判断一个单词是否出现过,那么就只要判断返回的数字是否大于零就行。
接下来来一题题目做做
这道题有时间限制,那么我们学会了字典树以后就能够很轻松的把它解出来了
#include<iostream>
#include<string>
using namespace std;
const int tree_size = 26;
typedef struct trie_node
{
int count;
trie_node *children[tree_size];
}*trie;
trie_node *creat_trie_node()
{
trie_node *pNode = new trie_node();
pNode->count = 0;
for (int i = 0; i < tree_size; i++)
pNode->children[i] = NULL;
return pNode;
}
void trie_insert(trie_node *root, char *key)
{
trie_node *node = root;
char *p = key;
while (*p)
{
if (node->children[*p - 'a'] == NULL)
{
node->children[*p - 'a'] = creat_trie_node();
}
node = node->children[*p - 'a'];
p++;
}
node->count += 1;
}
int trie_search(trie_node *root, char *key)
{
trie_node *node = root;
char *p = key;
while (*p&&node != NULL)
{
node = node->children[*p - 'a'];
++p;
}
if (node == NULL)
return 0;
else
return node->count;
}
int main()
{
int num;
int maxs;
int max = 0;
int mark = 0;
cin >> num;
trie_node *root = creat_trie_node();
char *ans = new char[101];
for (int i = 0; i <num; i++)
{
char ch[110];
scanf_s("%s", ch);
getchar();
trie_insert(root, ch);
if (trie_search(root, ch) > max)
{
max = trie_search(root, ch);
mark = i;
}
ans =ch;
}
cout << ans << endl;
system("pause");
return 0;
}
大家可以找一些题目来练练手,然后总结一下经验。。。