字典树学习总结

来源:互联网 发布:宁海知豆客服电话 编辑:程序博客网 时间:2024/05/09 20:07


解决问题:主要应对多次查询,典例就是字典,字典树就是一本字典,字典的最大好处就是能快速查询;

主要原理:我们在查某一个单词时总会先索引第一个字母,然后在查第二个字母,以此类推直到查到此单词为止,那么字典树的查询过程也是如此,先查第一个字母的节点位置,然后在该节点的子节点之中查询第二个字母的位置,以此类推,直到查到最后一个字母,就相当于我们查到了这个单词;想一想我们在查字典时查到某个字母,这个字母下面还会有很多单词,而这些单词都通过这个字母连起来,我们要查到其中某一个单词的话必须要经历这个字母,即单词具有相同的前缀时,有相同的就要合并,计算机优化的就是相同的东西,尽量让一个东西只出现一次,根据这个我们可以构建一棵字典树,具有相同前缀的单词连在同一个节点上,那么查询时我们就可以像查单词一样了;



主要操作:

建树(插入):1。设置三个指针,一个指向待插入字符串(序列),一个指向树的根节点,另一个不做初始化,称为自由指针;

2、查找首字母在在树中的位置,如果当前的数节点的子节点之中没有此字母,那么动态分配一个新节点内存使自由指针指向他并初始化方法,然后挂到当前节点之上(父节点),然后将当前节点指针下移,字符串指针右移,更新节点中存储的数据;

3.循环进行以上过程,直至待插入·字符串指针移动到字符串末尾为止;

void insert(char *str){int i=0; Node *p1=root,*p2;//1.初始化指针 while(str[i]!='\0')//2.插入 {int pos=str[i]-'a';//节点应处位置 if(p1->son[pos]==NULL)//判断此字母知否存在 {p2=new Node;//不存在则建点 init(p2);//初始化新节点 p1->son[pos]=p2;//挂到父节点上 }p1=p1->son[pos];//指针移动 ++i;}p1->flag=true;//更新节点数据(题目不同意义不同) } 


查询:1.设置两个指针并初始化: 一个指向待查询字符串,一个指向树的根节点;

2.查询第一个字母在树上的位置,如果为空,返回false(或者不返回,更新其他结果),如果找到,两个指针移动到下一位,更新结果;

3. 循环进行步骤2,直至字符串指针移动到末尾,返回结果;


bool find(char str[]){int i=0; Node *p=root;//1.初始化指针 while(str[i])//2.依次检索 {int pos=str[i]-'a';//字母应在位置 if(p->son[pos]==NULL) return false;//如果此位置不存在 返回 p=p->son[pos]; ++i;//若存在 指针移动 }return p->flag;//更新结果(题目不同变化不同) 返回结果 }



初始化:将动态申请的新节点中的数据进行初始化;

释放内存:每次测试完之后记得释放动态申请的内存,即字典树,释放过程利用递归,先将子节点释放完在释放父节点;

void init(Node *p)//初始化节点p {p->flag=false; int i=0;for(i=0;i<26;++i) p->son[i]=NULL;}void delet(Node *root)//释放root为根的树 {int i=0;for(i=0;i<26;++i)//先释放子节点 {if(root->son[i]!=NULL) delet(root->son[i]);}delete(root);//再释放根节点 }

注意:1.动态内存可能时间静态的要慢,静态的可能有时候又会超内存,所以应该如何选择或者两者结合用(用静态存储较大的信息,字典树用动态来存)具体情况应仔细斟酌;

2.当有多组测试数据时,释不释放动态申请的内存又是一个问题,如果释放,那么空间复杂度减小,时间复杂度增高;不释放,空间复杂度增高,时间复杂度减小,这也需要判断具体哪一个影响更大,然后选择取舍;

3.对于各种题目,变形可能利用节点的数据,题目虽变,但利用字典树的思想未变:查询,所以确定用字典树之后就是怎样将问题转化成如何查询的问题了(注意逆向思维的运用);


详细讲解:http://baike.so.com/doc/6260618-6474038.html

http://www.cnblogs.com/dong008259/archive/2011/11/11/2244900.html

http://kymowind.blog.163.com/blog/static/18422229720114264416738/

0 0