第十二章 二叉查找树
前几章比较简单,都是数据结构里的简单内容,以前也都写过,这次就不浪费时间在这些上面了。直接写二叉查找树、红黑树。
在二叉查找树上执行的基本操作的时间与树的高度成正比。对一棵含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 }