黑紅樹
使用的平臺:vs2015
語言:c++
代碼有部分是借鑑的
我是一隻菜鳥,在平衡二叉樹要旋轉的時候總是繞道自己昏頭轉向,自己都弄不懂那棵樹是怎麼旋轉的,其實我也是不太明白了,但是希望我的代碼能夠幫助你們解決問題。代碼有錯誤,提前說啦!!
//核心函數: //void rb_right_rotate(rbnode* g) //void rb_left_rotate(rbnode* g) //void rbt_insert_check(rbnode* node) //int rbt_insert(rbtree* &tree, keyType key) //void rbt_delete_check //int is_black //int rbt_delete //左旋和右旋的代碼基本相同,只需要更改right和left //插入只有4中情況,而刪除有六種 //檢查部分需要細心看
#include <iostream>
using namespace std;
#define COLOR_RED 0
#define COLOR_BLACK 1
typedef int keyType;
// 定義而二叉樹節點數據結構
struct BinaryTreeNode {
keyType key;
int color;
BinaryTreeNode* parent; // 保存父節點
BinaryTreeNode* left; // left child
BinaryTreeNode* right; // right child
BinaryTreeNode* next;
};
// 定義紅黑樹的結點
typedef BinaryTreeNode rbnode;
// 定義紅黑樹
typedef BinaryTreeNode rbtree;
//左旋和右旋的代碼基本相同,只需要更改right和left
//插入只有4中情況,而刪除有六種
void preorder(rbtree *g);
void inorder(rbtree *g);
void postorder(rbtree *g);
void print(rbtree *g);
//R
void rb_right_rotate(rbnode* g) {
rbnode * p = g->left; //右轉,p指向g的left
//交換
keyType k = g->key;
g->key = p->key;
p->key = k;
//g的左節點是g的做節點的左節點
g->left = p->left;
if (NULL != p->left) {//右旋,p的left不能爲空
p->left->parent = g;
}
p->left = p->right;
p->right = g->right;
//這個if-else用於將g的父親節點的left或right點指向p,如果g的父節點爲不存在,則樹的parent指向p
if (NULL != g->right) {
g->right->parent = p;
}
g->right = p;
}
// L
void rb_left_rotate(rbnode* g) {
rbnode* p = g->right;
keyType k = g->key;
g->key = p->key;
p->key = k;
g->right = p->right;
if (NULL != p->right) {
p->right->parent = g;
}
p->right = p->left;
p->left = g->left;
if (NULL != g->left) {
g->left->parent = p;
}
g->left = p;
}
// 插入後調整
void rbt_insert_check(rbnode* node) {
// CASE 1 : 如果節點等於根節點,則設置節點的顏色爲黑色並返回。
if (NULL == node->parent) {
node->color = COLOR_BLACK;
return;
}
// CASE 2 : 當節點的父節點爲黑色時,所有功能都已滿足,停止檢查並返回
if (node->parent->color == COLOR_BLACK) {
return;
}
// 父節點爲紅色,這意味着祖父節點存在。
rbnode* gf = node->parent->parent;
rbnode* uf = (gf->left == node->parent) ? gf->right : gf->left;
// CASE 3 : 當叔叔節點存在並且它是紅時
if (NULL != uf && uf->color == COLOR_RED) {
// 設置父親和叔叔黑色,設置祖父紅色
node->parent->color = COLOR_BLACK;
uf->color = COLOR_BLACK;
gf->color = COLOR_RED;
// 然後重新檢查來自CASE 1的祖父節點處的樹。
rbt_insert_check(gf);
return;
}
// CASE 4 : 當叔叔是NULL或它的顏色是黑色。
if (node->parent == gf->left) { // 該節點在其祖父的左邊
// (a) LL model
if (node == node->parent->left) { //該節點在其父節點的左側
rb_right_rotate(gf);
}
// (b) LR model
else if (node == node->parent->right) { //該節點在其父節點的右側
rb_left_rotate(node->parent);
rb_right_rotate(gf);
}
}
else if (node->parent == gf->right) { //該節點在其祖父節點的右側
// (c) RR model
if (node == node->parent->right) { //該節點在其父節點的右側
rb_left_rotate(gf);
}
// (d) RL model
else if (node == node->parent->left) { //該節點在其父節點的左側
rb_right_rotate(node->parent);
rb_left_rotate(gf);
}
}
}
// 插入新的關鍵字
int rbt_insert(rbtree* &tree, keyType key) {
if (NULL == tree) { // 樹是否爲空
tree = (rbtree*)malloc((sizeof(rbnode))); //開闢空間
tree->key = key;
tree->color = COLOR_BLACK;//根爲黑色
tree->parent = tree->left = tree->right = NULL;
return 1;
}
//尋找插入點
rbnode *n = tree, *p = tree->parent;
while (NULL != n) {
if (key == n->key) { //插入值相同時,不用再插入
return 0;
}
p = n;
n = (key > p->key) ? p->right : p->left; //排序,有利於插入刪除
}
// 插入節點
n = (rbtree*)malloc((sizeof(rbnode)));
n->key = key;
n->color = COLOR_RED; //除了根節點外,插入的節點都是紅色,當調整完後,方可恢復黑色
n->parent = p;
n->right = n->left = NULL;
((key > p->key) ? p->right : p->left) = n; //判斷插入左節點還是右節點
// 調整數
rbt_insert_check(n);
return 1;
}
int is_black(rbnode * node) {
if (node == NULL) return 1;
if (node->color == COLOR_BLACK) return 1;
return 0;
}
//檢查刪除調整後
void rbt_delete_check(rbnode* p, bool delLeft) {
rbnode * n = delLeft ? p->left : p->right;
// case 1: n 是紅
if (NULL != n && n->color == COLOR_RED) {
n->color = COLOR_BLACK;
return;
}
// 其他子樹至少一個節點
rbnode * s = delLeft ? p->right : p->left;
rbnode * sl = s->left;
rbnode * sr = s->right;
// case 2 : S 紅 , p 左轉
if (s->color == COLOR_RED) {
if (delLeft) {
rb_left_rotate(p);
}
else {
rb_right_rotate(p);
}
p = s;
s = delLeft ? sl : sr;
sl = s->left;
sr = s->right;
}
// Other cases : S 黑
// SL 和 SR 黑
if (is_black(sl) && is_black(sr)) {
// case 3 : P紅, S SL和 SR 黑
if (!is_black(p)) {
p->color = COLOR_BLACK;
s->color = COLOR_RED;
}
// case 4: P ,S, SL,SR 黑
else {
s->color = COLOR_RED;
if (NULL == p->parent) {
return;
}
delLeft = (p == p->parent->left);
rbt_delete_check(p->parent, delLeft);
}
return;
}
// SL 和 SR 有紅色節點
if (delLeft) {
if (is_black(sr)) { // case 5(a) : delLeft 真 ,SR 黑
rb_right_rotate(s);
sr = s->right;
}
rb_left_rotate(p); // case 6(a) : p節點旋轉
sr->color = COLOR_BLACK;
}
else {
if (is_black(sl)) { // case 5(b) : delLeft 假 和SL 黑
rb_left_rotate(s);
sl = s->left;
}
rb_right_rotate(p); // case 6(b) : p節點旋轉
sl->color = COLOR_BLACK;
}
}
// 刪除一個節點
int rbt_delete(rbtree* &tree, keyType key) {
if (NULL == tree) {
return 0;
}
// 尋找節點
rbnode *curr, *temp;
for (curr = tree;;) {
if (key == curr->key) {
break;
}
curr = (key > curr->key) ? curr->right : curr->left;
if (NULL == curr) {
return 0;
}
}
//刪除的有兩個孩子
if (NULL != curr->left && NULL != curr->right) {
for (temp = curr->left; NULL != temp->right; temp = temp->right) {
}
curr->key = temp->key;
curr = temp;
}
if (NULL == curr->parent) { // 判斷是否樹的根
tree = (NULL == curr->left) ? curr->right : curr->left;
if (tree != NULL) {
tree->color = COLOR_BLACK;
tree->parent = NULL;
}
free(curr);
return 1;
}
// 刪除節點
rbnode* fa = curr->parent;
temp = (NULL == curr->left) ? curr->right : curr->left;
bool delLeft = (fa->left == curr);
if (NULL != temp) {
temp->parent = fa;
}
delLeft ? fa->left = temp : fa->right = temp;
if (curr->color != COLOR_RED) { // adjust after deletion
rbt_delete_check(fa, delLeft);
}
free(curr);
return 1;
}
void preorder(rbnode *g)
{
if (g != NULL)
{
cout << g->key<< " " ;
preorder(g->left);
preorder(g->right);
}
}
void inorder(rbnode *g)
{
if (g != NULL)
{
inorder(g->left);
cout << g->key<<" ";
inorder(g->right);
}
}
void postorder(rbnode *g)
{
if (g != NULL)
{
postorder(g->left);
postorder(g->right);
cout << g->key << " ";
}
}
void print(rbnode *g)
{
//
cout << "先序輸出 :";
preorder(g);
cout << endl;
cout << "中序輸出 :" ;
inorder(g);
cout << endl;
cout << "後序輸出 :";
postorder(g);
cout << endl;
}
int main()
{
rbnode *p=NULL ;
cout << "插入數據:\n" << endl;
for (int i = 0; i <6; i++)
{
cout << i + 1 << endl;
int a;
cin >> a;
rbt_insert(p,a);
print(p);
cout << endl;
}
//cout << "調整後:\n" << endl;
//print(p);
//
cout << "刪除數據 :\n" << endl;
for (int i = 0; i <5; i++)
{
cout << i + 1 << endl;
int a;
cin >> a;
rbt_delete(p, a);
print(p);
cout << endl;
}
system("pause");
}