trie字典树

在上一次 C 语言比赛的题目里,运用到的一个知识点,就是字典树

上一次比赛答案如下

嵌入式 Linux :第一届 C 语言比赛答案


字典树介绍

字典树的图形如下

<img src="https://pic2.zhimg.com/v2-6f5d815c516c05e8656f351df2318909_b.jpg" data-size="small" data-rawwidth="1215" data-rawheight="1594" class="origin_image zh-lightbox-thumb" width="1215" data-original="https://pic2.zhimg.com/v2-6f5d815c516c05e8656f351df2318909_r.jpg">

从网上拿到的一个图

字典树简单的是用一个二维数组表示,如果想更加节省空间,大神的做法肯定是用指针链表来搞定了。比如我们用 g_trie[i][j]=k 这个二维数组表示字典树,那么他们的含义有三点, i,j,k ,这个是字典树的核心,只有理解 i,j,k 代表的意义,才能更好的去写代码构建字典树,运用字典树。

i >>> 这个可以理解为根节点(上面的 e,k 字符都可以认为是 i ),如果这个没有孩子,下面没有分支,就可以理解为 i

j>>>j 可以理解为 i 的孩子,他的值意思就是第几个孩子的意思

k>>> 这个我认为就是一共有多少个字符,统计所有字符数量的意思


实例代码

#include "stdio.h"


#define false (0)

#define true (1)


int g_trie[ 100 ][ 100 ];

char g_str[ 100 ];

int g_root = ;

int g_tot = ;


void insert ( char * s)

{

    int id = ;

    g_root = ;

    while ( * s != '\0' )

    {

        id  = * s ++ - 'a' ;

        if (g_trie[g_root][id] == )

        {

            g_trie[g_root][id] = ++ g_tot;

        }

        g_root = g_trie[g_root][id];

    }

}



int find_str ( char * s)

{

    g_root = ;

    while ( * s != '\0' )

    {

        int id = * s ++ - 'a' ;

        if (g_trie[g_root][id] == ) return false ;

        g_root = g_trie[g_root][id];

    }

    return true ;

}


void main ( void )

{

    int N = ;

    memset(g_trie, , sizeof ( int ) * 100 * 100 );

    scanf( "%d" , & N);

    for ( int i = ;i <= N;i ++ )

    {

        scanf( "%s" ,g_str);

        insert(g_str);

    }

    puts( "Please input find string" );

    while ( ~ scanf( "%s" ,g_str))

    {

        if (find_str(g_str) == true )

        {

            puts( "find str" );

        }

        else

        {

            puts( "find nothing!" );

        }

    }  

}

解释

为什么 id =*s++- 'a'; 这个是为了节省空间,本来数组建立的字典树就浪费了很多空间,这个写法能节省很多空间。

if(g_trie[g_root][id] == 0) 我们在前面已经初始化数组为 ,这里如果检测是 ,那么就说明里面没有东西,就可以往里面存东西。


用链表实现的字典树代码

// C implementation of search and insert operations 

// on Trie 

#include <stdio.h> 

#include <stdlib.h> 

#include <string.h> 

#include <stdbool.h> 

  

#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0]) 

  

// Alphabet size (# of symbols) 

#define ALPHABET_SIZE (26) 

  

// Converts key current character into index 

// use only 'a' through 'z' and lower case 

#define CHAR_TO_INDEX(c) ((int)c - (int)'a') 

  

// trie node 

struct TrieNode 

    struct TrieNode * children[ALPHABET_SIZE]; 

  

    // isEndOfWord is true if the node represents 

    // end of a word 

    bool isEndOfWord; 

}; 

  

// Returns new trie node (initialized to NULLs) 

struct TrieNode * getNode ( void

    struct TrieNode * pNode = NULL

  

    pNode = ( struct TrieNode * )malloc( sizeof ( struct TrieNode)); 

  

    if (pNode) 

    { 

        int i; 

  

        pNode -> isEndOfWord = false

  

        for (i = ; i < ALPHABET_SIZE; i ++

            pNode -> children[i] = NULL

    } 

  

    return pNode; 

  

// If not present, inserts key into trie 

// If the key is prefix of trie node, just marks leaf node 

void insert ( struct TrieNode * root, const char * key) 

    int level; 

    int length = strlen(key); 

    int index; 

  

    struct TrieNode * pCrawl = root; 

  

    for (level = ; level < length; level ++

    { 

        index = CHAR_TO_INDEX(key[level]); 

        if ( ! pCrawl -> children[index]) 

            pCrawl -> children[index] = getNode(); 

  

        pCrawl = pCrawl -> children[index]; 

    } 

  

    // mark last node as leaf 

    pCrawl -> isEndOfWord = true

  

// Returns true if key presents in trie, else false 

bool search ( struct TrieNode * root, const char * key) 

    int level; 

    int length = strlen(key); 

    int index; 

    struct TrieNode * pCrawl = root; 

  

    for (level = ; level < length; level ++

    { 

        index = CHAR_TO_INDEX(key[level]); 

  

        if ( ! pCrawl -> children[index]) 

            return false

  

        pCrawl = pCrawl -> children[index]; 

    } 

  

    return (pCrawl != NULL && pCrawl -> isEndOfWord); 

  

// Driver 

int main () 

    // Input keys (use only 'a' through 'z' and lower case) 

    char keys[][ 8 ] = { "the" , "a" , "there" , "answer" , "any"

                     "by" , "bye" , "their" }; 

  

    char output[][ 32 ] = { "Not present in trie" , "Present in trie" }; 

  

  

    struct TrieNode * root = getNode(); 

  

    // Construct trie 

    int i; 

    for (i = ; i < ARRAY_SIZE(keys); i ++

        insert(root, keys[i]); 

  

    // Search for different keys 

    printf( "%s --- %s\n" , "the" , output[search(root, "the" )] ); 

    printf( "%s --- %s\n" , "these" , output[search(root, "these" )] ); 

    printf( "%s --- %s\n" , "their" , output[search(root, "their" )] ); 

    printf( "%s --- %s\n" , "thaw" , output[search(root, "thaw" )] ); 

  

    return

}



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31561984/viewspace-2221111/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31561984/viewspace-2221111/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值