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(){

我已经用c实现了二叉搜索树++

#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==根。或者使用不接受非布尔作为布尔方法返回类型的强类型语言。