Trie Tree并找到具有最高出现次数,指针的n个单词

时间:2014-01-19 16:20:38

标签: c arrays pointers struct tree

所以我有这段代码,我必须按照主题编写它 - 找到出现次数最多的n个单词,我对此有一般的想法并将其写入void setorder函数但我有一些麻烦用指针。

无论如何,我的想法是我有两个数组,一个用于单词,第二个用整数,所以来自单词char数组的index [i]将出现x次出现,其中x存储在整数数组中index [i]

我的问题是,我不知道如何爬下树,所以我不会乱搞任何东西,因为我递归,我只是似乎没有得到结构的指针,我不知道我应该在这个函数参数中准确放入什么:(请帮忙

编辑:我忘了添加代码,呵呵 https://gist.github.com/anonymous/a20e459e2214629d3839

#include <stdio.h>
#include <stdlib.h>
#include <string.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')


char words[]={0};
int counters[1000]={0};

// trie node
typedef struct trie_node trie_node_t;
struct trie_node
{
    int counter;
    char letter;
    trie_node_t *children[ALPHABET_SIZE];
};

// trie ADT
typedef struct trie trie_t;
struct trie
{
    trie_node_t *root;
    int count;
};

// Returns new trie node (initialized to NULLs)
trie_node_t *getNode(void)
{
    trie_node_t *pNode = NULL;

    pNode = (trie_node_t *)malloc(sizeof(trie_node_t));

    if( pNode )
    {
        int i;

        pNode->counter = 0;

        for(i = 0; i < ALPHABET_SIZE; i++)
        {
            pNode->children[i] = NULL;
        }
    }

    return pNode;
}

// Initializes trie (root is dummy node)
void initialize(trie_t *pTrie)
{
    pTrie->root = getNode();
    pTrie->count = 0;
}

int wordnr=0;

void setorder(trie_node_t *pTrie, char word[])
{
    int length = strlen(word);
    char tempword[1000] = {0};


    for(int i=0; i<length; i++)
    {
        tempword[i]=word[i];
    }

    trie_node_t *pCrawl;
    pCrawl = pTrie->root;


    for(int i=0 ; i<26; i++ )
    {
        tempword[length]=pCrawl->letter;
        tempword[length+1]='\0';

        if(pCrawl->counter!=0)
        {
            for(int i=0; i<=length; i++)
                words[wordnr+i]=tempword[i];

            counters[wordnr]=pCrawl->counter;
        }

        else
        {
            pCrawl = pCrawl->children[i];
            setorder(pCrawl, tempword);
        }
    }
}

// If not present, inserts key into trie
// If the key is prefix of trie node, just marks leaf node
void insert(trie_t *pTrie, char key[])
{
    int level;
    int length = strlen(key);
    int index;
    trie_node_t *pCrawl;


    pTrie->count++;
    pCrawl = pTrie->root;

    for( level = 0; level < length; level++ )
    {
        index = CHAR_TO_INDEX(key[level]);
        if( !pCrawl->children[index] )
        {
            pCrawl->children[index] = getNode();
        }
        pCrawl->letter=key[level];
        pCrawl = pCrawl->children[index];
    }

    if(pCrawl->counter!=0)
        pCrawl->counter++;
    else
        pCrawl->counter=1;

    printf("counter slow 3= %d\n", pCrawl->counter);
}

// Returns non zero, if key presents in trie
int search(trie_t *pTrie, char key[])
{
    int level;
    int length = strlen(key);
    int index;
    trie_node_t *pCrawl;

    pCrawl = pTrie->root;

    for( level = 0; level < length; level++ )
    {
        index = CHAR_TO_INDEX(key[level]);

        if( !pCrawl->children[index] )
        {
            return 0;
        }

        pCrawl = pCrawl->children[index];
    }

    return (0 != pCrawl && pCrawl->counter);
}

// Driver
int main()
{
    // Input keys (use only 'a' through 'z' and lower case)
    char keys[][15] = {"THE", "THE", "BYE", "A", "THERE", "ANSWER", "ANSWER", "BBUWNTSMFK", "THE", "THEIR", "ANSWER", "THE", "LOL", "OMG", "WTF"};
    trie_t trie;

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

    initialize(&trie);

    // Construct trie
    for(int i = 0; i < ARRAY_SIZE(keys); i++)
    {
        insert(&trie, keys[i]);
    }

    char word[1000] = {0};
    setorder(&trie, word);

    // Search for different keys
    printf("%s --- %s\n", "THE", output[search(&trie, "THE")] );
    printf("%s --- %s\n", "THESE", output[search(&trie, "THESE")] );
    printf("%s --- %s\n", "THEIR", output[search(&trie, "THEIR")] );
    printf("%s --- %s\n", "THAW", output[search(&trie, "THAW")] );

    return 0;
}

1 个答案:

答案 0 :(得分:1)

我认为您的代码中存在一些概念错误。基本的trie插入有效,但计算出现次数是错误的。

首先,您在此处提供的代码无法编译,因为您在trie_t中混淆了trie_node_tsetorder。如果要引用整个结构,请使用trie_t;当引用该结构中的节点及其子节点(和孙子节点等)节点时,请使用tire_node_t。当您对trie进行抓取时,您会关注trie_node_t节点,从root的{​​{1}}开始。

然后,当你插入一个节点时,你不需要在分配计数器时区分零和非零情况,只需

trie_t

会做的。 (如果你考虑一下,你应该看到递增零产生一个,所以你只是抓住一个不需要特别对待的所谓特殊情况。你的代码没有错,只是不必要的复杂。)

好的,继续走路,并报告单词的出现次数。我不太确定pCrawl->counter++; 中发生了什么,但同样,它看起来很复杂。摆脱辅助数组setorder。我认为该阵列的簿记会使您的程序出现段错误。您还可以删除counters的{​​{1}}字段。您需要的所有信息都在trie节点本身及其连接中。特别是,letter由您从其父节点到达此节点的路径给出。 trie_node_t表示它是A,letter表示它是X.

尝试是一种树木,树木最好随着递归而爬行。所以让我们写一个children[0]的递归变体:

children[23]

一个前端函数,它将定义一个临时数组并在根节点开始递归:

setorder

递归函数向下遍历节点,向字符串添加适当的字母,并在找到单​​词时打印计数。 trie的当前级别等于当前字符串长度,并且都等于当前递归深度,即函数调用自身的次数。

插入和搜索之间的区别在于,在这里,我们没有通过单词给出的单个线性路径,即字母序列,但我们必须沿着所有现有的子节点走下去。

在非递归函数中,我们必须走第一条路径,回溯到所有分支点,再向下走一点,依此类推。控制所有爬行和倒退都是非常繁琐的。在递归函数中,向下搜索对应于对#define INDEX_TO_CHAR(IX) ('A' + IX) void setorder_rec(trie_node_t *pCrawl, char *str, int n) { if (pCrawl == NULL) return; if (pCrawl->counter) { printf("%.*s: %d\n", n, str, pCrawl->counter); } for (int i = 0; i < ALPHABET_SIZE; i++) { str[n] = INDEX_TO_CHAR(i); setorder_rec(pCrawl->children[i], str, n + 1); } } 的调用,向上爬回对应于从void setorder(trie_t *pTrie) { char tempword[40] = {0}; setorder_rec(pTrie->root, tempword, 0); } 返回。

请注意,我创建了第二个宏,即setorder_rec的反转。在搜索trie时,我们需要知道char中的索引。当无条件地走遍所有分支时,我们需要能够从子索引中重建一个单词的字符。

如果您不想仅打印计数但想要创建数组,则可以使用示例中的全局索引。但是你必须将这些单词本身与计数一起存储,也许在第二个数组中存储,也许在一个特殊的结构中。

最后一点:你的程序没有防止计算错误的指数。如果您添加的字词不是全部大写字母行setorder_recCHAR_TO_INDEX,则会出现访问冲突。