zoukankan      html  css  js  c++  java
  • 查找:二叉查找树 c++ 2020年8月

    一、实现思想

      1、二叉查找树,实际上是根据『左小右大』的规则去生成一颗二叉树。

      2、这就有点类似折半查找,可以瞬间排除一大部分数据,专注于树的一边。

      3、最有趣的是,『左小右大』生成的树,中序遍历后得到的数据居然是有序的(这个和查找没有什么关系,但是真的很妙)

    补充:

      1、我觉得构建一棵树并不难,最难的是对这棵树进行删除操作,因为需要调整树的结构,所以第二部分图列会专注于删除。

      2、为了便于实现删除操作,我为节点增加了指向父节点的指针。

    1 typedef struct NODE
    2 {
    3     int data;
    4     NODE *left;
    5     NODE *right;
    6     NODE *parent;
    7 } Node, *pNode;

    二、实现图例

    1、构建一棵树

     

    2、删除一个节点

      删除的节点可以分为两种情况

      1、可以直接删除的节点     (左右子树不同时存在,或者左右子树为空)

      2、需要替换删除的节点    (左右子树同时存在)

    补充:替换删除的时候,如何知道被删除节点需要被哪一个节点替换?

      其实只要挑一个节点,让树的结构保持满足『左小右大』就行,可以是 删除节点左子树里面的最大值,也可以是删除节点右子树里面的最大值(这里的代码实现使用了后者)

     

    三、实现代码

      1、类的构成

     1 class BiSortTree
     2 {
     3 public:
     4     BiSortTree();
     5     BiSortTree(int a[], int len);
     6     ~BiSortTree();
     7 
     8     pNode InsertBST(pNode root, int data);
     9     //这个安排也是秒得很,既可以实现无参打印整棵树,也有有参的可以选择
    10     void middle_print() { middle_print(root); }
    11     pNode SerchBST(int des) { return SerchBST(root, des); }
    12     int DeleteBST(int des);
    13 
    14 private:
    15     //可以指定根节点进行中序遍历
    16     void middle_print(pNode root); //这个重载的设为private,不想被别人用
    17     pNode SerchBST(pNode root, int des);
    18     pNode DeleteBST(pNode p, pNode &root);
    19     pNode successor(pNode root);
    20     pNode root;
    21 };

      

      2、插入

     1 BiSortTree::BiSortTree(int a[], int len)
     2 {
     3     root = NULL;
     4     for (int i = 0; i < len; i++)
     5         root = InsertBST(root, a[i]);
     6     root->parent = NULL;
     7 }
     8 BiSortTree::~BiSortTree() {}
     9 
    10 //插入算法,并且返回新增节点的指针
    11 pNode BiSortTree::InsertBST(pNode root, int data)
    12 {
    13 
    14     if (root == NULL)
    15     {
    16         pNode tmp = new Node;
    17         tmp->data = data;
    18         tmp->left = NULL;
    19         tmp->right = NULL;
    20         tmp->parent = NULL;
    21         root = tmp;
    22         return root;
    23     }
    24 
    25     else if (data <= root->data)
    26     {
    27         root->left = InsertBST(root->left, data); //返回一个节点指针,实际上完成了叶节点的拓展
    28         root->left->parent = root;
    29     }
    30     else
    31     {
    32         root->right = InsertBST(root->right, data);
    33         root->right->parent = root;
    34     }
    35     return root; //做一个好的收尾
    36 }

      3、中序遍历

     1 //中序遍历算法,要求输入一个根节点 pNode root
     2 void BiSortTree::middle_print(pNode root)
     3 {
     4     if (root == NULL)
     5         return;
     6     else
     7     {
     8         middle_print(root->left);   //前序递归遍历root左子树
     9         printf("%d  ", root->data); //访问root的data
    10         if (root->parent != NULL)
    11             printf("    parent : %d
    ", root->parent->data);
    12         else
    13             printf("    根节点
    ");
    14         middle_print(root->right); //
    15     }
    16 }

      

      3、查找

     1 //查找算法,妙处就在于『递归』,太强大了
     2 pNode BiSortTree::SerchBST(pNode root, int des)
     3 {
     4     // if (root == NULL)
     5     //     return NULL;
     6     // else if (root->data == des)
     7     //     return root;
     8 
     9     if (root == NULL || root->data == des)
    10         return root; //原来上面两句代码还可以1简洁到合在一起。厉害厉害。
    11     else if (des <= root->data)
    12         return SerchBST(root->left, des);
    13     else
    14         return SerchBST(root->right, des);
    15 }

      

      4、删除

     1 //查找右子树的最小节点,返回最小节点的指针
     2 pNode BiSortTree::successor(pNode root)
     3 {
     4     pNode p = root, s = root->right;
     5     if (s->left == NULL)
     6         return s;
     7     while (s->left != NULL)
     8     {
     9         p = s;
    10         s = s->left;
    11     }
    12     return s;
    13 }
    14 
    15 int BiSortTree::DeleteBST(int des)
    16 {
    17     pNode p = NULL;   //记录查找到的要被删除的节点
    18     pNode del = NULL; //记录真正要被删除的节点      (注意这两个不一定一样的哦)
    19     int result;
    20     if ((p = SerchBST(des)) != NULL)
    21     {
    22         result = p->data;
    23         if ((del = DeleteBST(p, root)) != NULL)
    24             delete del;
    25     }
    26 
    27     return result;
    28 }
    29 
    30 pNode BiSortTree::DeleteBST(pNode p, pNode &root)
    31 {
    32     //补充一下,这里传一个引用很重要,因为有可能根节点的指向需要改变
    33 
    34     pNode y = NULL; //y用来指向代替p的节点
    35     pNode x = NULL; //x用来指向y,以后的节点
    36 
    37     if ((p->left == NULL) || (p->right == NULL))
    38     {
    39         y = p;
    40         printf("可以直接删除 %d
    ", y->data);
    41     }
    42     else
    43     {
    44         y = successor(p);
    45         printf("代替 %d 的将会是:%d
    ", p->data, y->data);
    46     }
    47 
    48     //确认x
    49     if (y->left != NULL)
    50         x = y->left;
    51     else
    52         x = y->right;
    53 
    54     if (x != NULL)
    55         x->parent = y->parent; //将x回归大部队,因为下一步要把y分离出去了
    56 
    57     //把y分离出去
    58     if (y->parent == NULL) //这样一个特殊情况(直接删除根节点)也考虑了,真的是太周到了
    59         root = x;
    60     else if (y == y->parent->left)
    61         y->parent->left = x;
    62     else
    63         y->parent->right = x;
    64 
    65     //删除p,实际上只是删除了p的data,拿y作p的替代
    66     if (y != p)
    67         p->data = y->data;
    68 
    69     return y;
    70 }

      5、main测试

     1 int main(void)
     2 {
     3     int a[] = {5, 1, 3, 7, 6, 2, 9, 8, 4};
     4     int len = 9;
     5     int val = 7;
     6     BiSortTree bt(a, len);
     7     bt.middle_print();
     8 
     9     for (int i = 1; i <= 9; i++)
    10     {
    11         if (bt.SerchBST(i))
    12             printf("查找成功 %d
    ", bt.SerchBST(i)->data);
    13 
    14         else
    15             printf("查找失败 %d
    ", i);
    16     }
    17 
    18     for (int i = 1; i <= 9; i++)
    19     {
    20         printf("删除了  %d
    ", bt.DeleteBST(i));
    21     }
    22 
    23     bt.middle_print();
    24     return 0;
    25 }

      6、输出

     1 /* 
     2 ——————————————————————————————————
     3 1      parent : 5
     4 2      parent : 3
     5 3      parent : 1
     6 4      parent : 3
     7 5      根节点    
     8 6      parent : 7
     9 7      parent : 5
    10 8      parent : 9
    11 9      parent : 7
    12 查找成功 1
    13 查找成功 2
    14 查找成功 3
    15 查找成功 4
    16 查找成功 5
    17 查找成功 6
    18 查找成功 7
    19 查找成功 8
    20 查找成功 9
    21 可以直接删除 1
    22 删除了  1
    23 可以直接删除 2
    24 删除了  2
    25 可以直接删除 3
    26 删除了  3
    27 可以直接删除 4
    28 删除了  4
    29 可以直接删除 5
    30 删除了  5
    31 可以直接删除 6
    32 删除了  6
    33 可以直接删除 7
    34 删除了  7
    35 可以直接删除 8
    36 删除了  8
    37 可以直接删除 9
    38 删除了  9
    39 ——————————————————————————————————
    40  */

      

      7、全部代码

      1 /*
      2  created by coderon
      3     26 August 2020
      4 */
      5 #include <stdio.h>
      6 
      7 typedef struct NODE
      8 {
      9     int data;
     10     NODE *left;
     11     NODE *right;
     12     NODE *parent;
     13 } Node, *pNode;
     14 
     15 class BiSortTree
     16 {
     17 public:
     18     BiSortTree();
     19     BiSortTree(int a[], int len);
     20     ~BiSortTree();
     21 
     22     pNode InsertBST(pNode root, int data);
     23     //这个安排也是秒得很,既可以实现无参打印整棵树,也有有参的可以选择
     24     void middle_print() { middle_print(root); }
     25     pNode SerchBST(int des) { return SerchBST(root, des); }
     26     int DeleteBST(int des);
     27 
     28 private:
     29     //可以指定根节点进行中序遍历
     30     void middle_print(pNode root); //这个重载的设为private,不想被别人用
     31     pNode SerchBST(pNode root, int des);
     32     pNode DeleteBST(pNode p, pNode &root);
     33     pNode successor(pNode root);
     34     pNode root;
     35 };
     36 
     37 BiSortTree::BiSortTree(int a[], int len)
     38 {
     39     root = NULL;
     40     for (int i = 0; i < len; i++)
     41         root = InsertBST(root, a[i]);
     42     root->parent = NULL;
     43 }
     44 BiSortTree::~BiSortTree() {}
     45 
     46 //插入算法,并且返回新增节点的指针
     47 pNode BiSortTree::InsertBST(pNode root, int data)
     48 {
     49 
     50     if (root == NULL)
     51     {
     52         pNode tmp = new Node;
     53         tmp->data = data;
     54         tmp->left = NULL;
     55         tmp->right = NULL;
     56         tmp->parent = NULL;
     57         root = tmp;
     58         return root;
     59     }
     60 
     61     else if (data <= root->data)
     62     {
     63         root->left = InsertBST(root->left, data); //返回一个节点指针,实际上完成了叶节点的拓展
     64         root->left->parent = root;
     65     }
     66     else
     67     {
     68         root->right = InsertBST(root->right, data);
     69         root->right->parent = root;
     70     }
     71     return root; //做一个好的收尾
     72 }
     73 
     74 //中序遍历算法,要求输入一个根节点 pNode root
     75 void BiSortTree::middle_print(pNode root)
     76 {
     77     if (root == NULL)
     78         return;
     79     else
     80     {
     81         middle_print(root->left);   //前序递归遍历root左子树
     82         printf("%d  ", root->data); //访问root的data
     83         if (root->parent != NULL)
     84             printf("    parent : %d
    ", root->parent->data);
     85         else
     86             printf("    根节点
    ");
     87         middle_print(root->right); //
     88     }
     89 }
     90 
     91 //查找算法,妙处就在于『递归』,太强大了
     92 pNode BiSortTree::SerchBST(pNode root, int des)
     93 {
     94     // if (root == NULL)
     95     //     return NULL;
     96     // else if (root->data == des)
     97     //     return root;
     98 
     99     if (root == NULL || root->data == des)
    100         return root; //原来上面两句代码还可以1简洁到合在一起。厉害厉害。
    101     else if (des <= root->data)
    102         return SerchBST(root->left, des);
    103     else
    104         return SerchBST(root->right, des);
    105 }
    106 
    107 //查找右子树的最小节点,返回最小节点的指针
    108 pNode BiSortTree::successor(pNode root)
    109 {
    110     pNode p = root, s = root->right;
    111     if (s->left == NULL)
    112         return s;
    113     while (s->left != NULL)
    114     {
    115         p = s;
    116         s = s->left;
    117     }
    118     return s;
    119 }
    120 
    121 int BiSortTree::DeleteBST(int des)
    122 {
    123     pNode p = NULL;   //记录查找到的要被删除的节点
    124     pNode del = NULL; //记录真正要被删除的节点      (注意这两个不一定一样的哦)
    125     int result;
    126     if ((p = SerchBST(des)) != NULL)
    127     {
    128         result = p->data;
    129         if ((del = DeleteBST(p, root)) != NULL)
    130             delete del;
    131     }
    132 
    133     return result;
    134 }
    135 
    136 pNode BiSortTree::DeleteBST(pNode p, pNode &root)
    137 {
    138     //补充一下,这里传一个引用很重要,因为有可能根节点的指向需要改变
    139 
    140     pNode y = NULL; //y用来指向代替p的节点
    141     pNode x = NULL; //x用来指向y,以后的节点
    142 
    143     if ((p->left == NULL) || (p->right == NULL))
    144     {
    145         y = p;
    146         printf("可以直接删除 %d
    ", y->data);
    147     }
    148     else
    149     {
    150         y = successor(p);
    151         printf("代替 %d 的将会是:%d
    ", p->data, y->data);
    152     }
    153 
    154     //确认x
    155     if (y->left != NULL)
    156         x = y->left;
    157     else
    158         x = y->right;
    159 
    160     if (x != NULL)
    161         x->parent = y->parent; //将x回归大部队,因为下一步要把y分离出去了
    162 
    163     //把y分离出去
    164     if (y->parent == NULL) //这样一个特殊情况(直接删除根节点)也考虑了,真的是太周到了
    165         root = x;
    166     else if (y == y->parent->left)
    167         y->parent->left = x;
    168     else
    169         y->parent->right = x;
    170 
    171     //删除p,实际上只是删除了p的data,拿y作p的替代
    172     if (y != p)
    173         p->data = y->data;
    174 
    175     return y;
    176 }
    177 
    178 int main(void)
    179 {
    180     int a[] = {5, 1, 3, 7, 6, 2, 9, 8, 4};
    181     int len = 9;
    182     int val = 7;
    183     BiSortTree bt(a, len);
    184     bt.middle_print();
    185 
    186     for (int i = 1; i <= 9; i++)
    187     {
    188         if (bt.SerchBST(i))
    189             printf("查找成功 %d
    ", bt.SerchBST(i)->data);
    190 
    191         else
    192             printf("查找失败 %d
    ", i);
    193     }
    194 
    195     for (int i = 1; i <= 9; i++)
    196     {
    197         printf("删除了  %d
    ", bt.DeleteBST(i));
    198     }
    199 
    200     bt.middle_print();
    201     return 0;
    202 }
    203 /* 
    204 ——————————————————————————————————
    205 1      parent : 5
    206 2      parent : 3
    207 3      parent : 1
    208 4      parent : 3
    209 5      根节点    
    210 6      parent : 7
    211 7      parent : 5
    212 8      parent : 9
    213 9      parent : 7
    214 查找成功 1
    215 查找成功 2
    216 查找成功 3
    217 查找成功 4
    218 查找成功 5
    219 查找成功 6
    220 查找成功 7
    221 查找成功 8
    222 查找成功 9
    223 可以直接删除 1
    224 删除了  1
    225 可以直接删除 2
    226 删除了  2
    227 可以直接删除 3
    228 删除了  3
    229 可以直接删除 4
    230 删除了  4
    231 可以直接删除 5
    232 删除了  5
    233 可以直接删除 6
    234 删除了  6
    235 可以直接删除 7
    236 删除了  7
    237 可以直接删除 8
    238 删除了  8
    239 可以直接删除 9
    240 删除了  9
    241 ——————————————————————————————————
    242  */
    全部代码

    总结:

      程序不可能一下子就无懈可击,总是有想得不周到的地方,这时候需要的是冷静有逻辑的判断,有时候机械地一句一句地执行也会发现许多意想不到的收获。

  • 相关阅读:
    极致平台开发技巧介绍1如何利用升级包,快速给客户升级
    如何用极致业务基础平台做一个通用企业ERP系列之三启用期间管理设计
    caca需要用到x11作为图形输出
    spring boot 使用 mybatis 开启事务回滚 的总结
    RabbitMQ --- 直连交换机 【 同步操作,等到消费者处理完后返回处理结果 】
    RabbitMQ --- 直连交换机 【 有回调方法,获取消费结果 】
    RabbitMQ --- 直连交换机 【 无回调方法,不能获取消费结果 】
    spring boot 启动警告 WARN 15684 --- [ restartedMain] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources. 解决
    Java基础复习到此结束,统一把源码放到GitHub仓库了,响应开源精神
    用一道题 来 复习 MySQL 的 复杂 sql 语句
  • 原文地址:https://www.cnblogs.com/coderon/p/13562844.html
Copyright © 2011-2022 走看看