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


     #返回上一级

    @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!
    ");
     76                 else
     77                     printf("Found: %d
    ", 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("
    ");
    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, "
    	\tree");
    230     tree_print(root, fd);
    231     fprintf(fd, "
    
    ");
    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

     #返回上一级

  • 相关阅读:
    HelperProvider提供控件的弹出或联机帮助
    弹出层之3:JQuery.tipswindow
    使用重绘项美化WinForm中的控件
    BackgroundWorker在单独的线程上执行操作
    NHibernate学习笔记之一,Hello world!
    FileSystemWatcher 监视指定目录中的变更
    JQuery扩展插件Validate—6radio、checkbox、select的验证
    弹出层之1:JQuery.Boxy (一)
    大文件复制时块的取值问题
    JQuery扩展插件Validate—4设置错误提示的样式
  • 原文地址:https://www.cnblogs.com/zhanghaiba/p/3532885.html
Copyright © 2020-2023  润新知