字典树(链式+数组模拟)--最基础的算法,最详细的注释

知识整理啦啦啦

承前启后,再挂一个入门算法的典范

字典树

啥是字典树,照我看这其实算不上一个算法,就是数据结构里树的第一种表示方式

精髓在用法上,一般用来查询前缀词数量和单词是否存在

一言以蔽之,用以高效查询上述两类问题的一种存储结构

上代码

#include
#include
#include
#define N 26     //26个字母


struct tree{
   struct tree *childs[N];    //类似突触用以下一节点
   int count;                        //计数,有多少单词经过此节点,也就是到此节点为止的前缀词数
   int final;                          //标志,表示单词到该字母时结束
};


struct tree *root; //入口,不存储信息,用来找到这棵树 
//另,全局变量有一个好处  不占用有限的函数堆内存



void insert(char *x){  //插入单词,传入一个字符串
   int length;      //记录单词长度
   struct tree *p,*q;  //用以操作树的节点的指针
   length=strlen(x);  //获取单词长度
   p=root;  //进入树中
   for(int i=0;ichilds[x[i]-'a']!=null){  //也从树的头处开始询问当前字母是否存在
         p=p->childs[x[i]-'a'];  //存在,进入该字母所在的节点
      }
      else{
          q=new tree;  //不存在,先建立这样一个节点
          p->childs[x[i]-'a']=q;  //将指针指过去
          p=q;  //同样进入这个节点
      }
      p->count++;//该单词经过了这个节点,故计数加一
   }
   p->final=1;  //遍历完了,指向的是最后一个字母,设置结束标志
}



int findprefix(char *x){  //传入前缀,查询前缀词数
   int length;  //长度
   struct tree *p;  //用以操作树的节点的指针
   length=strlen(x);  //获取长度
   if(!length)return 0;  //空串,返回0个
   p=root;  //进入树中
   for(int i=0;ichilds[x[i]-'a']!=null){  //也从树的头处开始询问当前字母是否存在
         p=p->childs[x[i]-'a'];  //存在,进入该字母所在的节点
      }else{  
      return 0;  //不存在,就没这个前缀,返回0个
     }
     return p->count; //遍历完了,有count个单词经过这个节点就说明有这么多个前缀词
}



int findword(char *x){  //传入单词,查询前缀词数
   int length;  //长度
   struct tree *p;  //用以操作树的节点的指针
   length=strlen(x);  //获取长度
   if(!length)return 0;  //空串,返回0表示不存在
   p=root;  //进入树中
   for(int i=0;ichilds[x[i]-'a']!=null){  //也从树的头处开始询问当前字母是否存在
         p=p->childs[x[i]-'a'];  //存在,进入该字母所在的节点
      }else{  
      return 0;  //不存在,就没这个单词,返回0表示不存在
     }
     if(p->final==1) return 1:  //遍历完了,若最后一个字母是某词的结尾,则表示有该词,返回存在
     else  return 0;  //否则,表示这个单词是某个前缀,返回不存在
}



int main(){
   root= new tree;
  /*
  输入单词或查询
  */
   return 0;
}

get到了这个算法,但

回头一想查,询单词是一件很简单的事对吧

那为啥要有这个算法呢

因为快,有多快呢,举个栗子
你的词库里有10亿个单词(嗯 尽是些长单词)

如果是用朴素方法,需要多少开销呢

查询单词还好些,用二分也没几次,但你要先排序(时间复杂度天文数字)

要是查询前缀,一个个匹配(大天文数字)

但对字典树来说,只要遍历一个单词就好了,和词库容量无关,多少词都这个速度,看起来好像挺快的

已经这么快了,只能换个角度去优化了,在内存上有好多悬空指针啊,浪费!

于是

数组模拟字典树(降速减容)

#include
#include
#define N 900000  
int tree[N][26],count[N]; //看成N个连续的地址空间 每个空间有26个通道和一个计数 
int pc;  //模拟连续内存的首地址,是几无所谓啦,默认0 
void insert(char x*){   //插入单词 
	int length;  
	length=strlen(x);  //获取单词长度 
	int p=0;  //类似指针,数值就是地址了 
	for(int i=0;i

ps:因为第一个链式结构用的是动态生成的方法,其实两个用的内存差不多

你可能感兴趣的:(字典树(链式+数组模拟)--最基础的算法,最详细的注释)