#include<bits/stdc++.h>
using namespace std;
int trie[100001][26],k;
//trie树的数组表示形式,其中k表示当前这棵树所有的节点数
bool col[100001];//记录终止的位置
/*模板
Type function(char *s)
{
int len =s.length(),p=0;
for(int i=0;i<len;i++)
{
char c = s[i] - x;//x为最小可能的字符
//do sth ...
p= trie[p][c];
}
//do sth...
}
*/
//插入
//记录小写字母的trie树
void insert_trie(char* s)
{
int len = strlen(s),p=0;
for(int i=0;i<len;i++)
{
char c=s[i]-'a';//直接定位到该节点所对应的相应路径上
if(!trie[p][c])
trie[p][c] = ++k;//如果没有该路径,则新生成一个节点,将节点数加1处理
//实现给树中的节点编号
p = trie[p][c];//定位到下一个节点
}
col[p]=1;//标记好结束的节点
}
//查询是否存在该字符串
bool search_trie(char *s)
{
int len=strlen(s),p=0;
for(int i=0;i<len;i++)
{
int c=s[i] - 'a';
if(!trie[p][c])
return false;//不存在相应的边,表示没有这个单词
p=trie[p][c];
}
if(col[p])
return true;
else
return false;
}
//删除相应的单词操作
bool delete_trie(char *s)
{//为了降低时间复杂度,并不调用search函数来判断对应的单词是否存在
//需要考虑分叉问题 ,删除到上一个分叉的地方
int len=strlen(s),p=0;
int flag=0;
int pre_num=0;//记录前面对应节点的位置
for(int i=0;i<len;i++)
{
int c=s[i] - 'a';
if(!trie[p][c])
return false;//不存在相应的边 ,无删除的单词
int cnt=0;
for(int j=0;j<26;j++)
{
if(trie[p][j])
cnt++;
}
if(cnt>1)
pre_num=p;
if(col[p])
pre_num=p;//字串
p=trie[p][c];
}
//继续向后遍历
//只需要看一看删除单词后面是否还有边
//删除的单词是否为字串
if(!col[p])
return false;//结束位置没有标记 ,没有删除的单词
for(int i=0;i<26;i++)
{
if(trie[p][i])
{//后面还有边
//删除的单词为字串
//将结束位置抹掉
flag=1;
}
}
if(flag)
col[p]=0;//删除结束
else
{//从pre_num一直删到单词结束
p=pre_num;
for(int i=pre_num;i<len;i++)
{ int c=s[i] - 'a';
trie[p][c]=0;
p=trie[p][c];
}
col[p]=0;//把标记结束的位置删掉
}
}
int main()
{
FILE *fp=fopen("trie_test.txt","r");
if(!fp)
{
cout<<"file open error!"<<endl;
}
else
{
cout<<"file open successfully!"<<endl;
}
char buff[1000];
while(fgets(buff,1000,fp)!=NULL)
{
char *temp=strtok(buff,"\n");//去除读入的换行符
insert_trie(temp);
}
char test[]="bttopeses";
char test2[]="bttob";
if(search_trie(test))
cout<<"find successfully!"<<endl;
else
cout<<"not find!" <<endl;
delete_trie(test);
if(search_trie(test2))
cout<<"find successfully!"<<endl;
else
cout<<"not find!" <<endl;
return 0;
}