C++ 二叉搜索树
我已经用c实现了二叉搜索树++C++ 二叉搜索树,c++,C++,我已经用c实现了二叉搜索树++ #include <iostream> #include <cstdlib> using namespace std; class binary{ private: struct tree{ tree *left; tree *right; int data; }; tree *root; public: binary(){
#include <iostream>
#include <cstdlib>
using namespace std;
class binary{
private:
struct tree{
tree *left;
tree *right;
int data;
};
tree *root;
public:
binary(){
root=NULL;
}
bool empty() { return root=NULL;}
void print_inorder();
void inorder(tree*);
void print_preorder();
void pre_order(tree*);
void print_postorder();
void post_order(tree *);
void insert(int);
void remove(int);
};
void binary::insert(int d){
tree *t=new tree;
tree *parent;
t->data=d;
t->left=NULL;
t->right=NULL;
parent=NULL;
//is new tree;
if (empty()) root=t;
else{
tree *current;
current=root;
//find Nod's parent
while (current){
parent=current;
if (t->data>current->data) current=current->right;
else current=current->left;
}
if (t->data<parent->data)
parent->left=t;
else
parent->right=t;
}
}
void binary::remove(int d){
//locate the element
bool found=true;
if (empty()){
cout<<"tree is empty"<<endl;
return ;
}
tree *current;
tree *parent;
current=root;
while (current!=NULL){
if (current->data==d){
found=true;
break;
}
else{
parent=current;
if (d>current->data) current=current->right;
else current=current->left;
}
}
if (!found){
cout<<"data not found "<<endl;
return ;
}
//three case
// 1. We're removing a leaf node
// 2. We're removing a node with a single child
// 3. we're removing a node with 2 children
// Node with single child
if ((current->left==NULL && current->right!=NULL )||(current->left!=NULL && current->right==NULL)){
if (current->left==NULL && current->right!=NULL){
if(parent->left==current){
parent->left=current->right;
delete current;
}
else{
parent->right=current->right;
delete current;
}
}
else // left child present, no right child
{
if (parent->left==current){
parent->left=current->left;
delete current;
}
else{
parent->right=current->left;
delete current;
}
}
return ;
}
if (current->left==NULL && current->right==NULL){
if (parent->left==current) parent->left=NULL;
else parent->right==NULL;
delete current;
return ;
}
//node with 2 children
//replace node with smalles value in right subtree
if ( current->left!=NULL && current->right!=NULL){
tree *ch;
ch=current->right;
if ((ch->left==NULL) &&(ch->right==NULL))
{
current=ch;
delete ch;
current->right=NULL;
}
else// right child has children
{
//if the node's right child has a left child
// Move all the way down left to locate smallest element
if ((current->right)->left!=NULL){
tree * rr;
tree * lr;
lr=current->right;
rr=(current->right)->left;
while (rr->left!=NULL){
lr=rr;
rr=rr->left;
}
current->data=rr->data;
delete rr;
lr->left=NULL;
}
else
{
tree *tmp;
tmp=current->right;
current->data=tmp->data;
current->right=tmp->right;
delete tmp;
}
}
return;
}
}
void binary::print_inorder(){
inorder(root);
}
void binary::inorder(tree *p){
if (p!=NULL){
if (p->left) inorder(p->left);
cout<<" "<<p->data<<" ";
if (p->right) inorder(p->right);
}
else return ;
}
void binary::print_preorder(){
pre_order(root);
}
void binary::pre_order(tree *p){
if (p!=NULL){
cout<<" "<<p->data<<" ";
if (p->left) pre_order(p->left);
if (p->right) pre_order(p->right);
}
else return ;
}
void binary::print_postorder(){
post_order(root);
}
void binary::post_order(tree *p){
if (p!=NULL){
if (p->left) post_order(p->left);
if (p->right) post_order(p->right);
cout<<" "<<p->data;
}
else return ;
}
int main(){
binary b;
int ch,tmp,tmp1;
while (1){
cout<<endl<<endl;
cout<<" Binary Search Tree Operations "<<endl;
cout<<" ----------------------------- "<<endl;
cout<<" 1. Insertion/Creation "<<endl;
cout<<" 2. In-Order Traversal "<<endl;
cout<<" 3. Pre-Order Traversal "<<endl;
cout<<" 4. Post-Order Traversal "<<endl;
cout<<" 5. Removal "<<endl;
cout<<" 6. Exit "<<endl;
cout<<" Enter your choice : ";
cin>>ch;
switch(ch)
{
case 1: cout<<"enter number to be inserted:";
cin>>tmp;
b.insert(tmp);
break;
case 2: cout<<endl;
cout<<"in order traversal"<<endl;
cout<<"------------------"<<endl;
b.print_inorder();
break;
case 3: cout<<endl;
cout<<"pre order traversal "<<endl;
cout<<"------------------"<<endl;
b.print_preorder();
break;
case 4: cout<<endl;
cout<<"post order traversal"<<endl;
cout<<"---------------------"<<endl;
b.print_postorder();
break;
case 5: cout<<"enter data to be deleted:";
cin>>tmp1;
b.remove(tmp1);
break;
case 6:
return 0;
}
}
return 0;
}
为什么?发生此类问题的原因是什么?问题在于:
bool empty() { return root=NULL;}
改为:
bool empty() { return root == NULL;}
问题在于:
bool empty() { return root=NULL;}
改为:
bool empty() { return root == NULL;}
在Linux系统上的gdb下运行代码,这是报告的错误:
Program received signal SIGSEGV, Segmentation fault.
0x080488ac in binary::insert (this=0xbffff33c, d=7) at so.cpp:52
52 if (t->data<parent->data)
程序接收信号SIGSEGV,分段故障。
二进制中的0x080488ac::在so.cpp:52处插入(this=0xbfff33c,d=7)
52如果(t->datadata)
在您的情况下,
parent
为空;这是因为在empty()
方法中,您使用的是root=NULL
(将root
设置为NULL
)而不是root==NULL
(检查root
是否为NULL
)。在Linux系统上的gdb下运行代码,这是报告的错误:
Program received signal SIGSEGV, Segmentation fault.
0x080488ac in binary::insert (this=0xbffff33c, d=7) at so.cpp:52
52 if (t->data<parent->data)
程序接收信号SIGSEGV,分段故障。
二进制中的0x080488ac::在so.cpp:52处插入(this=0xbfff33c,d=7)
52如果(t->datadata)
在您的情况下,
parent
为空;这是因为在empty()
方法中,您使用的是root=NULL
(将root
设置为NULL
)而不是root==NULL
(检查root
是否为NULL
)。我看到的最明显错误是,empty的实现实际上删除了树的根。它应该返回root==NULL
的结果,而不是将NULL
赋值给root
(root=NULL
)的结果。由于树实际上是空的,NULL相当于false,这导致采用insert的“search”分支。由于当前
(和根
)为空,父项
永远不会被设置,并且当您尝试检查父项
的数据值时,会出现内存访问错误
你可能还有其他错误,但这就是我所看到的。我建议您基于特定场景为您的单个方法编写一些单元测试,以测试在该场景的条件下每个方法中发生的情况。如果您在编写足以通过测试的代码之前编写测试,这样您就知道当您的代码通过测试时,它是正确的,并且涵盖了测试场景,那么这样做会更好,但是您也可以在之后编写它们。如果您在事后编写代码,就很难知道您是否完全掌握了所需的代码(不再需要)。当调试程序失败时(在本例中,很明显)在调试器中运行这些测试有助于理解出现了什么问题,但是如果您以测试为指导慢慢构建代码,您通常可以锁定错误所在的点,而不使用该点。我看到的最明显的错误是,您的empty实现实际上删除了树的根。它应该返回
root==NULL
的结果,而不是将NULL
赋值给root
(root=NULL
)的结果。由于树实际上是空的,NULL相当于false,这导致采用insert的“search”分支。由于当前
(和根
)为空,父项
永远不会被设置,并且当您尝试检查父项
的数据值时,会出现内存访问错误
你可能还有其他错误,但这就是我所看到的。我建议您基于特定场景为您的单个方法编写一些单元测试,以测试在该场景的条件下每个方法中发生的情况。如果您在编写足以通过测试的代码之前编写测试,这样您就知道当您的代码通过测试时,它是正确的,并且涵盖了测试场景,那么这样做会更好,但是您也可以在之后编写它们。如果您在事后编写代码,就很难知道您是否完全掌握了所需的代码(不再需要)。当调试失败时在调试器中运行这些测试(在本例中,非常明显)有助于理解出错的原因,但如果您以测试为指导缓慢地构建代码,通常可以确定错误所在的位置。这是逐步通过调试器可以帮助您解决的问题,而不是让我们帮你修复你的代码。这是通过调试程序帮助你的,davit-datuashvili:始终以编译器捕获此问题的方式写入NULL==根。或者使用不接受非布尔作为布尔方法返回类型的强类型语言。davit-datuashvili:始终以编译器捕获此问题的方式写入NULL==根。或者使用不接受非布尔作为布尔方法返回类型的强类型语言。