红黑树浅浅学习
红黑树概念
- 二叉树:二叉树是每个节点最多有两个子树的树结构。
- 二叉查找树:又称“二叉搜索树”,左孩子比父节点小,右孩子比父节点大,还有一个特性就是”中序遍历“可以让结点有序。
- 平衡二叉树:它是一颗空树或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
- 红黑树是一种自平衡的二叉查找树,它属于平衡树,但是却没有平衡二叉树那么“平衡”。可以保证在最坏情况下基本动态操作的时间复杂度为O(log n)。
- 红黑树中的每个节点都有一个颜色属性,可以是红色或黑色。
红黑树满足以下5个性质:
- 每个节点要么是红色的,要么是黑色的,根节点是黑色的。
- 每个叶子节点(NIL节点,空节点)是黑色的。
- 任何相邻节点不能同时为红色。
- 任何叶子节点,到根节点,所经过的黑节点数目相同。
- 当前节点到其所有叶节点包含的黑色节点数量相同。
通过这些性质,红黑树可以保证在插入和删除节点时,自动调整树的结构,以保持树的平衡和性质的满足。相比于普通的二叉查找树,红黑树的平衡性更好,查找、插入和删除都具有更稳定的时间复杂度,因此在很多场景下被广泛应用。
红黑树平衡性调整
- 依次插入 100 90 120,不需要进行平衡性调整
- 插入85,把90和120变成黑色,100变成红色。但100必须为黑色,100也变成黑色
平衡性调整情况1:爷节点为黑色,父节点为红色,且有叔节点为红色,父亲节点为爷节点的左孩子
- 将父节点和叔节点都变为黑色。
- 爷节点变成红色
- 若爷节点变色之后红黑树性质出现问题,需要沿着爷节点继续向上调整
- 若爷节点为根节点,要变黑色。
- 插入60为红色,红黑树继续进行调整,85变成黑色,90变成红色。
平衡性调整情况2:爷节点为黑色,父节点为红色,没有叔节点或叔节点为黑色,父亲节点为爷节点的左孩子,插入的节点是父节点的左孩子
平衡性调整情况3:爷节点为黑色,父节点为红色,没有叔节点或叔节点为黑色,父亲节点为爷节点的右孩子,插入的节点是父节点的左孩子
平衡性调整情况4-6分别为1-3的反情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
| #include <iostream> #include <list> #include <vector> #include <string> #include <map> #include <set> #include <assert.h> #include <sstream> #include <stack>
using namespace std;
template<typename T> struct RBNode{ T data; RBNode* leftChild; RBNode* rightChild; RBNode* parentNd;
bool isRed; };
template<typename T> class RBTree{ public: RBTree():root(nullptr){}
~RBTree(){ ReleaseNode(root); }
void InsertElem(const T&e){ InsertElem(root,e); }
void InsertElem(RBNode<T>*& tNode, const T& e){ RBNode<T>* point = tNode; RBNode<T>* parent = nullptr;
while(point !=nullptr){ if(e==point->data) return; parent = point;
if(e > point->data){ point = point->rightChild; } else{ point = point->leftChild; } }
point = new RBNode<T>; point->data = e; point->leftChild = nullptr; point->rightChild = nullptr; point->parentNd = nullptr; point->isRed = true;
if(parent == nullptr){ point->isRed = false; tNode = point; return; }
if(e > parent->data){ parent->rightChild = point; }else{ parent->leftChild = point; }
point->parentNd = parent; if(parent->isRed == false) return;
BalanceTune(point,parent); root->isRed = false;
}
private:
RBNode<T>* getBrotherNode(RBNode<T>* p){ if(p->parentNd->leftChild == p){ return p->parentNd->rightChild; } return p->parentNd->leftChild; }
void BalanceTune(RBNode<T>* point, RBNode<T>* parent){
RBNode<T>* parentBroNode = nullptr; RBNode<T>* grandFatherNode = nullptr; while(true){ parentBroNode = (parent->parentNd !=nullptr) ? (getBrotherNode(parent)):nullptr; grandFatherNode = point->parentNd->parentNd;
if(grandFatherNode == nullptr) break;
if(parentBroNode != nullptr && parentBroNode->isRed == true){
parent->isRed = false; parentBroNode->isRed = false; grandFatherNode->isRed = true;
if(grandFatherNode == root) break;
point = grandFatherNode; parent = point->parentNd; if(parent->isRed = false) break;
continue; }
RBNode<T>* gff = grandFatherNode->parentNd; int sign = 0; if(gff!=nullptr){ if(gff->leftChild == grandFatherNode){ sign = 1; } else{ sign = 2; } } if(grandFatherNode->leftChild == parent){ if(parent->leftChild == point){ RotateRight(grandFatherNode); }else{ RotateLeftRight(grandFatherNode); }
grandFatherNode->isRed = false; grandFatherNode->rightChild->isRed = true; }else{ if(parent->rightChild == point){ RotateLeft(grandFatherNode); }else{ RotateRightLeft(grandFatherNode); } grandFatherNode->isRed = false; grandFatherNode->leftChild->isRed = true; }
if(gff == nullptr){ root = grandFatherNode; }else if(sign == 1){ gff->leftChild = grandFatherNode; }else if(sign == 2){ gff->rightChild = grandFatherNode; } break;
} return; }
void RotateRight(RBNode<T>*& pointer){ RBNode<T>* ptmproot = pointer; pointer = ptmproot->leftChild; pointer->parentNd = ptmproot->parentNd;
ptmproot->leftChild = pointer->rightChild; if(pointer->rightChild){ pointer->rightChild->parentNd =ptmproot; } pointer->rightChild = ptmproot; ptmproot->parentNd = pointer;
}
void ReleaseNode(RBNode<T>* pnode){ if(pnode !=nullptr){ ReleaseNode(pnode->leftChild); ReleaseNode(pnode->rightChild); } delete pnode; }
private: RBNode<T>* root; };
int main() { RBTree<int> myrbtr; int array[] = {80,50,120,30,60,20,40}; int acount = sizeof(array)/sizeof(int); for(int i=0;i<acount;i++){ myrbtr.InsertElem(array[i]); } return 0; }
|