二进制搜索树插入垃圾数据
Binary Search Tree Insert Garbage Data
所以,我正在为一个项目编写一个自我平衡的二进制搜索树,而且我似乎对插入功能有问题。具体来说,此处的代码块:
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
之后(,从而破坏了初始书面的值。因此,当您再次阅读内存时,您得到了与初始书面的值不同的东西,从那里出现了全部错误。
相关文章:
- 逐行读取文件,并将数据插入变量和数组中
- Qt & SqlLite 将数据插入数据库
- C++ - 将数据插入到地图循环的地图中
- SQLite C/C++ 接口:将数据插入表时内存增加
- C++将 X 向量数据插入到另一个向量
- 如何通过 C 变量将数据插入表中
- 将数据插入一些复杂的数据结构-C
- 将数据插入C 中的文本文件中
- 如何通过c++中的应用程序将数据插入solr
- 在Windows上将数据插入文件
- C++链表——如何将每个新数据插入尾部
- C++链表实现多数据插入
- 在c++中,将数据插入到文件中的特定位置而不进行覆盖
- C++内存从将数据插入链表中泄漏
- 将数据插入多维向量并进行排序
- WINAPI SQLite C无法正确地将数据插入数据库
- 参照同一矢量的数据插入矢量
- PostgreSQL字节二进制数据插入
- Cuda有效地将数据插入到未排序的填充数组中
- 使用 ADO 将原始文件数据插入访问表的 BLOB("OLE 对象")字段