二叉搜索树的查找、删除、插入

  1 #include<iostream>
  2 
  3 using namespace std;
  4 
  5 //二叉搜索树
  6 typedef struct BiNode
  7 {
  8     int data;
  9     struct BiNode *lchild; //这里定义的是BiNode的指针类型
 10     struct BiNode *rchild;
 11 
 12 }BiNode ,*BiTree; //这里面的BiTree前面有一个星星,表示这种结构的指针类型
 13 
 14 //sousuo
 15 //这里的*T代表的是二叉排序树,key表示的是要查找的值 ,f是指向*T的双亲,p是指向查找路线上的最后一个节点
 16 int searchnum(BiTree *T,BiTree f, int key ,BiTree *p) //这里的p一定要有指针或者引用,避免值传递
 17 {
 18     if(!(*T))
 19     {
 20         *p = f ;
 21         return 0;
 22     }
 23     else if(key == (*T)->data)
 24     {
 25         *p = *T;
 26         return 1;
 27     }
 28     else if (key > (*T)->data)
 29     {
 30         searchnum(& ((*T)->rchild) ,*T,key,p); //f是父节点,在这里的赋值体现出来
 31 
 32     }
 33     else 
 34     {
 35         searchnum(& ( (*T)->lchild) ,*T,key,p);
 36     }
 37 }
 38 //插入操作
 39 int insertnum(BiTree &T,int key)
 40 {
 41     BiTree *p = (BiTree *)malloc(sizeof(BiNode));
 42 
 43     if(searchnum(&T,NULL,key,p) != 0 )  //已经有该关键字,不需要插入了
 44     {
 45         return 0;
 46     }
 47     else
 48     {
 49         BiTree s = (BiTree )malloc(sizeof(BiNode));
 50         s->data = key;
 51         s->lchild = s->rchild = NULL;
 52             
 53         if (!(*p))//这里忘了一种情况那就是空树的插入操作 
 54         {
 55             T = s;
 56         }
 57         else if(key > (*p)->data)
 58         {
 59             (*p)->rchild = s;
 60         }
 61         else 
 62         {
 63             (*p)->lchild = s; // 这里不存在等于的那种情况,要不然当一个if就已经检测出来了
 64         }
 65     //然后整个做完之后,看起来似乎无懈可击,但是这样子完全不对的,涉及值传递和址传递的过程
 66         //上面的函数接口部分应该写上函数的值或者引用,因为输出的结果要造成T在整个函数运行后,只得到改变
 67         //我这里为了方便,不更改下面的代码 直接加了一个引用
 68     }
 69 }
 70 
 71 
 72 //00删除操作
 73 
 74 void Delete(BiTree *p)
 75 {
 76     
 77     BiTree s;
 78     if((*p)->lchild == NULL)
 79     {
 80         s = (*p);
 81         (*p) = (*p)->rchild;
 82         free(s);
 83     }
 84     else if( (*p)->rchild == NULL)
 85     {
 86         s = (*p);
 87         (*p) = (*p)->lchild;
 88         free(s); 
 89     }
 90     else  //这种情况两个孩子都不能空了
 91     {
 92         BiTree q,s;
 93         q= (*p);
 94         s= (*p)->lchild; // 这里要取第一个做孩子,向右遍历,到左右的孩子来替换删除节点
 95         while(s->rchild)
 96         {
 97             q = s;
 98             s = s->rchild;
 99         }
100         //这里忘记了替换,找到删除节点的 中序遍历相邻节点 要进行替换的。
101         (*p)->data = s->data ; //这里容易写成(*p)=s ,为什么不能这么写呢,因为这么写就改变了他的结构了,左右孩子都变了。
102         //下面就分两种情况了,就是q有没有移动,换言之就是删除节点的左孩纸有没有节点。
103         //这一步是已经完成了删除,剩下删除的节点左子树的烂摊子要收拾
104         if(q == (*p))
105         {
106             (q)->lchild = s->lchild;
107         }
108         else
109         {
110             (q)->rchild = s->lchild;
111         }
112 
113         free(s);
114     
115 
116     }
117 }
118 
119  int deletenum(BiTree *T ,int key)
120  {
121      if(*T )
122      {
123          return 0;
124      }
125      else
126      {
127         if(key  == (*T)->data)
128         {
129             Delete(T);
130         }
131         else if(key >(*T)->data )
132         {
133             deletenum(&(*T)->rchild ,key);
134         }
135         else
136         {
137             deletenum(&(*T)->lchild ,key);
138         }
139      }
140  }
141 
142 int main()
143 {
144     system("pause");
145 }

注意事项:

  • 注意值传递和址传递的情况,希望传入的值有所改变,并且在调用函数外部依旧用到这个值,就用址传递,其他时候都可以了
  • 在删除的时候,要释放空间
  • 删除操作的时候,删除节点要赋值,注意有种情况是直接赋值的,而不是节点相等,赋值后,对之后改变的子树进行操作。
原文地址:https://www.cnblogs.com/xiaochige/p/8540671.html