zoukankan      html  css  js  c++  java
  • 《算法导论》CLRS算法C++实现(十)P151 二叉查找树

    第十二章 二叉查找树

    前几章比较简单,都是数据结构里的简单内容,以前也都写过,这次就不浪费时间在这些上面了。直接写二叉查找树、红黑树。

    在二叉查找树上执行的基本操作的时间与树的高度成正比。对一棵含n个结点的完全二叉树,这些操作的最坏情况运行时间为O(lgn)。但是如果二叉查找树是含n个结点的线性链,则这些操作的最坏情况运行时间为O(n)。

    二叉查找树的基本操作有:遍历,查找,求最大值,求最小值,求直接前驱,求直接后继,插入,删除等。

    1、遍历

    根据二叉查找树的性质,可以用一个递归算法按排列顺序输出树中的所有关键字。这种算法称为中序遍历算法。因为对任一子树根的关键字在输出时介于左子树和右子树的关键字之间。

    INORDER-TREE-WALK(x)

    1 if x ≠ NIL
    2     then INORDER-TREE-WALK(left[x])
    3     print key[x]
    4     INORDER-TREE-WALK(right[x])

     2、查找(搜索)

    给定指向树根的指针和关键字k,算法返回指向包含关键字k的结点的指针,如果不存在,返回NIL。算法过程从树的根结点开始进行查找,并沿着树下降,对碰到的每个结点x,就比较k和key[x],如果相同,则搜索结束,如果k小于key[x],则继续查找x的左子树,如果k大于key[x],则继续在x的右子树中查找。算法如下:

    ITERATIVE-TREE-SEARCH(x, k)

    1 while x ≠ NIL and k ≠ key[x]
    2     do if k < key[x]
    3         then x ← left[x]
    4     else x ← right[x]
    5 return x

    3、最大值、最小值

    要查找二叉树中具有最小关键字的元素,只要从根结点开始,沿着各结点的left指针查找下去,直到遇到NIL为止,如下图从15->6->3->2。类似地,要查找二叉树中具有最大关键字的元素,只要从根结点开始,沿着各结点的right指针查找下去即可,如下图15->18->20。

    算法如下:

    TREE-MINIMUM (x)

    1 while left[x] ≠ NIL
    2     do x ← left[x]
    3 return x

    4、前驱和后继

    给定一个二叉查找树中的结点,有时候要求找出在中序遍历下它的前驱或后继。其实前驱就是查找其左子树的最大值,而后继就是查找其右子树的最小值。算法如下:

    TREE-SUCCESSOR(x)

    1 if right[x] ≠ NIL
    2     then return TREE-MINIMUM (right[x])
    3 y ← p[x]
    4 while y ≠ NIL and x = right[y]
    5     do x ← y
    6     y ← p[y]
    7 return y

    对一棵高度为h的二叉查找树,动态集合操作search,minimum,maximum,successor,predecessor等的运行时间均为O(h)。

    5、插入和删除

    插入操作较为简单,从根结点开始,并沿树下降。指根据待插入结点和当前结点的比较结果,可以决定向左转或者向右转。直到x成为NIL时为止。如下图:在二叉查找树中插入结点13。

     

    TREE-INSERT(T, z) 

     1 y ← NIL
     2 x ← root[T]
     3 while x ≠ NIL
     4     do y ←  x
     5     if key[z] < key[x]
     6         then x ← left[x]
     7     else x ← right[x]
     8 p[z] ← y
     9 if y = NIL
    10     then root[T] ← z
    11 else if key[z] < key[y]
    12     then left[y] ← z
    13 else right[y] ← z

    在二叉查找树中删除结点的情况较为复杂,需要分三种情况考虑

    (1)该结点没有子女,直接删除即可。

    (2)只有一个左孩子或者右孩子,则将唯一的孩子接到将删除结点原来的位置上,再删除结点即可。

    (3)有两个子女,则将其直接后继替换到将删除结点原来的位置上,再将其直接后继删除即可。

    以上三种情况分别如下图(a)(b)(c)所示。

    TREE-DELETE(T, z)

     1 if left[z] = NIL or right[z] = NIL
     2     then y ← z
     3 else y ← TREE-SUCCESSOR(z)
     4 if left[y] ≠ NIL
     5     then x ← left[y]
     6 else x ← right[y]
     7 if x ≠ NIL
     8     then p[x] ← p[y]
     9 if p[y] = NIL
    10     then root[T] ← x
    11 else if y = left[p[y]]
    12     then left[p[y]] ← x
    13 else right[p[y]] ← x
    14 if y ≠ z
    15     then key[z] ← key[y]
    16     copy y's satellite data into z
    17 return y

     对高度为h的二叉查找树,动态集合操作insert和delete的运行时间为O(h)。

     C++源码: 

      1 #include <iostream>
      2 
      3 using namespace std;
      4 
      5 class BinarySearchTree;
      6 class BinaryNode
      7 {
      8     public:
      9         int element;
     10         BinaryNode* leftChild;
     11         BinaryNode* rightChild;
     12         BinaryNode(int value, BinaryNode* lChild, BinaryNode* rChild):element(value), leftChild(lChild), rightChild(rChild){};
     13         friend class BinarySearchTree;
     14 };
     15 
     16 class BinarySearchTree
     17 {
     18     public:
     19         BinaryNode* root;
     20         BinarySearchTree(BinaryNode* t){root = t;}
     21         void walk(BinaryNode * & t)const;
     22         BinaryNode* find(int x, BinaryNode* t)const;
     23         BinaryNode* findMax(BinaryNode* t)const;
     24         BinaryNode* findMin(BinaryNode* t)const;
     25         BinaryNode* predecessor(BinaryNode * & t)const;
     26         BinaryNode* successor(BinaryNode * & t)const;
     27         void insert(int x, BinaryNode * & t);
     28         void remove(int x, BinaryNode * & t);
     29 };
     30 
     31 void BinarySearchTree::walk(BinaryNode * & t) const
     32 {
     33     if(t != NULL)
     34     {
     35         walk(t->leftChild);
     36         cout << t->element << " ";
     37         walk(t->rightChild);
     38     }
     39 }
     40 
     41 BinaryNode* BinarySearchTree::find(int x, BinaryNode* t) const
     42 {
     43     while(t != NULL)
     44     {
     45         if(x < t->element)
     46             t = t->leftChild;
     47         else if(x > t->element)
     48             t = t->rightChild;
     49         else
     50             return t;
     51     }
     52     return NULL;
     53 }
     54 
     55 BinaryNode* BinarySearchTree::findMax(BinaryNode* t) const
     56 {
     57     if(t != NULL)
     58     {
     59         while(t->rightChild != NULL)
     60         {
     61             t = t->rightChild;
     62         }
     63     }
     64     return t;
     65 }
     66 
     67 BinaryNode* BinarySearchTree::findMin(BinaryNode* t) const
     68 {
     69     if(t != NULL)
     70     {
     71         while(t->leftChild != NULL)
     72         {
     73             t = t->leftChild;
     74         }
     75     }
     76     return t;
     77 }
     78 
     79 BinaryNode* BinarySearchTree::predecessor(BinaryNode * & t) const
     80 {
     81     if(t != NULL)
     82     {
     83         if(t->leftChild != NULL)
     84         {
     85             return findMax(t->leftChild);
     86         }
     87         return NULL;
     88     }
     89     return NULL;
     90 }
     91 
     92 BinaryNode* BinarySearchTree::successor(BinaryNode * & t) const
     93 {
     94     if(t != NULL)
     95     {
     96         if(t->rightChild != NULL)
     97         {
     98             return findMin(t->rightChild);
     99         }
    100         return NULL;
    101     }
    102     return NULL;
    103 }
    104 
    105 void BinarySearchTree::insert(int x, BinaryNode * & t)
    106 {
    107     if(t == NULL)
    108         t = new BinaryNode(x, NULL, NULL);
    109     else if(x < t->element)
    110         insert(x, t->leftChild);
    111     else if(x > t->element)
    112         insert(x, t->rightChild);
    113     else
    114     {
    115         cerr << "Duplicate Element!" << endl;
    116     }
    117 }
    118 
    119 void BinarySearchTree::remove(int x, BinaryNode * & t)
    120 {
    121     if(t == NULL)
    122          cerr << "Not exist!" << endl;
    123     if(x < t->element)
    124         remove(x, t->leftChild);
    125     else if(x > t->element)
    126         remove(x, t->rightChild);
    127     else if((t->leftChild != NULL) && (t->rightChild != NULL))
    128     {
    129         t->element = findMin(t->rightChild)->element;
    130         remove(t->element, t->rightChild);
    131     }
    132     else
    133     {
    134         BinaryNode* temp = t;
    135         t = (t->leftChild != NULL) ? t->leftChild : t->rightChild;
    136         delete temp;
    137     }
    138 }
  • 相关阅读:
    数组 A
    考试中。。。
    高精度加法
    1319:【例6.1】排队接水
    Docker基于容器创建镜像
    Docker上传/拉取阿里云镜像
    Docker配置阿里镜像加速器
    CentOS7安装、卸载Docker
    Python3+requests+unittest+log+excel+HTMLTestRunner+email框架接口自动化案例⑼——执行用例及GitHub源码地址
    Python3+requests+unittest+log+excel+HTMLTestRunner+email框架接口自动化案例⑻——测试用例
  • 原文地址:https://www.cnblogs.com/juventus/p/2544165.html
Copyright © 2011-2022 走看看