魔兽争霸3终极兼容方案:Warcraft Helper让你的经典游戏在Win10/Win11焕发新生
2026/5/22 16:22:19
红黑树是一种自平衡二叉搜索树,它通过额外的颜色规则保证在最坏情况下基本操作(插入、删除、查找)的时间复杂度为O(log n)。相比AVL树,红黑树的平衡条件更宽松,因此旋转操作更少,适合需要频繁修改的场景(如STL的map、set)。
红黑树是每个节点带有颜色属性(红色或黑色)的二叉搜索树,需满足以下5条性质:
红黑树的核心操作包括查找、插入和删除。其中查找与普通二叉搜索树一致,插入和删除后可能破坏红黑树性质,需通过旋转和重新着色修复。
旋转是调整树结构的基础操作,分为左旋和右旋,用于保持二叉搜索树性质的同时调整节点位置。
以节点x为中心,将x的右子节点y提升为父节点,x成为y的左子节点,y的原左子节点成为x的右子节点。
与左旋对称,以节点y为中心,将y的左子节点x提升为父节点,y成为x的右子节点,x的原右子节点成为y的左子节点。
插入步骤:
假设新节点为z,父节点p(z),祖父节点g(z),叔节点u(z)(p(z)的兄弟节点):
u(z)是红色 → 将p(z)和u(z)设为黑色,g(z)设为红色,然后递归检查g(z)。u(z)是黑色,且z是p(z)的右子节点 → 对p(z)左旋,转化为情况3。u(z)是黑色,且z是p(z)的左子节点 → 将p(z)设为黑色,g(z)设为红色,对g(z)右旋。删除步骤:
s,可能是后继或前驱)。s为黑色时):假设当前节点为x(替代节点),兄弟节点s:
s是红色 → 将s设为黑色,父节点设为红色,对父节点左旋,更新s为新兄弟节点。s是黑色,且s的两个子节点都是黑色 → 将s设为红色,x上移至父节点。s是黑色,左子红、右子黑 → 将s设为红色,左子设为黑色,对s右旋,更新s为新兄弟节点。s是黑色,右子红 → 将s的颜色设为父节点颜色,父节点设为黑色,右子设为黑色,对父节点左旋,x设为根节点结束。以下是简化版的红黑树实现(仅包含插入和遍历,删除操作类似但更复杂)
// 节点颜色枚举typedefenum{RED,BLACK}Color;// 红黑树节点(使用NIL节点简化边界处理)typedefstructNode{intdata;// 数据域Color color;// 颜色structNode*left;// 左子节点structNode*right;// 右子节点structNode*parent;// 父节点}Node;// 全局NIL节点(所有空指针指向它)Node*NIL;// 初始化NIL节点voidinitNIL(){NIL=(Node*)malloc(sizeof(Node));NIL->color=BLACK;NIL->left=NIL->right=NIL->parent=NULL;}// 创建新节点(初始颜色为RED)Node*createNode(intdata){Node*node=(Node*)malloc(sizeof(Node));node->data=data;node->color=RED;// 新节点默认红色node->left=node->right=node->parent=NIL;returnnode;}// 中序遍历(验证二叉搜索树性质)voidinOrderTraversal(Node*root){if(root==NIL)return;inOrderTraversal(root->left);printf("%d(%s) ",root->data,root->color==RED?"R":"B");inOrderTraversal(root->right);}// 层序遍历(直观查看树结构)voidlevelOrderTraversal(Node*root){if(root==NIL){printf("Tree is empty\n");return;}Node*queue[100];intfront=0,rear=0;queue[rear++]=root;while(front<rear){Node*current=queue[front++];printf("%d(%s) ",current->data,current->color==RED?"R":"B");if(current->left!=NIL)queue[rear++]=current->left;if(current->right!=NIL)queue[rear++]=current->right;}printf("\n");}// 左旋(x为旋转中心)voidleftRotate(Node**root,Node*x){Node*y=x->right;// y是x的右子节点x->right=y->left;// y的左子节点变为x的右子节点if(y->left!=NIL){y->left->parent=x;}y->parent=x->parent;// y继承x的父节点if(x->parent==NIL){*root=y;// x是根节点,y成为新根}elseif(x==x->parent->left){x->parent->left=y;// x是左子节点,y替换x的位置}else{x->parent->right=y;// x是右子节点,y替换x的位置}y->left=x;// x成为y的左子节点x->parent=y;}// 右旋(与左旋对称)voidrightRotate(Node**root,Node*y){Node*x=y->left;// x是y的左子节点y->left=x->right;// x的右子节点变为y的左子节点if(x->right!=NIL){x->right->parent=y;}x->parent=y->parent;// x继承y的父节点if(y->parent==NIL){*root=x;// y是根节点,x成为新根}elseif(y==y->parent->left){y->parent->left=x;// y是左子节点,x替换y的位置}else{y->parent->right=x;// y是右子节点,x替换y的位置}x->right=y;// y成为x的右子节点y->parent=x;}// 插入修复(处理插入后可能的红红冲突)voidinsertFixup(Node**root,Node*z){while(z->parent->color==RED){// 父节点为红色时需修复if(z->parent==z->parent->parent->left){// 父节点是祖父的左子Node*y=z->parent->parent->right;// 叔节点if(y->color==RED){// 情况1:叔节点红z->parent->color=BLACK;y->color=BLACK;z->parent->parent->color=RED;z=z->parent->parent;// 检查祖父}else{if(z==z->parent->right){// 情况2:z是右子z=z->parent;leftRotate(root,z);}// 情况3:z是左子z->parent->color=BLACK;z->parent->parent->color=RED;rightRotate(root,z->parent->parent);}}else{// 父节点是祖父的右子(对称处理)Node*y=z->parent->parent->left;// 叔节点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->left){z=z->parent;rightRotate(root,z);}z->parent->color=BLACK;z->parent->parent->color=RED;leftRotate(root,z->parent->parent);}}}(*root)->color=BLACK;// 确保根节点为黑}// 插入节点(返回根节点)Node*insert(Node*root,intdata){Node*z=createNode(data);Node*y=NIL;// y记录z的父节点Node*x=root;// 寻找插入位置(类似BST插入)while(x!=NIL){y=x;if(z->data<x->data){x=x->left;}else{x=x->right;}}z->parent=y;if(y==NIL){root=z;// 树为空,z成为根}elseif(z->data<y->data){y->left=z;}else{y->right=z;}// 修复红黑树性质insertFixup(&root,z);returnroot;}intmain(){initNIL();// 初始化NIL节点Node*root=NIL;// 插入测试数据inttestData[]={10,20,30,15,25,5};intn=sizeof(testData)/sizeof(testData[0]);for(inti=0;i<n;i++){root=insert(root,testData[i]);printf("插入 %d 后层序遍历: ",testData[i]);levelOrderTraversal(root);}// 验证中序遍历(应有序)printf("中序遍历结果: ");inOrderTraversal(root);printf("\n");return0;}红黑树因其高效的动态操作性能,被广泛应用于需要快速查找、插入、删除的场景:
map、set、multimap、multiset的底层实现(GCC使用红黑树)。TreeMap、TreeSet基于红黑树。CFS)、内存管理中的区间树。红黑树通过颜色规则和旋转操作,在动态数据维护中实现了高效的平衡。其核心是理解插入/删除后的修复逻辑(尤其是各种情况的处理顺序)。尽管代码实现较复杂,但掌握红黑树能帮助我们理解许多高级数据结构的设计思想。