[英]Insertion into AVL tree only replaces root node
我目前正在執行一項任務,其中必須打印一本書 (.txt) 中最常用的 N 個單詞。 我目前面臨的問題是,當我將一個節點添加到我的一棵樹時,它只是替換了根節點,因此,樹仍然是一個節點。
將文件“stopwords.txt”中的單詞添加到名為 stopwords 的樹中的代碼片段:
Dict stopwords = newDict();
if (!readFile("stopwords.txt"))
{
fprintf(stderr, "Can't open stopwords\n");
exit(EXIT_FAILURE);
}
FILE *fp = fopen("stopwords.txt", "r");
while (fgets(buf, MAXLINE, fp) != NULL)
{
token = strtok(buf, "\n");
DictInsert(stopwords, buf); //the root is replaced here
}
fclose(fp);
數據結構定義如下:
typedef struct _DictNode *Link;
typedef struct _DictNode
{
WFreq data;
Link left;
Link right;
int height;
} DictNode;
typedef struct _DictRep *Dict;
struct _DictRep
{
Link root;
};
typedef struct _WFreq {
char *word; // word buffer (dynamically allocated)
int freq; // count of number of occurences
} WFreq;
插入和重新平衡樹的代碼:
// create new empty Dictionary
Dict newDict(void)
{
Dict d = malloc(sizeof(*d));
if (d == NULL)
{
fprintf(stderr, "Insufficient memory!\n");
exit(EXIT_FAILURE);
}
d->root = NULL;
return d;
}
// insert new word into Dictionary
// return pointer to the (word,freq) pair for that word
WFreq *DictInsert(Dict d, char *w)
{
d->root = doInsert(d->root, w); //the root is replaced here before doInsert runs
return DictFind(d, w);
}
static int depth(Link n)
{
if (n == NULL)
return 0;
int ldepth = depth(n->left);
int rdepth = depth(n->right);
return 1 + ((ldepth > rdepth) ? ldepth : rdepth);
}
static Link doInsert(Link n, char *w)
{
if (n == NULL)
{
return newNode(w);
}
// insert recursively
int cmp = strcmp(w, n->data.word);
if (cmp < 0)
{
n->left = doInsert(n->left, w);
}
else if (cmp > 0)
{
n->right = doInsert(n->right, w);
}
else
{ // (cmp == 0)
// if time is already in the tree,
// we can return straight away
return n;
}
// insertion done
// correct the height of the current subtree
n->height = 1 + max(height(n->left), height(n->right));
// rebalance the tree
int dL = depth(n->left);
int dR = depth(n->right);
if ((dL - dR) > 1)
{
dL = depth(n->left->left);
dR = depth(n->left->right);
if ((dL - dR) > 0)
{
n = rotateRight(n);
}
else
{
n->left = rotateLeft(n->left);
n = rotateRight(n);
}
}
else if ((dR - dL) > 1)
{
dL = depth(n->right->left);
dR = depth(n->right->right);
if ((dR - dL) > 0)
{
n = rotateLeft(n);
}
else
{
n->right = rotateRight(n->right);
n = rotateLeft(n);
}
}
return n;
}
static Link newNode(char *w)
{
Link n = malloc(sizeof(*n));
if (n == NULL)
{
fprintf(stderr, "Insufficient memory!\n");
exit(EXIT_FAILURE);
}
n->data.word = w;
n->data.freq = 1;
n->height = 1;
n->left = NULL;
n->right = NULL;
return n;
}
// Rotates the given subtree left and returns the root of the updated
// subtree.
static Link rotateLeft(Link n)
{
if (n == NULL)
return n;
if (n->right == NULL)
return n;
Link rightNode = n->right;
n->right = rightNode->left;
rightNode->left = n;
n->height = max(height(n->left), height(n->right)) + 1;
rightNode->height = max(height(rightNode->right), n->height) + 1;
return rightNode;
}
// Rotates the given subtree right and returns the root of the updated
// subtree.
static Link rotateRight(Link n)
{
if (n == NULL)
return n;
if (n->left == NULL)
return n;
Link leftNode = n->left;
n->left = leftNode->right;
leftNode->right = n;
n->height = max(height(n->left), height(n->right)) + 1;
leftNode->height = max(height(leftNode->right), n->height) + 1;
return leftNode;
}
我相信大部分代碼都是有效的,只是插入失敗了。 當我嘗試使用 gdb 進行調試時,我發現根節點(d->root)在遞歸插入 function(doInsert)運行之前被替換,導致程序總是返回節點 n,結果,已經存在於樹中。 例如,如果文本文件包含以下內容:
一個
b
c
然后程序會首先插入"a"
作為stopwords->root
,然后"b"
將替換"a"
並成為新的stopwords->root
,最后"c"
將替換"b"
作為stopwords->root
,結果在具有一個節點的樹中, "c"
。
您的代碼中有許多不一致之處。
這里有一個錯誤:
d->root = doInsert(d->root, w);
每次插入新節點時,您都會無條件地重新分配根。
您應該從 function doInsert
返回新節點,並且僅當新節點已成為新根時才重新分配根。
但是你犯的另一個錯誤是你從doInsert
返回了一個局部變量n
,它不是新分配的,而是初始化為指向前一個根的。
在doInsert
內部,您需要分配一個新節點NEW
並使用變量x
從根向下走,直到找到插入新分配節點NEW
的位置。 如果x
在 root 處停止,則重新初始化d->root = NEW
。
您的 function newNode
僅存儲傳遞的字符串指針,因此當您修改原始字符串時,指向的內容會發生變化。
為防止這種情況,您應該在節點插入時復制輸入字符串。
要存檔,
n->data.word = w;
應該
n->data.word = malloc(strlen(w) + 1);
if (n->data.word == NULL)
{
fprintf(stderr, "Insufficient memory!\n");
exit(EXIT_FAILURE);
}
strcpy(n->data.word, w);
添加#include <string.h>
以使用strlen()
和strcpy()
如果不是。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.