二叉排序树删除、搜索、插入的迭代实现
@Author: 张海拔
@Update: 2014-01-24
@Link: http://www.cnblogs.com/zhanghaiba/p/3532885.html
迭代实现的难点是删除操作。
难点1是想清楚各种情况下的删除(逻辑难点),难点2是迭代实现中的删除操作中一般都涉及指向指针的指针(C语言实现难点)。
难点1解答——
删除伴随着搜索过程,当搜不到待删节点则忽略操作,若找到待删节点D,分三种情况
1)如果D有左孩子,说明在BST排序序列(中序序列:从小到大)中,D至少会存在直接的前驱节点C,而C必定是D节点左子树里面值最大的节点。
因为要满足“直接”这个条件,即C紧靠在D的左边,所以要求C是D节点的左子树的最大节点。
而左子树也是BST,若左子树本身没有右孩子则树根最大;否则左子树的最右孩子最大。
换句话说,C要么是D的左孩子,要么是D的左孩子的最右孩子。(可见,C的特征是没有右孩子,否则就不会是最大了)
我们可以获得指向C的指针,然后将C的值赋值给D,类似于数组[2, 3, 5, 7, 9, 11, 13]变为[2, 3, 5, 5, 9, 11, 13]这种情形(假设D==7,则求出C==5)。
此时我们可以认为C和D两个结点交换位置了(删掉C后仍是BST),所以问题从删除D转换为删除C。(因为C有固定的特征)
我们已经拥有指向C的指针q,而C的特征是没有右孩子(左孩子不一定有),这确保了C的直接前驱就是其左孩子,
所以剩下的工作是,把原本指向C的指针q指向C的左孩子,和释放C节点内存。
2)如果D没有左孩子但有右孩子,说明在BST排序中,D肯定存在直接后继节点E,而E必定是D节点右子树中的最小节点。
接下来的分析与1)的分析是对称的。
3)如果D是叶子,则直接删除D,把指向D的指针置为NULL。
难点2解答——
当我们不使用指向指针的指针时,设指针p指向待删节点D,这个p仅仅是D的父节点的next指针的一个副本,
用来释放D节点没有问题,但将p置为NULL,并没有将D的父节点的next置为NULL。
这在删除叶子这种简单情况时几乎一定会发生段错误(访问到了非法内存)。
所以先保存root为save,设link *p = &root,始终保存指向指针的指针( 如p = &((*p)->left) ),
当我们找到C(真正要删的节点)时( C满足的条件是(*p)->right == NULL ),*p就是C的父节点的next,这样便可以正确修改了。
另外,当删除BST最后一个节点后,返回如果仍是root,则出错,因为root和*p共享了节点内存。
在这种情况下,不仅是*p需要置为NULL,root也要置为NULL。所以加入代码:if (*p == save) save = NULL;
值得一提是:
这里迭代实现与 "二叉排序树删除、搜索、插入的递归实现 link(public) ",删除操作都是正确的,但具体方式有区别。
看下面的一棵树,删除值为50的节点时——
50 ___|___ | | 38 65 _|__ _|__ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 67 _|__ | | /*递归删除50后的BST*/ 38 ___|___ | | 36 65 _|__ _|__ | | | | 35 70 _|__ _|__ | | | | 68 _|__ | | 67 _|__ | | /*迭代删除50后的BST*/ 38 ___|___ | | 35 65 _|__ _|__ | | | | 36 70 _|__ _|__ | | | | 68 _|__ | | 67 _|__ | |
递归实现中,删除50时,会递归地去删除38(50变成38),删除38又递归删除36(38变36),最后归结为删除36这个叶子(原来的36)
迭代实现中,删除50时,38赋值给50,然后直接删除38(原来的38),并把指向38的指针(即是根节点的next指针)更改为指向原38节点的左孩子(肯定要事先保存该指针)。
下面的二叉排序树完整的迭代实现,以及一个删除情况足够多的测试示范。
1 /* 2 *Author: ZhangHaiba 3 *Date: 2014-1-24 4 *File: binary_search_tree_iter.c 5 * 6 *this demo shows how to build a BST data structure 7 *and support some command line to operate this BST 8 *such like i(insert), d(delete), s(search), q(quit) etc 9 *interestingly, this demo use tree module which written by Greg Lee 10 *making BST data structure and it's opreation visualization 11 * 12 *hint: implementation iterative 13 */ 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <stdbool.h> 18 #define MOD 256 19 #define CMD_LEN 128 20 21 typedef struct node* link; 22 23 typedef struct node { 24 int item; 25 link left; 26 link right; 27 }node; 28 29 //public 30 link NODE(int item, link left, link right); //as constructor 31 link bst_insert(link root, int item); 32 link bst_delete(link root, int item); 33 link bst_search(link root, int item); 34 void bst_inorder(link root); 35 void bst_show_by_tree(link root); 36 //private 37 link* pre(link root); 38 link* next(link root); 39 void inorder(link root); //included in bst_inorder() 40 void tree_print(link root, FILE* fd); //included in bst_show_by_tree() 41 42 int main(void) 43 { 44 45 link r = NULL; //BST root 46 47 //operating this the BST r 48 49 /*** Command Line Manual ***/ 50 /* 51 * "i 100" means insert item which value 100 52 * "d 200" means delete item which value 200 53 * "s 300" means search item which value 300 54 * "p" means call the tree module to print the BST tree 55 * "l" means list the inorder list of BST 56 * "q" means quit 57 */ 58 59 while (true) { 60 char cmd[CMD_LEN]; 61 62 scanf("%s", cmd); 63 if (cmd[0] == 'q') 64 break; 65 else if (cmd[0] == 'i' || cmd[0] == 'd' || cmd[0] == 's') { 66 int item; 67 scanf("%d", &item); 68 if (cmd[0] == 'i') 69 r = bst_insert(r, item); 70 else if (cmd[0] == 'd') 71 r = bst_delete(r, item); 72 else { 73 link aim_link = bst_search(r, item); 74 if (aim_link == NULL) 75 printf("Not Found!\n"); 76 else 77 printf("Found: %d\n", aim_link->item); 78 } 79 } 80 else if (cmd[0] == 'p') 81 bst_show_by_tree(r); 82 else if (cmd[0] == 'l') 83 bst_inorder(r); 84 else 85 ; //ingnore illegal command line 86 } 87 return 0; 88 } 89 90 link NODE(int item, link left, link right) 91 { 92 link born = malloc(sizeof (node)); 93 born->item = item; 94 born->left = left; 95 born->right = right; 96 return born; 97 } 98 99 link bst_insert(link root, int item) 100 { 101 if (root == NULL) 102 return NODE(item, NULL, NULL); 103 link p = root; 104 while (true) { 105 if (item < p->item) { 106 if (p->left != NULL) 107 p = p->left; 108 else { 109 p->left = NODE(item, NULL, NULL); 110 return root; 111 } 112 } else if (item > p->item) { 113 if (p->right != NULL) 114 p = p->right; 115 else { 116 p->right = NODE(item, NULL, NULL); 117 return root; 118 } 119 } else 120 return root; 121 } 122 } 123 124 link bst_delete(link root, int item) 125 { 126 if (root == NULL) 127 return NULL; 128 link save = root; 129 link *p = &root; 130 while (true) { 131 if (item < (*p)->item) { 132 if ((*p)->left != NULL) 133 p = &((*p)->left); 134 else 135 return save; //if search failed then delete nothing 136 } else if (item > (*p)->item) { 137 if ((*p)->right != NULL) 138 p = &((*p)->right); 139 else 140 return save; 141 } else { 142 if ((*p)->left != NULL) { 143 link *q = pre(*p); 144 (*p)->item = (*q)->item; 145 link del = *q; 146 *q = (*q)->left; 147 free(del); 148 } else if ((*p)->right != NULL) { 149 link *q = next(*p); 150 (*p)->item = (*q)->item; 151 link del = *q; 152 *q = (*q)->right; 153 free(del); 154 } else { 155 free(*p); 156 if (*p == save) //guarantee delete correctly in case: BST those have only one node 157 save = NULL; 158 *p = NULL; 159 } 160 return save; 161 } 162 } 163 } 164 165 link bst_search(link root, int item) 166 { 167 if (root == NULL) 168 return NULL; 169 link p = root; 170 while (true) { 171 if (item < p->item) { 172 if (p->left != NULL) 173 p = p->left; 174 else 175 return NULL; 176 } else if (item > p->item) { 177 if (p->right != NULL) 178 p = p->right; 179 else 180 return NULL; 181 } else 182 return p; 183 } 184 } 185 186 //guarantee root != NULL 187 link* pre(link root) 188 { 189 link *p = &(root->left); 190 191 while ((*p)->right != NULL) 192 p = &((*p)->right); 193 return p; 194 } 195 196 //guarantee root != NULL 197 link* next(link root) 198 { 199 link *p = &(root->right); 200 201 while ((*p)->left != NULL) 202 p = &((*p)->left); 203 return p; 204 } 205 206 void bst_inorder(link root) 207 { 208 inorder(root); 209 printf("\n"); 210 } 211 212 void inorder(link root) 213 { 214 if (root == NULL) 215 return; 216 inorder(root->left); 217 printf("%d ", root->item); 218 inorder(root->right); 219 } 220 221 void bst_show_by_tree(link root) 222 { 223 char cmd[CMD_LEN]; 224 225 sprintf(cmd, "rm -f ./tree_src.txt"); 226 system(cmd); 227 228 FILE *fd = fopen("./tree_src.txt", "a+"); 229 fprintf(fd, "\n\t\\tree"); 230 tree_print(root, fd); 231 fprintf(fd, "\n\n"); 232 fclose(fd); 233 234 sprintf(cmd, "cat ./tree_src.txt | ~/tree/tree"); 235 system(cmd); 236 } 237 238 void tree_print(link root, FILE *fd) 239 { 240 fprintf(fd, "("); 241 if (root != NULL) { 242 fprintf(fd, "%d", root->item); 243 tree_print(root->left, fd); 244 tree_print(root->right, fd); 245 } 246 fprintf(fd, ")"); 247 }
测试示范:
ZhangHaiba-MacBook-Pro:code apple$ ./a.out p i 50 p 50 _|__ | | i 45 i 55 p 50 ___|___ | | 45 55 _|__ _|__ | | | | i 35 i 36 i 39 i 38 l 35 36 38 39 45 50 55 i 70 i 68 i 61 i 65 i 62 i 67 p 50 ____|____ | | 45 55 _|__ __|___ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 39 61 _|__ _|__ | | | | 38 65 _|__ ___|___ | | | | 62 67 _|__ _|__ | | | | l 35 36 38 39 45 50 55 61 62 65 67 68 70 s 66 Not Found! s 62 Found: 62 s 39 Found: 39 s 37 Not Found! d 62 p 50 ____|____ | | 45 55 _|__ __|___ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 39 61 _|__ _|__ | | | | 38 65 _|__ _|__ | | | | 67 _|__ | | d 45 p 50 ____|____ | | 39 55 _|__ __|___ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 38 61 _|__ _|__ | | | | 65 _|__ | | 67 _|__ | | d 55 p 50 ____|____ | | 39 61 _|__ __|___ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 38 65 _|__ _|__ | | | | 67 _|__ | | d 39 p 50 ___|___ | | 38 61 _|__ _|__ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 65 _|__ | | 67 _|__ | | d 61 p 50 ___|___ | | 38 65 _|__ _|__ | | | | 35 70 _|__ _|__ | | | | 36 68 _|__ _|__ | | | | 67 _|__ | | d 50 p 38 ___|___ | | 35 65 _|__ _|__ | | | | 36 70 _|__ _|__ | | | | 68 _|__ | | 67 _|__ | | d 38 d 68 d 70 d 35 d 36 d 67 p 65 _|__ | | d 65 p i 99 p 99 _|__ | | q