字符串算法——字典树

来源:互联网 发布:大数据涉及技术要求 编辑:程序博客网 时间:2024/05/21 15:38

Trie树,又称字典树、单词查找树,是一种树形结构,用于保存大量的字符串,其核心思想是空间换时间。它的优点是:利用字符串的公共前缀来节约存储空间。相对来说,Trie树是一种比较简单的数据结构.理解起来比较简单,正所谓简单的东西也得付出代价.故Trie树也有它的缺点,Trie树的内存消耗非常大。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。


1、三个性质

a、根节点不包含字符,除根节点外每一个节点都只包含一个字符。

b、 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。

c、 每个节点的所有子节点包含的字符都不相同。

2、基本操作

其基本操作有:查找 插入和删除,当然删除操作比较少见

3、实现方法

(1) 从根结点开始一次搜索;

(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;

(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。

(4) 迭代过程……

(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。

4、基本模板

#include<stdio.h>#include <string.h>      #include <stdlib.h>      struct dictree      {          struct dictree *child[26];          bool isWord=false;      int n;    // 统计一组字符串中某前缀出现的次数  };   //结点结构,有26个子节点   struct dictree *root;      void insert (char *source)      {         int len,i,j;          struct dictree *current,*newnode;          len=strlen(source);          if(len==0)      {          return;         }       current=root;          for(i=0;i<len;i++)          {              if(current->child[source[i]-'a']!=0)              {  //插入字符 已经存在              current=current->child[source[i]-'a'];               current->n=current->n+1;            }           else             {     //不存在 新建节点  加入字典树中              newnode=(struct dictree *)malloc(sizeof(struct dictree));                  for(j=0;j<26;j++)              {                  newnode->child[j]=0;               }                 current->child[source[i]-'a']=newnode;                  current=newnode;               current->n=1;               }             }         current->isWord=true;//标识 单词的最后一个 字母为 单词结尾  } //查找,返回所查找的单词在某前缀出现的次数    int findF(char *source)      {          int i,len;          struct dictree *current;         len=strlen(source);       if(len==0) return 0;          current=root;          for(i=0;i<len;i++)          {              if(current->child[source[i]-'a']!=0) //查找该字母是否在字典树中              current=current->child[source[i]-'a'];              else return 0;          }          return current->n;//返回所查找的单词在某前缀出现的次数   } //查找  bool 返回值判断 给定 的单词是否在所给的字符串之中   bool findS(char *source)      {          int i,len;          struct dictree *current;         len=strlen(source);       // bool 返回值判断 给定 的单词是否在所给的字符串之中     if(len==0) return false;          current=root;          for(i=0;i<len;i++)          {              if(current->child[source[i]-'a']!=0)                  current=current->child[source[i]-'a'];              else return false;          }          return current->isWord;    }      int main()   {       char temp[11];       int i,j;       root=(struct dictree *)malloc(sizeof(struct dictree));          for(i=0;i<26;i++)   { root->child[i]=0; }         root->n=1000;        while(gets(temp),strcmp(temp,"")!=0)       {    insert(temp);  }             while(scanf("%s",temp)!=EOF)       {           i=findF(temp);           printf("%d   ",i);if(true==findS(temp))   {printf("Isword is true\n");}else{printf("Isword is false\n");}    }     free(root);//释放空间 return 0;  }


5、字典树的典型应用

1.统计一组字符串中某前缀出现的次数(直接用上面的代码就行)。
2.判断一组字符串中是否有一个字符串是另一个字符串的前缀。
    分析:我们只要在结点中添加一个nEndFlag成员变量即可。若nEndFlag == 1,说明该结点字符是某一字符串的结尾(假设为A),若在插入B字符串的过程中经过这一结点,则说明A是B的    前缀;还有一种情况,当要插入最后一个字符c时,却发现p->next[c-'a']为真,则说明该字符串是一个前缀字符串,eg:先插入abcde,再插入abc这种情况。
3. 串排序:给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出
用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。



0 0