二叉排序树删除、搜索、插入的迭代实现

 #返回上一级

@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

 

 #返回上一级

posted @ 2014-01-24 20:48  张海拔  阅读(768)  评论(0编辑  收藏  举报