《算法导论》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。

《算法导论》CLRS算法C++实现(十)P151 二叉查找树_第1张图片

算法如下:

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。

《算法导论》CLRS算法C++实现(十)P151 二叉查找树_第2张图片

 

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)所示。

《算法导论》CLRS算法C++实现(十)P151 二叉查找树_第3张图片

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 }

 

你可能感兴趣的:(二叉查找树)