字典树(边改边抄)

来源:互联网 发布:最新搜片软件 编辑:程序博客网 时间:2024/05/21 00:56

百度定义内容:
       又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

    
性质

  它有3个基本性质:
  根节点不包含字符,除根节点外每一个节点都只包含一个字符。 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。 每个节点的所有子节点包含的字符都不相同。
                

基本操作

  其基本操作有:查找 插入和删除,当然删除操作比较少见。我在这里只是实现了对整个树的删除操作,至于单个word的删除操作也很简单。


实现方法

  搜索字典项目的方法为
       (1) 从根结点开始一次搜索;
  (2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
  (3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
  (4) 迭代过程……
  (5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
  其他操作类似处理


应用

串的快速检索

  给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
  在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。

“串”排序

  给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出
  用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。

最长公共前缀问题

  对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为最近公共祖先问题。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
对于指针我算是怕了:只好再看看了;


字典树基本模板

  #define MAX 26 //字符集大小
  typedef struct TrieNode
  {
  int nCount; //记录该字符出现次数
  struct TrieNode *next[MAX];

  }TrieNode;//字典树的结构表达;
        其中的next[26]是对应于每个节点下面的可能有的26个字母,因为对于一个单词而言,每个字母后面的字母只有26种可能嘛(如果只是允许大写或者是小写的话),而且在后面大家可能会发现,对于某个不为空的节点,它的子节点所对应的字母是按照字母表次序来的,然后nCount就是指该节点的孩子节点的数目,也就是以从根节点到该节点的路径上所有字母组成的字符串为前缀的字符串的数目。
         然后需要定义一个全局的头指针,因为每次对字符串开始进行插入操作的时候,都需要从头结点开始,这样才可以利用公共前缀,减少存储空间,还有加快查找速度。
        接着就是字典树的构建问题,其实就是一个for循环,对你所要插入字典树的字符串的每一位字符进行插入操作,同时我们定义两个Node 指针,一个t,用于中间的新建节点,因为当你查找到某个节点下面没有你这个字符所对应的节点的时候,你就需要自己新建一个节点用以保存你这个字符,另外一个指针s,就是用于对头指针开始操作,作用前面已经说了,接着就开始建树,对字符串str,对每一次循环,如果当前指针s下面的对应于当前字符str[i]在字母表的位置的孩子节点为空,就说明此时该字符串str于其他的字符的公共前缀最多延伸到s处,接着就需要新建节点了,同时对新建节点以及新建节点的孩子进行初始化(尤其是num的初始化),如果当前指针s下面的对应于当前字符str[i]在字母表的位置的孩子结点不为空,那么此时就不需要进行新建节点,指针向下移动即可.这样对输入的每个字符串进行插入操作,就可以构建出一棵字典树了:












  TrieNode Memory[1000000];

  int allocp =0;
  /*初始化*/
  void InitTrieRoot(TrieNode **pRoot)
  {
  *pRoot = NULL;
  }
  /*创建新结点*/
  TrieNode *CreateTrieNode()
  {
  int i;
  TrieNode *p;
  p =&Memory[allocp++];
  p->nCount =1;
  for(i =0 ; i < MAX ; i++)
  {
  p->next[i] = NULL;
  }
  return p;
  }
  /*插入*/
  void InsertTrie(TrieNode **pRoot , char*s)
  {
  int i , k;
  TrieNode *p;
  if(!(p =*pRoot))
  {
  p =*pRoot = CreateTrieNode();
  }
  i =0;
  while(s[i])
  {
  k = s[i++] -'a'; //确定branch
  if(p->next[k])
  p->next[k]->nCount++;
  else
  p->next[k] = CreateTrieNode();
  p = p->next[k];
  }
  }
  //查找
  int SearchTrie(TrieNode **pRoot , char*s)
  {
  TrieNode *p;
  int i , k;
  if(!(p =*pRoot))
  {
  return0;
  }
  i =0;
  while(s[i])
  {
  k = s[i++] -'a';
  if(p->next[k] == NULL) return0;
  p = p->next[k];
  }
  return p->nCount;
  }




原创粉丝点击