Trie树的应用,一道算法问题求解 代码实现

  上篇文章中我们介绍了Trie树结构,并使用Trie树解决了一个算法问题,具体问题请参看这里:  

  http://www.cnblogs.com/springfield/archive/2010/06/16/1758450.html

 

  这篇文章中我们来介绍这个算法的具体实现:

  

  首先我们要定义Trie树的节点:

  

 

typedef struct Node{

    
int words;                //在该节点处结束的字符串数量    
    BOOL hasChild;            //该节点是否有子节点,用于遍历Trie树
    struct Node *edges[10];   //该节点的10条边 分别对应0-9每个字符

}TrieNode;

 

  

  在定义好节点之后,我们需要初始化该节点,所以下面的初始化函数用来给节点的各个成员设置默认值:

 

 

void init(TrieNode *node){
    
    
int i;
    node
->words = 0;
    node->hasChild = FALSE;
    
for(i = 0;i < 10;i++){
        
        node
->edges[i] = NULL;
    }
}

 

 

  下面就可以开始构造Trie树了,由于我们的题目中,输入的是一组电话号码,所以我们逐一用每条电话号码来构造Trie树,从第一个电话号码开始,将每个电话号码插入Trie树中,具体过程前面介绍过了,这里只简单说一下:从根节点开始,如果这个号码的第一个字符为'2',那么就从根节点对应字符为'2'的边上创建一个子节点,然后再从这个子节点开始继续和该号码的下一个字符进行比对,操作方式和上面相同,更详细的资料请参看上一篇文章,这里不再赘述.
  我们这里引入了一个函数,用这个函数来进行增加号码的操作:
 
  
void addNode(TrieNode *node,char *word){

    
char firstChar;
    TrieNode 
*tempNode;
    
int edgeIndex;

    
if(strlen(word) == 0){

        node
->words = node->words + 1;

    }
else{
                
        node
->hasChild = TRUE;
        firstChar 
= word[0];
        edgeIndex 
= ((int)firstChar) - 48;
        
if(node->edges[edgeIndex] == NULL){

            tempNode 
= node->edges[edgeIndex] = createTrieNode();  //创建Trie树节点,进行分配内存空间等操作

            init(tempNode);
        }
        

        cutLeftmostCharacter(word);  //删除字符串中的最左边的字符,因为这个字符已经在Trie树中计算过了
        addNode(node
->edges[edgeIndex],word);

    }
}

 

  有了AddNode()这个函数,我们就可以构造出整棵Trie树了,这个函数中用到了两个辅助函数createTrieNode()和cutLeftmostCharacter(),分别用来创建新节点和去除最左边的字符,以便进行下一次调用。

  在我们将一组电话号码全都增加到Trie树中之后,我们进可以遍历这颗树,来确定是否要包含关系的字符串了,这个函数主要是通过判断是否有非叶子节点被标识成字符串结尾(这个字上一篇文章中有详细介绍),该函数实现如下:

 

int calcIfConsistent(TrieNode *node){
    
    
int i;
    
long rs = 0;                //用来表示是否有非叶子节点被表示为字符串结尾,如果rs大于0证明有这种节点

    
if(node->hasChild){            //如果该节点不是叶子节点,判断它的标识情况
        
        rs 
= node->words;        //该节点被标识为字符串结尾的数量

        
for(i = 0;i < 10;i++){    //对该节点的所有子节点进行同样的操作
            
            
if(node->edges[i] != NULL){
                
                rs 
+= calcIfConsistent(node->edges[i]);
            }
        }            

        
return rs;

    }
else{
        
return 0;
    }
}

 

 

   我们通过这个函数的返回值,就可以判断出这组电话号码是否一致,然后输出相应的结果,这道问题就可以解决了。当然这里给出的代码肯定不是最好的,如果大家有更好的思路,欢迎大家一起交流。完整代码如下:

 

  

  

算法代码
#include <stdio.h>
#include 
<string.h>
#include 
<stdlib.h>

#define TRUE 1
#define FALSE 0

typedef 
int BOOL;

typedef 
struct Node{

    
int words;                //在该节点处结束的字符串数量    
    BOOL hasChild;            //该节点是否有子节点,用于遍历Trie树
    struct Node *edges[10];    //该节点的10条边 分别对应0-9每个字符

}TrieNode;

TrieNode
* createTrieNode(){
    
    
return (TrieNode*)malloc(sizeof(TrieNode));
}

void cutLeftmostCharacter(char *str){

    
int len = strlen(str);
    
int i;

    
for(i = 1;i < len;i++){
        
        str[i 
- 1= str[i];

    }

    str[i 
- 1= '\0';
}

void init(TrieNode *node){
    
    
int i;
    node
->words = 0;
    
//node->prefixes = 0;
    node->hasChild = FALSE;
    
for(i = 0;i < 10;i++){
        
        node
->edges[i] = NULL;
    }
}

void addNode(TrieNode *node,char *word){

    
char firstChar;
    TrieNode 
*tempNode;
    
int edgeIndex;

    
if(strlen(word) == 0){

        node
->words = node->words + 1;

    }
else{
                
        node
->hasChild = TRUE;
        firstChar 
= word[0];
        edgeIndex 
= ((int)firstChar) - 48;
        
if(node->edges[edgeIndex] == NULL){

            tempNode 
= node->edges[edgeIndex] = createTrieNode();

            init(tempNode);
        }
        

        cutLeftmostCharacter(word);
        addNode(node
->edges[edgeIndex],word);

    }
}

int calcIfConsistent(TrieNode *node){
    
    
int i;
    
long rs = 0;                //用来表示是否有非叶子节点被表示为字符串结尾,如果rs大于0证明有这种节点

    
if(node->hasChild){            //如果该节点不是叶子节点,判断它的标识情况
        
        rs 
= node->words;        //该节点被标识为字符串结尾的数量

        
for(i = 0;i < 10;i++){    //对该节点的所有子节点进行同样的操作
            
            
if(node->edges[i] != NULL){
                
                rs 
+= calcIfConsistent(node->edges[i]);
            }
        }            

        
return rs;

    }
else{
        
return 0;
    }
}


void freeTrieTree(TrieNode *node){

    
int i;

    
if(node->hasChild){
    
        
for(i = 0;i < 10;i++){
            
            
if(node->edges[i] != NULL){

                freeTrieTree(node
->edges[i]);
            }

        }

        free(node);

    }
else{

        free(node);
    }
}

int main(){

    
int group_count = 0;
    
int n = 0;
    
char phoneNumber[11];
    TrieNode 
*root;
    scanf(
"%d\n",&group_count);

    
while(group_count != 0){
                
        scanf(
"%d\n",&n);
        
        root 
= createTrieNode();        
        init(root);        
        
while(n != 0){
            
            scanf(
"%s\n",phoneNumber);
            addNode(root,phoneNumber);
            n
--;

        }

        
if(calcIfConsistent(root) > 0){
            
            printf(
"NO\n");

        }
else{
        
            printf(
"YES\n");
        }
        
        freeTrieTree(root);
        group_count
--;
    }
}

 

 

  

 

  

posted @ 2010-06-20 19:53  Springfield  阅读(2588)  评论(2编辑  收藏  举报