二进制搜索树插入垃圾数据

Binary Search Tree Insert Garbage Data

本文关键字:数据 插入 搜索树 二进制      更新时间:2023-10-16

所以,我正在为一个项目编写一个自我平衡的二进制搜索树,而且我似乎对插入功能有问题。具体来说,此处的代码块:

if(element > n->data)
{
    n->rightChild = insert(n->rightChild, element);
}   

为了进行测试,我只是使用插入(root,10(插入(root,20(插入(root,30(等。问题发生在插入30。它通过并试图用另一个非空子树代替非空子树(20(。我不确定为什么我似乎遇到这个问题,因为递归是我看到的唯一方法,在我发现的所有其他问题中,答案都是以类似的方式编码的与此完全相同。谁能帮我弄清楚发生了什么事?目前,在尝试用30的30个子树覆盖20个子树之后,它最终会用垃圾数据填充右孩子,然后当它尝试重新平衡时,会引发exc_bad_access错误,大概是因为我试图访问一个没有做的节点存在。

源代码

#include <iostream>
using namespace std;
struct node
{
public:
    int data, height;
    node *leftChild, *rightChild;
};
int findMin(struct node *p) // finds the smallest node in the tree
{
    while (p->leftChild != NULL)
        p = p->leftChild;
    return p->data;
}
int findMax(struct node *p) // finds the largest node in the tree
{
    while(p->rightChild != NULL)
        p = p->rightChild;
    return p->data;
}
int max(int a, int b) // gets the max of two integers
{
    if(a > b)
        return a;
    else
        return b;
}
int height(struct node *p) // gets the height of the tree
{
    int lHeight, rHeight;
    if(p == NULL)
        return -1;
    else
    {
        lHeight = height(p->leftChild);
        rHeight = height(p->rightChild);
        if(lHeight > rHeight)
            return lHeight + 1;
        else
            return rHeight + 1;
    }
}
struct node* newNode(int element) // helper function to return a new node with empty subtrees
{
    node* newPtr = (struct node*) malloc(sizeof(newPtr));
    newPtr->data = element;
    newPtr->leftChild = NULL;
    newPtr->rightChild = NULL;
    newPtr->height = 1;
    return newPtr;
}
struct node* rightRotate(struct node* p) // function to right rotate a tree rooted at p
{
    node* child = p->leftChild;
    node* grandChild = child->rightChild;
    // perform the rotation
    child->rightChild = p;
    p->leftChild = grandChild;
    // update the height for the nodes
    p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
    child->height = max(height(child->leftChild), height(child->rightChild)) + 1;
    // return new root
    return child;
}
struct node* leftRotate(struct node* p) // function to left rotate a tree rooted at p
{
    node* child = p->rightChild;
    node* grandChild = child->leftChild;
    // perform the rotation
    child->leftChild = p;
    p->rightChild = grandChild;
    // update heights
    p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
    // return new root
    return child;
}
int getBalance(struct node *p)
{
    if(p == NULL)
        return 0;
    else
        return height(p->leftChild) - height(p->rightChild);
}
// recursive version of BST insert to insert the element in a sub tree rooted with root
// which returns new root of subtree
struct node* insert(struct node*& n, int element)
{
    // perform the normal BST insertion
    if(n == NULL) // if the tree is empty
        return(newNode(element));
    if(element< n->data)
    {
        n->leftChild = insert(n->leftChild, element);
    }
    if(element > n->data)
    {
        n->rightChild = insert(n->rightChild, element);
    }
    else // duplicate node
    {
        return n;
    }
    // update the height for this node
    n->height = 1 + max(height(n->leftChild), height(n->rightChild));
    // get the balance factor to see if the tree is unbalanced
    int balance = getBalance(n);
    // the tree is unbalanced, there are 4 different types of rotation to make
    // Single Right Rotation (Left Left Case)
    if(balance > 1 && element < n->leftChild->data)
    {
        return rightRotate(n);
    }
    // Single Left Rotation (Right Right Case)
    if(balance < -1 && element > n->rightChild->data)
    {
        return leftRotate(n);
    }
    // Left Right Rotation
    if(balance > 1 && element > n->leftChild->data)
    {
        n->leftChild = leftRotate(n->leftChild);
        return rightRotate(n);
    }
    // Right Left Rotation
    if(balance < -1 && element < n->rightChild->data)
    {
        n->rightChild = rightRotate(n->rightChild);
        return leftRotate(n);
    }
    cout << "Height: " << n->height << endl;
    // return the unmodified root pointer in the case that the tree does not become unbalanced
    return n;
}
void inorder(struct node *p)
{
    if(p != NULL)
    {
        inorder(p->leftChild);
        cout << p->data << ", ";
        inorder(p->rightChild);
    }
}
void preorder(struct node *p)
{
    if(p != NULL)
    {
        cout << p->data << ", ";
        preorder(p->leftChild);
        preorder(p->rightChild);
    }
}
void print(struct node* root)
{
    cout << "Min Value: " << findMin(root) << endl;
    cout << "Max Value: " << findMax(root) << endl;
    cout << "Pre Order: ";
    preorder(root);
    cout << "Inorder: ";
    inorder(root);
}
int main()
{
    struct node* root = NULL;
    root = insert(root, 10);
    root = insert(root, 20);
    root = insert(root, 30);
    root = insert(root, 40);
    root = insert(root, 50);
    root = insert(root, 25);
//    int array[11] = {25, 5, 6, 17, 34, 2, 57, 89, 12, 12, 73};
//    for(int i = 0; i < 11; i++)
//    {
//        root = insert(root, array[i]);
//    }
    preorder(root);
    return 0;
}

我不确定这是您遇到的唯一问题,但这是一个可能导致严重失败的问题:

struct node* newNode(int element) // helper function to return a new node with empty subtrees
{
    node* newPtr = (struct node*) malloc(sizeof(newPtr));

在这里,您可以分配存储器以持有node*

您想要的是持有node的内存。

而是尝试一下:

struct node* newNode(int element) // helper function to return a new node with empty subtrees
{
    node* newPtr = (struct node*) malloc(sizeof(*newPtr));
                                                ^
                                              notice

更新:

在评论中,OP问:

实际上确实修复了它,谢谢!有人可以解释为什么吗?

当您这样做时:

node* newPtr = (struct node*) malloc(sizeof(newPtr));

与:

相同
node* newPtr = (struct node*) malloc(sizeof(node*));

因此,您分配了持有指针的内存 - 大概是8或4个字节。

然后,您开始使用此代码写入内存区域:

newPtr->data = element;
newPtr->leftChild = NULL;
newPtr->rightChild = NULL;
newPtr->height = 1;

这些写作比分配的8(或4个(字节占用更多,因此您将记忆写入不属于程序的内存。那是不确定的行为(又称"任何可能发生的事情"(,从那里分析出了什么问题是没有意义的。

但是,后来可能会覆盖内存(例如,在第二秒malloc之后(,从而破坏了初始书面的值。因此,当您再次阅读内存时,您得到了与初始书面的值不同的东西,从那里出现了全部错误。