字典树是简单的数据结构,从根节点到其他节点的每条路径都表示一串字符。
举例分析(POJ-2418https://vjudge.net/problem/POJ-2418):
题目要求求出每一种树的占比,即进行词频统计。然后按照字典序输出,由于建树是就是按照字母的顺序插入节点,因此字典树的先根遍历就是字典序的输出结果。
整体代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include<stack>
using namespace std;
char s[40];
int index=0;
int node_num=0;
int word_index=0;
char out_word[35];
struct node
{
int sum;
bool isEnd;
node* son[256];
node()
{
sum=0;
isEnd=false;
for(int i=0;i<256;i++)
{
son[i]=NULL;
}
}
};
node* root;
void insert_node(char* s0)
{
node* node1=root;
if(strlen(s0)==0)
return;
for(int i=0;i<strlen(s0);i++)
{
int pos = s0[i];
if(node1->son[pos]==NULL)
{
node1->son[pos]=new node();
}
node1=node1->son[pos];
}
node1->isEnd=true;
node1->sum++;
}
bool dfs(node* node0,int pos0)
{
if(node0->son[pos0]==NULL)
{
return 0;
}
out_word[word_index++]=pos0;
if(node0->son[pos0]->isEnd)
{
for(int j=0;j<word_index;j++)
{
printf("%c",out_word[j]);
}
printf(" %.4f",float(node0->son[pos0]->sum)*100/(index));
printf("\n");
}
node0=node0->son[pos0];
for(int i=0;i<256;i++)
{
dfs(node0,i);
}
word_index--;
return 1;
}
int main()
{
root=new node();
while(gets(s)!=NULL)
{
insert_node(s);
index++;
}
for(int i=0;i<256;i++)
{
word_index=0;
dfs(root,i);
}
return 0;
}
部分解析
对于node结构体主要成员有sum来记录当前的字符串总共有几个;isEnd来表示这个单词是否到达结尾;还有大小为256的node指针类型的数组,来表示其儿子节点,256表示ASCII码的范围,以字母的ASCII码作为索引。
插入节点就是简单的检索,若存在该节点则不做操作,不存在则创建,并插入在指定位置。
按照字母序输出就是简单的先根遍历,其中结果存在out_word数组中。并用word_index来模拟栈指针。
主程序先读入数据,再插入各个节点,最后深度优先遍历搜索并输出。
问题及解法:
遇到的问题:
1:由于输入没有指明数量,并且读入的是整行字符(而非单词,也就是单词中允许空格)
2:输出的时候没有考虑到递归
3:内存溢出
4:运行时异常
解决的方法:
1:用到while(gets(s)!=NULL)读取数据
2:递归要退回到上一个状态时,要保留之前的子串结果。因此引入一个数组代表栈,并且用word_index来充当栈指针。栈指针的改变也要注意,之前总是出错,自己手动运行几次,才发现自己想复杂了
3:不需要存储的数据不要开空间存储
4:由于之前以为只有27个字符(字母和空格),后来发现不是这样,就干脆改成256,但是初始化部分忘记修改,发现指针溢出了