字典树

转载 2011年01月10日 13:43:00

字典树:

http://www.cnblogs.com/DiaoCow/archive/2010/04/19/1715337.html

 

字典树的基本功能是用来查询某个单词(前缀)在所有单词中出现次数的一种数据结构,它的插入和查询复杂度都为O(len),Len为单词(前缀)长度,但是它的空间复杂度却非常高,如果字符集是26个字母,那每个节点的度就有26个,典型的以空间换时间结构

模板代码:

#define  MAX    26 //字符集大小

typedef
struct TrieNode
{
   
int nCount; //记录该字符出现次数
    struct TrieNode *next[MAX];
}TrieNode;

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))
    {
       
return 0;
    }
    i
= 0;
   
while(s[i])
    {
        k
= s[i++] - 'a';
       
if(p->next[k] == NULL)    return 0;
        p
= p->next[k];
    }
   
return p->nCount;
}

 

 

典型例题:

1.统计难题(这里都用数组分配结点,用malloc分配太慢了)
这题就是统计一组字符串中某前缀出现次数(字典树第一类应用),因此只要简单的套模板就行了(在节点中设置一个成员变量nCount,来记录该字符出现次数)

#include <stdio.h>
#define  MAX    26

typedef
struct TrieNode
{
   
int nCount;
   
struct TrieNode *next[MAX];
}TrieNode;

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))
    {
       
return 0;
    }
    i
= 0;
   
while(s[i])
    {
        k
= s[i++] - 'a';
       
if(p->next[k] == NULL)    return 0;
        p
= p->next[k];
    }
   
return p->nCount;
}
   
int main(void)
{
   
char s[11];   
   
    TrieNode
*Root = NULL;  
    InitTrieRoot(
&Root);   
   
while(gets(s) && s[0]) 
    {      
        InsertTrie(
&Root , s);
    }   

   
while(gets(s))  
    {       
        printf(
"%d/n", SearchTrie(&Root , s));  
    }    
  

2.Phone List

这道题就是判断一组字符串中是否有一个字符串是另一个字符串的前缀(字典树第二类应用)。

分析:我们只要在结点中添加一个nEndFlag成员变量即可。若nEndFlag == 1,说明该结点字符是某一字符串的结尾(假设为A),若在插入B字符串的过程中经过这一结点,则说明A是B的前缀;还有一种情况,当要插入最后一个字符c时,却发现p->next[c-'0']为真,则说明该字符串是一个前缀字符串,eg:先插入abcde,再插入abc这种情况

return    0;
}

 

#include <stdio.h>
#define  MAX    10

typedef
struct TrieNode
{
   
int nEndFlag; //标记该字符是否是某一字符串的结尾
    struct TrieNode *next[MAX];
}TrieNode;

TrieNode Memory[
1000000];
int allocp = 0 , nFlag = 0;

void InitTrieRoot(TrieNode **pRoot)
{
   
*pRoot = NULL;
}

TrieNode
*CreateTrieNode()
{
   
int i;
    TrieNode
*p;

    p
= &Memory[allocp++];
    p
->nEndFlag = 0;
   
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++] - '0';
       
if(p->next[k])
        {
           
if(p->next[k]->nEndFlag == 1 || s[i] == '/0') //先短后长 || 先长后短
            {
                nFlag
= 1;
               
return;
            }
        }
       
else
        {
            p
->next[k] = CreateTrieNode();
        }
        p
= p->next[k];
    }
    p
->nEndFlag = 1//标记结尾
}


int main(void)
{
   
int  z , n , i;
   
char s[11];   
    TrieNode
*Root; 

    scanf(
"%d", &z);
   
while(z-- > 0
    {      
        nFlag
= allocp = 0;
        InitTrieRoot(
&Root);
        scanf(
"%d" , &n);    getchar();
       
for(i = 0 ; i < n ; i++)
        {
            gets(s);
           
if(!nFlag)    InsertTrie(&Root , s);
        }
        nFlag
? printf("NO/n") : printf("YES/n");
    }   
 
   
return    0;
}
  
   

 

字典树知识

  • 2012年10月15日 23:19
  • 42KB
  • 下载

字典树和KMP

  • 2015年03月17日 21:19
  • 860KB
  • 下载

字典树详解----串查找、排序、公共前缀之杀手锏

1、字典树       又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变形。典型应用是用于统计,排序和保存大量的字符串,所以经常被搜索引擎系统用于文本词频统计。它的优点是利用最大公共前缀来...

敏感词检索工程(字典树算法)

  • 2016年11月23日 18:31
  • 13.66MB
  • 下载

字典树查找统计及单词

  • 2013年10月17日 21:51
  • 6.63MB
  • 下载

Chip Factory(字典树,学会将路暂时删除)

题目链接:Chip Factory题目大意:给你n个数,从中选出三个数a,b,c,使得(a+b)异或c最大。思路:先建立字典树,选出两个数,先暂时删除,然后找出与其异或的最大值。下面是代码:#incl...

字典树(ACM算法)

  • 2008年09月29日 11:57
  • 59KB
  • 下载

字典树应用,检索文本文件单词

  • 2012年12月29日 19:08
  • 5.36MB
  • 下载

字典树 HDU-1251统计难题

关于字典树的讲解请参见

算法学习之字典树

  • 2012年06月25日 17:01
  • 62KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:字典树
举报原因:
原因补充:

(最多只允许输入30个字)