所以我有这段代码,我必须按照主题编写它 - 找到出现次数最多的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;
}
答案 0 :(得分:1)
我认为您的代码中存在一些概念错误。基本的trie插入有效,但计算出现次数是错误的。
首先,您在此处提供的代码无法编译,因为您在trie_t
中混淆了trie_node_t
和setorder
。如果要引用整个结构,请使用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_rec
或CHAR_TO_INDEX
,则会出现访问冲突。