二叉查找树、红黑树 判断二叉查找树 算法思想 遍历二叉树的所有元素,如果所有的节点,有左子树且左子树小于该节点,有右子树且右子树大于该节点,那么这就是一个二叉查找树。
时间复杂度:
遍历树的所有节点,时间复杂度$O(n)$
空间复杂度:
空间复杂度取决于递归调用深度,也就是树高,空间复杂度$O(h)$
代码 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 #include <iostream> #include <vector> using namespace std;class BiTree { public : int v; BiTree* left; BiTree* right; BiTree (int v) { this ->v = v; left = nullptr ; right = nullptr ; } }; void preorderPrintTree (BiTree* root) { if (root == nullptr ) return ; cout << root->v << " " ; preorderPrintTree (root->left); preorderPrintTree (root->right); } void inorderPrintTree (BiTree* root) { if (root == nullptr ) return ; inorderPrintTree (root->left); cout << root->v << " " ; inorderPrintTree (root->right); } bool checkBST (BiTree* root) { if (root == nullptr ) return true ; if (root->left != nullptr && root->left->v > root->v) return false ; if (root->right != nullptr && root->right->v < root->v) return false ; return checkBST (root->left) && checkBST (root->right); } void buildTree (BiTree* root, vector<int > preorder, vector<int > inorder) { if (preorder.size () == 0 ) return ; root->v = preorder[0 ]; int i = 0 ; for (; i < inorder.size (); i++) { if (inorder[i] == preorder[0 ]) break ; } vector<int > leftPreorder (preorder.begin() + 1 , preorder.begin() + i + 1 ) ; vector<int > leftInorder (inorder.begin(), inorder.begin() + i) ; vector<int > rightPreorder (preorder.begin() + i + 1 , preorder.end()) ; vector<int > rightInorder (inorder.begin() + i + 1 , inorder.end()) ; if (leftPreorder.size () != 0 ) { root->left = new BiTree (0 ); buildTree (root->left, leftPreorder, leftInorder); } if (rightPreorder.size () != 0 ) { root->right = new BiTree (0 ); buildTree (root->right, rightPreorder, rightInorder); } } int main () { vector<int > preorder = { 5 ,1 ,4 ,3 ,6 }; vector<int > inorder = { 1 ,5 ,3 ,4 ,6 }; BiTree* root = new BiTree (0 ); buildTree (root, preorder, inorder); cout << "构造树的前序序列:" << endl; for (int i = 0 ; i < preorder.size (); i++) { cout << preorder[i] << " " ; } cout << endl; cout << "构造树的中序序列:" << endl; for (int i = 0 ; i < inorder.size (); i++) { cout << inorder[i] << " " ; } cout << endl; cout << "树构造完成后的前序序列:" << endl; preorderPrintTree (root); cout << endl; cout << "树构造完成后的中序序列:" << endl; inorderPrintTree (root); cout << endl; cout << "是否为二叉搜索树:" ; checkBST (root) ? cout << "true" : cout << "false" ; }
运行结果及分析
根据前序中序,可以判断树为
遍历5 左子树1<5 右子树4<5 所以不是二叉查找树
红黑树插入、删除 算法思想 插入:
首先,插入新节点,按照普通的二叉搜索树的规则将其放入适当的位置。从根节点出发,小于该节点进左子树,大于该节点进右子树,若某子树为空,则放置。
新节点的颜色标记为红色。
插入后,需要检查红黑树的性质是否被破坏,主要是以下性质: a. 根节点是黑色的。 b. 每个叶子节点(NIL 节点)都是黑色的。 c. 如果一个节点是红色的,则它的子节点都是黑色的(没有两个相邻的红色节点)。 d. 从任一节点到其子树中每个叶子节点的路径都包含相同数目的黑色节点(黑高度相同)。
如果新插入的节点的父节点是黑色的,不会破坏性质。所以插入后,树仍然是一棵合法的红黑树。
如果新插入的节点的父节点是红色的,这可能违反了性质 c。为了修复这个问题,需要通过一系列旋转和颜色调整来恢复红黑树的性质。
a. 如果父节点的兄弟节点是红色的,执行以下操作:
将父节点标记为黑色。
将父节点的兄弟节点标记为黑色。
将祖父节点标记为红色。
将当前节点指向祖父节点。
重复步骤 3 以确保其他性质仍然得到满足。
b. 如果父节点的兄弟节点是黑色或NIL,且当前节点是其父节点的右子节点,执行以下操作:
如果当前节点是左子节点,先以父节点为支点进行右旋转,然后将父节点和当前节点互换颜色。
以祖父节点为支点进行左旋转,将父节点标记为黑色,祖父节点标记为红色。
c. 如果父节点的兄弟节点是黑色或NIL,且当前节点是其父节点的左子节点,执行以下操作:
以祖父节点为支点进行右旋转,将父节点标记为黑色,祖父节点标记为红色。
最后,确保根节点始终是黑色的,以满足性质 a。
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 RB-Insert (T, z): Binary-Search-Tree-Insert (T, z) z.color = RED RB-Insert-Fixup (T, z) RB-Insert-Fixup (T, z): while z.parent.color == RED: if z.parent == z.parent.parent.left: y = z.parent.parent.right if y.color == RED: z.parent.color = BLACK y.color = BLACK z.parent.parent.color = RED z = z.parent.parent else : if z == z.parent.right: z = z.parent Left-Rotate (T, z) z.parent.color = BLACK z.parent.parent.color = RED Right-Rotate (T, z.parent.parent) else : T.root.color = BLACK Left-Rotate (T, x): Right-Rotate (T, x):
删除:
首先,按照二叉搜索树的规则找到要删除的节点,然后执行删除操作。如果节点有两个子节点,可以采用以下方法: a. 找到要删除节点的中序遍历前驱或后继节点(通常是左子树的最大节点或右子树的最小节点)。 b. 用前驱或后继节点的值替代要删除节点的值。 c. 然后将删除操作重定向到前驱或后继节点,删除前驱或后继节点。
如果删除的节点是红色的,不会破坏红黑树性质,删除操作结束。树仍然是一棵合法的红黑树。
如果删除的节点是黑色的,可能会破坏性质,需要执行额外的操作来修复。
如果删除的节点是黑色,且替代节点是红色,将替代节点改为黑色,然后删除操作结束。
如果删除的节点是黑色,且替代节点也是黑色,这会破坏红黑树性质 c。在这种情况下,需要执行以下步骤来修复树:
a. 记录删除节点的父节点和兄弟节点。
b. 删除节点。
c. 如果删除节点是其父节点的左子节点,兄弟节点就是父节点的右子节点,反之亦然。
d. 进行以下情况分类:
i. 兄弟节点是红色的:为了解决这个问题,执行以下步骤:
进行父节点的颜色翻转(父节点由黑变红,兄弟节点由红变黑)。
对父节点进行左旋转(以父节点为支点进行左旋转)。
现在兄弟节点变成了新的兄弟节点(原来的兄弟节点的左子节点),进一步处理情况。
ii. 兄弟节点是黑色,且兄弟节点的两个子节点都是黑色(NIL 节点):这时,可以将兄弟节点标记为红色,并将问题上移到父节点。
iii. 兄弟节点是黑色,且只有一个子节点是黑色:需要进行进一步的分类,取决于哪一侧的子节点是黑色。 - 如果兄弟节点的左子节点是黑色,右子节点是红色,执行以下步骤:
对兄弟节点进行颜色翻转(兄弟节点由黑变红,右子节点由红变黑)。
对兄弟节点进行右旋转。 - 现在兄弟节点的左子节点成为新的兄弟节点。
然后,进一步处理情况。
iv. 兄弟节点是黑色,且右子节点是黑色,左子节点是红色:执行以下步骤来解决这个情况:
对兄弟节点进行颜色翻转(兄弟节点由黑变红,左子节点由红变黑)。
对父节点进行左旋转。
现在树重新满足红黑树性质,删除操作结束。
删除操作可能需要向上逐层处理,确保整棵树都满足红黑树性质,包括黑高度相同等性质。
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 RB-Delete (T, z): y = z y_original_color = y.color if z.left == NIL: x = z.right Transplant (T, z, z.right) else if z.right == NIL: x = z.left Transplant (T, z, z.left) else : y = Tree-Minimum (z.right) y_original_color = y.color x = y.right if y.parent == z: x.parent = y else : Transplant (T, y, y.right) y.right = z.right y.right.parent = y Transplant (T, z, y) y.left = z.left y.left.parent = y y.color = z.color if y_original_color == BLACK: RB-Delete-Fixup (T, x) RB-Delete-Fixup (T, x): while x != T.root and x.color == BLACK: if x == x.parent.left: w = x.parent.right if w.color == RED: w.color = BLACK x.parent.color = RED Left-Rotate (T, x.parent) w = x.parent.right if w.left.color == BLACK and w.right.color == BLACK: w.color = RED x = x.parent else : if w.right.color == BLACK: w.left.color = BLACK w.color = RED Right-Rotate (T, w) w = x.parent.right w.color = x.parent.color x.parent.color = BLACK w.right.color = BLACK Left-Rotate (T, x.parent) x = T.root else : x.color = BLACK Transplant (T, u, v):
时间复杂度:
插入: 因为红黑树能够自平衡,保持树的高度接近对数级别,因此红黑树的插入操作的时间复杂度为 $O(log(n))$,其中 n 是树中节点的数量。
删除: 同插入,$O(log(n))$
空间复杂度:
插入: 递归深度为树高,$O(log(n))$
删除: 同插入,$O(log(n))$
代码 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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 #include <iostream> #include <vector> using namespace std;enum Color { RED, BLACK };class Node {public : Color color; int val; Node* left; Node* right; Node* parent; Node (int val) { this ->val = val; this ->color = RED; this ->left = nullptr ; this ->right = nullptr ; this ->parent = nullptr ; } }; class RedBlackTree {public : Node* root; Node* nil; RedBlackTree () { nil = new Node (-1 ); nil->color = BLACK; root = nil; nil->left = nil; nil->right = nil; } void RBinsert (int val) { Node* node = new Node (val); node->left = nil; node->right = nil; node->parent = nil; if (root == nil) { root = node; root->color = BLACK; root->parent = nil; return ; } Node* cur = root; Node* pre = nil; while (cur != nil) { pre = cur; if (cur->val > val) { cur = cur->left; } else { cur = cur->right; } } if (pre->val > val) { pre->left = node; } else { pre->right = node; } node->parent = pre; RBinsertFixUp (node); } void RBinsertFixUp (Node* node) { while (node->parent->color == RED) { if (node->parent == node->parent->parent->left) { Node* uncle = node->parent->parent->right; if (uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->right) { node = node->parent; leftRotate (node); } node->parent->color = BLACK; node->parent->parent->color = RED; rightRotate (node->parent->parent); } } else { Node* uncle = node->parent->parent->left; if (uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; rightRotate (node); } node->parent->color = BLACK; node->parent->parent->color = RED; leftRotate (node->parent->parent); } } } root->color = BLACK; } void leftRotate (Node* node) { Node* right = node->right; node->right = right->left; if (right->left != nil) { right->left->parent = node; } right->parent = node->parent; if (node->parent == nil) { root = right; } else if (node == node->parent->left) { node->parent->left = right; } else { node->parent->right = right; } right->left = node; node->parent = right; } void rightRotate (Node* node) { Node* left = node->left; node->left = left->right; if (left->right != nil) { left->right->parent = node; } left->parent = node->parent; if (node->parent == nil) { root = left; } else if (node == node->parent->left) { node->parent->left = left; } else { node->parent->right = left; } left->right = node; node->parent = left; } void preorderPrintTree (Node* root) { if (root == nil) { return ; } if (root->color == 0 ) cout << "RED" << " " << root->val << endl; else if (root->color == 1 ) cout << "BLACK" << " " << root->val << endl; preorderPrintTree (root->left); preorderPrintTree (root->right); } void inorderPrintTree (Node* root) { if (root == nil) { return ; } inorderPrintTree (root->left); if (root->color == 0 ) cout << "RED" << " " << root->val << endl; else if (root->color == 1 ) cout << "BLACK" << " " << root->val << endl; inorderPrintTree (root->right); } void RBdelete (Node* node) { Node* y = node; Color y_original_color = y->color; if (node->left == nil) { Node* x = node->right; RBtransplant (node, node->right); } else if (node->right == nil) { Node* x = node->left; RBtransplant (node, node->left); } else { y = treeMinimum (node->right); y_original_color = y->color; Node* x = y->right; if (y->parent == node) { x->parent = y; } else { RBtransplant (y, y->right); y->right = node->right; y->right->parent = y; } RBtransplant (node, y); y->left = node->left; y->left->parent = y; y->color = node->color; } if (y_original_color == BLACK) { RBdeleteFixUp (node); } } void RBdeleteFixUp (Node* node) { while (node != nil && node->color == BLACK) { if (node == node->parent->left) { Node* w = node->parent->right; if (w->color == RED) { w->color = BLACK; node->parent->color = RED; leftRotate (node->parent); w = node->parent->right; } if (w->left->color == BLACK && w->right->color == BLACK) { w->color = RED; node = node->parent; } else { if (w->right->color == BLACK) { w->left->color = BLACK; w->color = RED; rightRotate (w); w = node->parent->right; } w->color = node->parent->color; node->parent->color = BLACK; w->right->color = BLACK; leftRotate (node->parent); node = root; } } else { Node* w = node->parent->left; if (w->color == RED) { w->color = BLACK; node->parent->color = RED; rightRotate (node->parent); w = node->parent->left; } if (w->right->color == BLACK && w->left->color == BLACK) { w->color = RED; node = node->parent; } else { if (w->left->color == BLACK) { w->right->color = BLACK; w->color = RED; leftRotate (w); w = node->parent->left; } w->color = node->parent->color; node->parent->color = BLACK; w->left->color = BLACK; rightRotate (node->parent); node = root; } } } node->color = BLACK; } void RBtransplant (Node* u, Node* v) { if (u->parent == nil) { root = v; } else if (u == u->parent->left) { u->parent->left = v; } else { u->parent->right = v; } v->parent = u->parent; } Node* treeMinimum (Node* node) { while (node->left != nil) { node = node->left; } return node; } Node* search (int val) { Node* cur = root; while (cur != nil) { if (cur->val == val) { return cur; } else if (cur->val > val) { cur = cur->left; } else { cur = cur->right; } } return nil; } }; int main () { vector<int > nums = { 1 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 }; vector<int > delnums = { 14 ,9 ,5 }; RedBlackTree tree; cout << "nums:" << endl; for (int i = 0 ; i < nums.size (); i++) { cout << nums[i] << " " ; } cout << endl; for (int i = 0 ; i < nums.size (); i++) { tree.RBinsert (nums[i]); } cout << "preorderPrint:" << endl; tree.preorderPrintTree (tree.root); cout << "inorderPrint:" << endl; tree.inorderPrintTree (tree.root); cout << "delnums:" << endl; for (int i = 0 ; i < delnums.size (); i++) { cout << delnums[i] << " " ; } cout << endl; for (int i = 0 ; i < delnums.size (); i++) { Node* tmp = tree.search (delnums[i]); tree.RBdelete (tmp); cout << "preorderPrint:" << endl; tree.preorderPrintTree (tree.root); cout << "inorderPrint:" << endl; tree.inorderPrintTree (tree.root); } cout << "preorderPrint:" << endl; tree.preorderPrintTree (tree.root); cout << "inorderPrint:" << endl; tree.inorderPrintTree (tree.root); }
运行结果及分析