• 前缀树


    在计算机科学中,trie,又称前缀树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

    Trie 这个术语来自于 retrieval。根据词源学,trie 的发明者 Edward Fredkin 把它读作/ˈtr/ "tree"。但是,其他作者把它读作 /ˈtr/ "try"。

    在图示中,键标注在节点中,值标注在节点之下。每一个完整的英文单词对应一个特定的整数。Trie 可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的。

    键不需要被显式地保存在节点中。图示中标注出完整的单词,只是为了演示 trie 的原理。

    trie 中的键通常是字符串,但也可以是其它的结构。trie 的算法可以很容易地修改为处理其它结构的有序序列,比如一串数字或者形状的排列。比如,bitwise trie 中的键是一串位元,可以用于表示整数或者内存地

     

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

    字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的话用同样的方法继续查找.字典树不仅可以用来储存字母,也可以储存数字等其它数据。

     

    相对来说,Trie树是一种比较简单的数据结构.理解起来比较简单,正所谓简单的东西也得付出代价.故Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.

    其基本性质可以归纳为:

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

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

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

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

    搜索字典项目的方法为:

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

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

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

    (4) 迭代过程……

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

    其他操作类似处理.

    #define MAX 26 //字符集大小
    enum NODE_TYPE{
           DONE,  
           UNDONE
    };


    typedef struct TrieNode   {
         enum NODE_TYPE type  
         char ch;                            
         struct TrieNode *next[MAX]; //26-tree->a, b ,c, .....z  
    }TrieNode;

      

    /*初始化*/   
    void InitTrieRoot(TrieNode **pRoot)   
    {   
          *pRoot = NULL;   
    }   


    /*创建新结点*/   
    TrieNode *CreateTrieNode(char ch)   
    {   
           int i;   
           TrieNode *p = (TrieNode *)malloc(sizeof(TrieNode));      
           p->ch = ch;
             p->type= UNDONE;  
           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;
           for(i=0;*(s+i)!='';i++)
           {
                k=s[i]-'a'
                if(!p->next[k])
                      p->next[k] = CreateTrieNode(s[i]);
                p = p->next[k];
           }  
         
           p->type=DONE;   
    }   

    //查找   
    int SearchTrie(TrieNode **pRoot , char*s)   
    {   
           TrieNode *p;   
           int i , k;   
           if(!(p =*pRoot))   
           {   
                 return 0;   
           }   
           i =0;   
           while(s[i])   
           {   
                 k = s[i++] -'a';
                 if(p->next[k] == NULL)
                          return   0;
                 p = p->next[k];   
           }
      
           return (s[i] == '') && (p->type==DONE);   
    }

  • 相关阅读:
    二维动规思想,j 具有明显枚举特征
    二分法题目总结
    最大(小)值最小(大)化 (二分法变形)
    C/ C++ 输入输出流
    正序扫描字符串问题
    React(基础一)_react中的三大属性
    找位置
    STL vector
    STL stack
    打印日期
  • 原文地址:https://www.cnblogs.com/cl1024cl/p/6205284.html
Copyright © 2020-2023  润新知