1.红黑树
红黑树是一种自平衡二叉查找树,它保证了每个节点在树中的黑色深度相同,并且满足以下性质:
-
节点要么是黑色,要么是红色。
-
根节点是黑色的。
-
叶子节点都是黑色的空节点。
-
如果一个节点是红色的,则它的两个子节点都是黑色的。
-
对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点。
通过这些性质,红黑树可以保证在插入和删除节点时能够自动地平衡树的结构,从而保证了查找、插入、删除等操作的时间复杂度为O(logn)。
红链所连的两个的节点可以合看成一个3-节点,合为一个节点,拥有三个子节点。
黑链所连为一般父子节点关系。
这里我们实现的是左偏红黑树,其中只有父节点与左节点链接处才为红链,根节点处不为红链(特殊),且红链不可连续,比如两个子节点与父节点相连都不能为红链。
我们是要创建一种自平衡二叉查找树(它通过保证左右子树的高度差小于等于1,来保持树的平衡),要控制树的高度平摊,不能像之前一样,添加节点使得树长的歪七扭八。
始终保持插入节点时,节点链接为红链,在之后的调整中进行黑红链的整改。
整改情况与措施:
1.如果子父连续红链,使用右旋法加颜色反转法。
2.如果两子节点都为红链,使用颜色反转法。
3.如果右子节点为红链,使用左选法。
2.左旋法
Node* rotateLeft(Node* node_h)
{
Node* node_x = node_h->right; //先把h节点的右节点取出
node_h->right = node_x->left; //换个向,使得红链接在左边的同时使得节点有序
node_x->left = node_h;
node_x->color = node_h->color;
node_h->color = RED;
return node_x;
}
出现了右节点红链,需要把红链移到左节点,移动后,父子节点值要进行改动(父节点大于左子节点,小于右子节点),且介于父子节点的节点也转换位置。
1.先取出父节点的右子节点
2.设父节点的右子节点为原右子节点的左节点(介于父子节点的节点)
3.设原右子节点的左节点为父节点
4.返回原右子节点,让原父节点的父节点指向
3.右旋法
Node* rotateRight(Node* node_h)
{
Node* node_x = node_h->left;
node_h->left = node_x->right;
node_x->right = node_h;
node_x->color = node_h->color;
node_h->color = RED;
return node_x;
}
1.先取出父节点的左子节点
2.让父节点的左子节点为原左子节点的右节点
3.让原左子节点的右节点为原父节点
4.返回原左子节点,让原父节点的父节点指向
左右旋如此”别扭“的目的:保持树的平衡
4.颜色反转法
void flipColor(Node* node) //颜色反转
{
node->color = RED;
node->left->color = BLACK;
node->right->color = BLACK;
}
字面意思,维持树的性质
添加数据后,再做些判断使用以上三个方法
添加函数put():
void put(int key, string value)
{
root=put(root, key, value);
if (root->left != NULL) /*两个if为特殊情况处理,根节点的两个左右子节点链
{ 不为红链*/
root->left->color = BLACK;
}
if (root->right != NULL)
{
root->right->color = BLACK;
}
}
Node* put(Node* node,int key, string value)
{
if (node == NULL)
{
N++;
return new Node(key, value,NULL,NULL, RED);
}
if (key < node->key)
{
node->left = put(node->left, key, value);
}
else if(key>node->key)
{
node->right = put(node->right, key, value);
}
else
{
node=new Node(key, value, NULL, NULL, RED);
}
//进行左旋
if (node->right->color == RED)
{
node=rotateLeft(node);
return node;
}
//进行右旋
if (node->left->color == RED && node->left->left->color == RED)
{
cout << value << endl;
cout << N << endl;
node=rotateRight(node);
}
//进行反转
if (node->left->color == RED && node->color == RED)
{
flipColor(node);
}
return node;
}
如果还是不解,可以了解下自平衡二叉查找树,并结以草图推导以上三个函数。
红黑树的高度比一般二叉查找树的要矮,查找其数据也就更高效,一般被用于实现高效的搜索算法。它不会出现极端情况,比如一颗二叉树从根节点开始就一直往左节点添加,那么查找最小值时是很耗费时间的。
整体代码如下(上传代码包好像太过于麻烦了):
#include <iostream>
using namespace std;
class Node
{
public:
Node(int key, string value, Node* left, Node* right,bool color)
{
this->key = key;
this->value = value;
this->left = left;
this->right = right;
this->color = color;
}
Node* left;
Node* right;
int key;
string value;
bool color;
};
class RedBlackTree
{
private:
Node* root;
int N;
bool RED;
bool BLACK;
public:
RedBlackTree()
{
root = NULL;
N = 0;
RED = true;
BLACK = false;
}
bool isRED(Node* node)
{
if (node == NULL)
{
return false;
}
if (node->color == RED)
{
return true;
}
return false;
}
Node* rotateLeft(Node* node_h)
{
Node* node_x = node_h->right; //先把h节点的右节点取出
node_h->right = node_x->left; //换个向,使得红链接在左边的同时使得节点有序
node_x->left = node_h;
node_x->color = node_h->color;
node_h->color = RED;
return node_x;
}
Node* rotateRight(Node* node_h)
{
Node* node_x = node_h->left;
node_h->left = node_x->right;
node_x->right = node_h;
node_x->color = node_h->color;
node_h->color = RED;
return node_x;
}
void flipColor(Node* node) //颜色反转
{
node->color = RED;
node->left->color = BLACK;
node->right->color = BLACK;
}
void put(int key, string value)
{
root=put(root, key, value);
if (root->left != NULL)
{
root->left->color = BLACK;
}
if (root->right != NULL)
{
root->right->color = BLACK;
}
}
Node* put(Node* node,int key, string value)
{
if (node == NULL)
{
N++;
return new Node(key, value,NULL,NULL, RED);
}
if (key < node->key)
{
node->left = put(node->left, key, value);
}
else if(key>node->key)
{
node->right = put(node->right, key, value);
}
else
{
node=new Node(key, value, NULL, NULL, RED);
}
//进行左旋
if (node->right->color == RED)
{
node=rotateLeft(node);
return node;
}
//进行右旋
if (node->left->color == RED && node->left->left->color == RED)
{
cout << value << endl;
cout << N << endl;
node=rotateRight(node);
}
//进行反转
if (node->left->color == RED && node->color == RED)
{
flipColor(node);
}
return node;
}
string get(int key)
{
return get(root, key);
}
string get(Node* node, int key)
{
if (node == NULL)
{
return "无此键值";
}
int result = key - node->key;
if (result==0)
{
return node->value;
}
if (result<0)
{
return get(node->left, key);
}
else
{
return get(node->right,key);
}
}
int size()
{
return N;
}
};
int main()
{
RedBlackTree RBtree;
RBtree.put(1, "张三");
RBtree.put(2, "李四");
RBtree.put(3, "王五");
cout << RBtree.get(1) << endl;
cout << RBtree.get(2) << endl;
cout << RBtree.get(3) << endl;
}