二叉搜索树的查找、删除、插入
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 }
注意事项:
- 注意值传递和址传递的情况,希望传入的值有所改变,并且在调用函数外部依旧用到这个值,就用址传递,其他时候都可以了
- 在删除的时候,要释放空间
- 删除操作的时候,删除节点要赋值,注意有种情况是直接赋值的,而不是节点相等,赋值后,对之后改变的子树进行操作。