寫一個自己想要的“set”,想實現什麼功能直接在裏面添加。STL雖然把set封裝的很好,很強大,易於擴展,但是正由於兼容性很好,封裝太多層,犧牲了很多性能。廢話不多說,先曬出我的測試結果:
測試用的是谷歌codejam的一道題,提供了一百個測試用例,這道題需要頻繁調用set的插入與刪除,用來測試再好不過。
題目地址:https://code.google.com/codejam/contest/6364486/dashboard(需要小工具哦)
下面是我下載的一個AC代碼
#include<iostream>
#include<ifstream>
#include<set>
using namespace std;
ifstream infile;
ofstream outfile;
const int MAXN = 500005;
int X[MAXN];
int S[MAXN];
long long sum[MAXN];
void erase_one(multiset<long long> &s, long long x) {
auto it = s.find(x);
auto it1 = it;
it1++;
s.erase(it++);
}
void solve() {
int N, O;
long long D;
infile >> N >> O >> D;
int X1, X2, A, B, C, M, L;
infile >> X1 >> X2 >> A >> B >> C >> M >> L;
X[1] = X1, X[2] = X2;
for (int i = 3; i <= N; i++) {
X[i] = (1LL * A * X[i - 1] + 1LL * B * X[i - 2] + C) % M;
}
for (int i = 1; i <= N; i++) {
S[i] = X[i] + L;
sum[i] = sum[i - 1] + S[i];
}
int cnt_odd = 0;
int l = 1;
multiset<long long> s;
long long ans = -0x3f3f3f3f3f3f3f3fLL;
for (int i = 1; i <= N; i++) {
s.insert(sum[i - 1]);
cnt_odd += S[i] & 1;
while (cnt_odd > O) {
erase_one(s, sum[l - 1]);
//s.erase_unique(sum[l - 1]);
cnt_odd -= S[l] & 1;
l++;
}
auto it = s.lower_bound(sum[i] - D);
if (it != s.end()) {
ans = std::max(ans, sum[i] - *it);
}
}
if (ans == -0x3f3f3f3f3f3f3f3fLL) {
outfile << "IMPOSSIBLE" << endl;
}
else {
outfile << ans << endl;
}
}
int main() {
infile.open("F:\\谷歌下載\\A-large-practice.in");
outfile.open("F:\\谷歌下載\\A-large-practice.out");
int T;
infile >> T;
for (int i = 1; i <= T; i++) {
cout << i << endl;
outfile << "Case #" << i << ": ";
solve();
}
return 0;
}
for循環中頻繁插入刪除,大部分測試用例N都是等於50 萬,我們來看看用時
14分鐘,如果你在做谷歌筆試題,這個時間可能會讓你抓狂。
再看看用了自己寫的set後
你沒看錯,僅需要一分鐘19秒。快了接近十倍。
再看看結果對不對
顯示correct是對的。
是我的算法效率更高?我看了源碼,並不是,大牛們在設計STL考慮到兼容性,可擴展性,不可避免的損失了一部分性能。
廢話不多說上代碼:
先給紅黑樹搞個數據結構,就是五大點,左右孩子,父母,key,顏色color;兩個函數分別是尋找前驅,尋找後繼,因爲在後面的迭代器與類中都要用到,爲了避免代碼重複,放在了結構體中。(全局函數也行)
template<class T>
struct RB_TreeNode
{
RB_TreeNode * left;
RB_TreeNode * right;
RB_TreeNode * p;
T key;
color color;
RB_TreeNode (T x,RB_TreeNode<T>* _Guard) :key(x), left(_Guard), right(_Guard), p(_Guard), color(red) {};
RB_TreeNode () : key(T()),left(NULL), right(NULL), p(NULL), color(black) {};
RB_TreeNode(T val) :key(val),left(NULL), right(NULL), p(NULL), color(black) {};
void operator=(RB_TreeNode<T>& oth) {
left = oth.left;
color = oth.color;
right = oth.right;
key = oth.key;
p = oth.p;
}
//尋找前驅
RB_TreeNode<T>* findFront(RB_TreeNode<T>* _Guard)
{
RB_TreeNode<T>* t = this;
if (t == _Guard) return t;
if (t->left != _Guard)
{
t = t->left;
while (t->right != _Guard)
t = t->right;
return t;
}
else
{
while (t->p != _Guard&&t == t->p->left)
t = t->p;
return t->p;
}
}
//尋找後繼
RB_TreeNode<T>* findSucceed(RB_TreeNode<T>* _Guard)
{
RB_TreeNode<T>* t = this;
if (t == _Guard) return t;
if (t->right != _Guard)
{
t = t->right;
while (t->left != _Guard)
t = t->left;
return t;
}
else
{
while (t->p != _Guard&&t == t->p->right)
t = t->p;
return t->p;
}
}
};
那既然是紅黑樹,不可避免要說到它的五個特性:
1 每個節點非黑即紅;
2 根節點黑色
3 每個葉節點黑色
4 如果節點爲紅色,則倆孩子都爲黑色
5 對於每個節點,該節點到葉節點的每條路徑黑高度都相同
我們來看看這種數據結構有什麼好處,在此之前,先證明一個公式,以x爲根的節點內節點個數至少是2的bh次方減一個,對於高度爲0的節點顯然成立,爲0;每個內節點都有兩個子女,若X的黑高度爲bh,則兒子的黑高度至少爲bh-1,如果這個公式對於子女成立,則對於跟至少有2^(bh-1)-1+2^(bh-1)-1=2^bh-1個節點,歸納假設成立。若樹內節點總數爲n,則有n>=2^bh-1;而由性質1,4可知,黑節點個數大於等於紅色節點個數的,故總高度h<=bh*2;因此n>=2^(h/2)-1;得到高度h<=2lg(n+1);這意味着搜索時間將是對數時間。
當然了,紅黑樹的優勢不止於此,不然直接使用AVL樹好了,搜索時間更佳,紅黑樹另一個特性是刪除後所執行的旋轉操作量級是O(1),而AVL樹是O(lgn),而且紅黑樹對插入刪除節點沒有AVL樹那麼敏感。
至於紅黑樹的插入刪除先留在後面講插入刪除代碼的時候講。
下面一部分一部分介紹代碼,總代碼放在最後
template<class value,class ref,class ptr>
struct rbtree_iterator :public iterator<bidirectional_iterator_tag, value> {
typedef rbtree_iterator<value, value&, value*> iterator;
typedef RB_TreeNode<value>* link_type;
typedef rbtree_iterator<value, ref, ptr> self;
link_type node;
link_type _Guard;
rbtree_iterator() {};
rbtree_iterator(const link_type& x,const link_type& g):node(x),_Guard(g) {};
rbtree_iterator(const iterator& it) :node(it.node), _Guard(it._Guard) {};
self& operator=(const self& oth) { node = oth.node; return *this; };
ref operator*() const { return node->key; };
ptr operator->() const { return &(node->key); };
self& operator++() { node = node->findSucceed(_Guard); return *this; };
self operator++(int) { self tmp = *this; node = node->findSucceed(_Guard); return tmp; };
self& operator--() { node = node->findFront(_Guard); return *this; };
self operator--(int) { self tmp = *this; node = node->findFront(_Guard); return tmp; };
bool operator==(const self& oth) { return node == oth.node; };
bool operator!=(const self& oth) { return !(node == oth.node); };
};
爲了與STL契合,必須爲RBTree設計一個專屬迭代器的類,在這裏我繼承了iterator類的iterator<bidirectional_iterator_tag, value>
bidirectional_iterator_tag 是可向前可向後的迭代器,迭代器的類型劃分,具體的可以看STL源碼剖析,裏面很詳細。
在迭代器這個類中,有一個link_type類型的節點,在這裏他的類型就是我們樹的節點類型,RB_TreeNode<value>*,之後我們通過迭代器的構造函數將RBTree的節點傳進來,通過操作這個節點來操作紅黑樹。類中主要重載了平時指針所用到的操作符諸如++,--,*,->等等;
在類的開始,我寫了一個仿函數,作爲RBTree比較函數的默認參數,如果對象重載了小於號,則無需傳入比較函數,注意到我們將給迭代器類模板參數進行了限定,並進行了重命名,參數限定,是爲了與我們的類匹配,重命名,Emmmm,STL迭代器都叫這名字。
然後就是構造函數與操作符重載
RBTree(const keycompare& comp = keycompare());//默認構造函數
RBTree(const RBTree<T,keycompare>& oth);
RBTree(RBTree<T,keycompare>&& oth);//移動構造函數
template<class _itr>
RBTree(_itr begin, _itr end);//如果傳入的是迭代器
virtual~RBTree();
///操作符重載
RBTree<T,keycompare>& operator=(const RBTree<T, keycompare>& oth);
RBTree<T,keycompare>& operator=(RBTree<T, keycompare>&& oth);
const_iterator operator[](int i);
這裏是一些功能函數(基本想要實現的都有)
void clear();//清空樹
int size();//返回樹的數量
bool empty();//判空
int count(T val);//與val相等的元素的數量
void insert(T value);//插入元素,可重複
void insert_unique(T value);//插入元素,如果重複,後來的會代替現在的。
//想怎麼刪除,就怎麼刪除
void erase_unique(T value);//刪除一個等於value的元素
void erase_equal(T value); //刪除所有等於value的元素
void erase(const_iterator& l, const_iterator& r);//刪除迭代器區間的元素
void erase(const_iterator& start, int n);//刪除從指定迭代器開始的n個元素
void erase(const_iterator& it);//刪除迭代器指向的元素
////你要的迭代器 我都有
const_iterator begin();//返回最小元素的迭代器
const_iterator end(); //返回一個邊界,跟STL其他容器的end()差不多
const_iterator back(); //返回最大元素的迭代器
const_iterator start(); //返回一個邊界,只不過是前邊界,實際與end()地址相同,爲了區別寫了這麼個函數
const_iterator find(T val);//尋找指定元素第一次出現,返回一個迭代器;
const_iterator findlast(T val);//尋找指定元素最後一次出現,返回一個迭代器;
const_iterator lower_bound(T val);//如果元素存在,返回它第一次出現時的迭代器,若不存在返回它下邊界迭代器
const_iterator upper_bound(T val);//元素存在,返回最後一次出現迭代器,不存在,返回上邊界迭代器
這些函數都被我一一測試過都可用,至於具體實現,看最後代碼。
爲了實現上面的功能,寫了以下輔助函數
//測試用的函數
void pre_traverse();
void mid_traverse(T* pt = NULL);
void post_traverse();
void print();
RB_TreeNode<T>* guard();
RB_TreeNode<T> * getroot();
private:
void RBerase(RB_TreeNode<T>* node);//刪除函數
RB_TreeNode<T>* RBTree_serch(T value, RB_TreeNode<T>* beginRoot);//尋找函數
void RBTree_insert(T value, bool isunique);//插入函數
void Left_Rotate(RB_TreeNode<T> * t);//左旋
void Right_Rotate(RB_TreeNode<T> * t);//右旋
void RBDELETE_Fixup(RB_TreeNode<T> * t);//刪除後調整紅黑特性
void RBINSERT_Fixup(RB_TreeNode<T> * t);//插入後調整紅黑特性
RB_TreeNode<T>* findFront(RB_TreeNode<T>* t);//尋找前驅
RB_TreeNode<T>* findSucceed(RB_TreeNode<T> * t);//尋找後繼
const_iterator findFandB(RB_TreeNode<T>* target, bool isForward);//尋找與指定值相等的最前面元素與最後面元素
RB_TreeNode<T> * copyTree(const RB_TreeNode<T>* oth, RB_TreeNode<T>* p, RB_TreeNode<T>*const& Guard);//拷貝
void distroy(RB_TreeNode<T>* root);//銷燬
int findindex(RB_TreeNode<T>* root, int num, RB_TreeNode<T>*& tar, int& index);
void relationGuard();
void printNode(RB_TreeNode<T> * outT);
RB_TreeNode<T>* _guard;
RB_TreeNode<T>* _root;
int _len;
keycompare com;
friend ostream& operator<<(ostream &out, RB_TreeNode<T> * outT);
下面講一講紅黑樹的插入:
具體代碼:
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::RBTree_insert(T value, bool isunique) {
RB_TreeNode<T> * Tnode = new RB_TreeNode<T>(value, _guard);
RB_TreeNode<T> * tmp = _root;
RB_TreeNode<T> * Ptmp = _guard;
if (_root == _guard)//如果插入的節點是第一個節點,相當於初始化根節點
{
_root = Tnode;
_root->color = black;
_len++;
_guard->left = _root;
_guard->right = _root;
return;
}
//如果插入的節點小於最小值,直接插在最左邊,並更新最小值節點
if (com(value, _guard->left->key)) {
Tnode->p = _guard->left;
_guard->left->left = Tnode;
_guard->left = Tnode;
}
//如果插入的節點大於等於最大值,直接插在最右邊,更新最大值節點
else if (!com(value, _guard->right->key)) {
if (!com(_guard->right->key, value) && isunique) {
swap(_guard->right->key, tmp->key);
delete Tnode;
return;
}
Tnode->p = _guard->right;
_guard->right->right = Tnode;
_guard->right = Tnode;
}
else {
///以上三種情況都不屬於尋找合適的插入節點,就一直往下找,直到邊界條件(找到了空節點,在我這是_guard)
while (tmp != _guard)
{
Ptmp = tmp;
if (com(value, tmp->key))
tmp = tmp->left;
else if (com(tmp->key, value))
tmp = tmp->right;
else {
if (isunique) {
swap(Tnode->key, tmp->key);
delete Tnode;
return;
}
tmp = tmp->right;
}
}
///更新插入節點的父親,以及該父親的孩子須得指向它
Tnode->p = Ptmp;
if (com(Tnode->key, Ptmp->key))
Ptmp->left = Tnode;
else
Ptmp->right = Tnode;
}
///如果插入節點的父親是紅色,則違反了紅黑樹紅黑特性,需要調整
if (Tnode->p->color == red)
RBINSERT_Fixup(Tnode);
_len++;///別忘了更新元素數目
}
需要注意的是,一般樹的邊界都是NULL,在這裏我有個特殊節點_guard,是所有葉節點的孩子,也就是說,在這裏他就是邊界,而且它也是 根_root的父母,其左右孩子分別指向最小值跟最大值,所以在插入的時候要注意更新
插入節點的父親如果是紅色,由於插入節點的顏色默認爲紅色,此時便違反了紅黑樹性質4中的如果節點顏色爲紅,則孩子必須爲黑。這種情況我們需要調整紅黑樹,也就是我函數中的
void RBDELETE_Fixup(RB_TreeNode<T> * t);//刪除後調整紅黑特性
void RBINSERT_Fixup(RB_TreeNode<T> * t);//插入後調整紅黑特性
在講這個之前,先講一講左旋與右旋,我轉載了一個有趣而生動的圖(博客地址,圖上有):
- 這兩幅圖分別是左旋與右旋;
- 其實看左旋與右旋很簡單,如圖1中的左旋E是S的父親,我們看到無論怎麼旋轉,下面三個子節點,E左,E右,S右,從橫向來看,相對位置沒變過,其實只要令S的左孩子爲E,然後順序把三個孩子掛上就行了。當然了,要維護節點中的P;
- 下面是左旋,右旋代碼,邏輯很簡單,就是要注意細節,別忘了維護他們的父節點,簡單來說,就是A的兒子變成了B,那麼別忘了把B的父親變成A;
//////左旋 template<class T, class keycompare = mycom<T>> void RBTree<T, keycompare>::Left_Rotate(RB_TreeNode<T> * t) { if (t == _guard || t->right == _guard) { cout << "左旋節點或節點右孩子不應爲空" << endl; return; } RB_TreeNode<T> * tmp = t->right; tmp->p = t->p; if (t->p == _guard) { _root = tmp; } else if (t == t->p->left) t->p->left = tmp; else t->p->right = tmp; t->p = tmp; t->right = tmp->left; if (tmp->left != _guard) tmp->left->p = t; tmp->left = t; } ////右旋 template<class T, class keycompare = mycom<T>> void RBTree<T, keycompare>::Right_Rotate(RB_TreeNode<T> * t) { if (!t || !t->left) { cout << "右旋節點或節點左孩子不應爲空" << endl; return; } RB_TreeNode<T> * tmp = t->left; tmp->p = t->p; if (t->p == _guard) { _root = tmp; } else if (t == t->p->left) t->p->left = tmp; else t->p->right = tmp; t->p = tmp; t->left = tmp->right; if (tmp->right != _guard) tmp->right->p = t; tmp->right = t; }
調整紅黑樹的顏色,主要分三種情況(當插入節點父親爲紅色的時候)
-
下面所有圖均轉載自:https://blog.csdn.net/lucienduan/article/details/38880523
-
第一種情況:如圖叔叔是紅色,此時將父親跟叔叔變成黑色,祖父變成紅色,這時我們令node等於祖父,如果祖父的父親還是紅色,繼續進入循環,如果祖父父親是黑色,則退出。也就是剛纔node面臨的情況現在到了祖父頭上
-
第二種情況與第三種情況放一起講,我們把第二種情況進行一個左旋,變成第三種情況,叔叔是黑色。這種情況將祖父節點來一個右旋,並把祖父節點變成紅色,父節點變成黑色,這樣黑高度保持不變,也滿足了性質4
-
總結一下。紅黑樹插入,如果插入節點父親是紅色,則需要調整紅黑樹。此時可分爲三種情況,其實是兩種情況,當叔叔是紅色和當叔叔是黑色,當叔叔是紅色,直接把叔叔跟父親染黑,祖父染紅(祖父原來肯定是黑色,不然在插入之前,這顆紅黑樹就違反了性質4),然後祖父節點代替原來的節點進入檢查,一直向上升,直到遇到叔叔是黑色或者上升到根節點。
-
當叔叔是黑色,此時分爲插入節點本身是是左孩子還是右孩子,如果是右孩子,一波左旋,變成情況3,當然了此時的父親孩子角色換了,不過這部重要,重要的是形狀。變成情況三一波右旋,把父親節點頂上去,染成黑色,祖父變成紅色。
-
這裏只討論了插入節點是左孩子的情況,如果是右孩子,對稱
-
下面是代碼:
-
template<class T, class keycompare = mycom<T>> void RBTree<T, keycompare>::RBINSERT_Fixup(RB_TreeNode<T> * t) { RB_TreeNode<T> * tmp = t->p; RB_TreeNode<T> * Pbra = _guard; //出遞歸的條件,就是節點是黑色 while (tmp->color==red) { //這個就是我們討論的當插入節點是左孩子的時候 if (tmp == tmp->p->left) { Pbra = tmp->p->right; ///第一種情況 叔叔是紅色 if (Pbra!=_guard&&Pbra->color == red) { tmp->color = black; tmp->p->color = red; Pbra->color = black; t = tmp->p;//當前節點變成祖父節點 tmp = t->p;//同時更新父節點爲祖父節點的父親節點 } else { ///叔叔是黑色 if (t == tmp->right)///插入節點是右孩子,左旋,變成第三種情況 { Left_Rotate(tmp); tmp = t;//注意這裏左旋之後,孩子父親角色換了 } tmp->color = black;//tmp顏色變黑,達到出循環的條件 tmp->p->color = red; Right_Rotate(tmp->p); } } else//這邊是插入節點是右孩子的情況,與上面是對稱的 { Pbra = tmp->p->left; if (Pbra!=_guard&&Pbra->color == red) { tmp->color = black; tmp->p->color = red; Pbra->color = black; t = tmp->p; tmp = t->p; } else { if (t == tmp->left) { Right_Rotate(tmp); tmp = t; } tmp->color = black; tmp->p->color = red; Left_Rotate(tmp->p); } } if (tmp==_guard)//說明當前節點是根節點,因爲只有根節點的父節點是邊界節點_guard { ///這裏其實可以直接將t的顏色變成黑色,然後直接出循環 tmp = t; tmp->color = black; } } }
-
下面是刪除代碼,如果節點有一個孩子是邊界節點,那麼直接把節點刪除,節點的父親與節點的另一個孩子相連。如果節點的左右孩子都不是邊界節點,那麼找到它的後繼節點,然後交換兩個節點的信息,刪除後後繼節點。其實在交換過程中,最簡單的就是交換兩者的key,這樣節點的結構就沒變化,不用更新左右孩子與父親(這個更新起來巨麻煩六個指針),但是如果這樣,指向後繼的迭代器就會失效。所以必須交換兩塊內存。
-
下面是代碼:
-
template<class T, class keycompare = mycom<T>> void RBTree<T, keycompare>::RBTree_insert(T value, bool isunique) { RB_TreeNode<T> * Tnode = new RB_TreeNode<T>(value, _guard); RB_TreeNode<T> * tmp = _root; RB_TreeNode<T> * Ptmp = _guard; if (_root == _guard)//如果插入的節點是第一個節點,相當於初始化根節點 { _root = Tnode; _root->color = black; _len++; _guard->left = _root; _guard->right = _root; return; } //如果插入的節點小於最小值,直接插在最左邊,並更新最小值節點 if (com(value, _guard->left->key)) { Tnode->p = _guard->left; _guard->left->left = Tnode; _guard->left = Tnode; } //如果插入的節點大於等於最大值,直接插在最右邊,更新最大值節點 else if (!com(value, _guard->right->key)) { if (!com(_guard->right->key, value) && isunique) { swap(_guard->right->key, tmp->key); delete Tnode; return; } Tnode->p = _guard->right; _guard->right->right = Tnode; _guard->right = Tnode; } else { ///以上三種情況都不屬於尋找合適的插入節點,就一直往下找,直到邊界條件(找到了空節點,在我這是_guard) while (tmp != _guard) { Ptmp = tmp; if (com(value, tmp->key)) tmp = tmp->left; else if (com(tmp->key, value)) tmp = tmp->right; else { if (isunique) { swap(Tnode->key, tmp->key); delete Tnode; return; } tmp = tmp->right; } } ///更新插入節點的父親,以及該父親的孩子須得指向它 Tnode->p = Ptmp; if (com(Tnode->key, Ptmp->key)) Ptmp->left = Tnode; else Ptmp->right = Tnode; } ///如果插入節點的父親是紅色,則違反了紅黑樹紅黑特性,需要調整 if (Tnode->p->color == red) RBINSERT_Fixup(Tnode); _len++;///別忘了更新元素數目 } /////刪除節點 template<class T, class keycompare = mycom<T>> void RBTree<T, keycompare>::RBerase(RB_TreeNode<T>* node) { RB_TreeNode<T>* t = node; if (t == _guard) return; RB_TreeNode<T>* tmp; if (t->left != _guard&&t->right != _guard) { ///節點左右孩子都不是邊界節點,交換信息 RB_TreeNode<T>* succ = findSucceed(t); if (t == t->p->left) t->p->left = succ; else t->p->right = succ; if (succ == succ->p->left) succ->p->left = t; else succ->p->right = t; swap(succ->p, t->p); swap(succ->color, t->color); swap(succ->left, t->left); swap(succ->right, t->right); succ->left->p = succ; succ->right->p = succ; if (t->left != _guard) t->left->p = t; if (t->right != _guard) t->right->p = t; if (succ->p == _guard) _root = succ; //這裏其實最簡單的方法是交換兩個key然後直接刪除succ,但是這樣做會令原來指向succ的迭代器失效,所以要逐個交換。 } ///這裏就是的tmp就是我們需要跟刪除節點父親建立聯繫的孩子節點 if (t->left == _guard) tmp = t->right; else tmp = t->left; ///如果刪除的是最小值或者最大值,要更新_guard孩子 if (t == _guard->left) _guard->left = findSucceed(t); if (t == _guard->right) _guard->right = findFront(t); if (t->p == _guard) _root = tmp;///如果是根,要及時更新根節點 else if (t == t->p->left)///tmp 取代原來t的位置 t->p->left = tmp; else t->p->right = tmp; tmp->p = t->p; if (t->color == black)///如果被刪除的節點是黑色,需要調整紅黑樹紅黑特性 { RBDELETE_Fixup(tmp); } _len--; delete t; t = NULL; return; }
如果被刪除節點是黑色,那麼這條路徑黑高度下降,需要調整顏色,刪除情況比插入複雜,我們可以假想成被刪除節點的黑色被加在了孩子節點上,這樣孩子節點就是兩層顏色,多了一層黑色,大概可分爲四種情況:
-
以下所有圖均轉載自:https://blog.csdn.net/lucienduan/article/details/38880523
-
第一種情況,兄弟是紅色,直接右旋,並將父親節點染紅。這樣節點的兄弟就變成黑色了,變成第2,3,4種情況
-
-
-
第二種情況:兄弟是黑,且兄弟的左右孩子都是黑色,這種情況吧兄弟染紅,上推至父親節點,node節點本來多的那一層黑色被移到父親節點身上了,現在父親節點身上有兩層黑色,繼續進入循環
第三種情況是兄弟黑,且兄弟的左孩子紅色,右孩子黑色,此時我們將兄弟節點跟左孩子節點顏色交換,並將兄弟右旋,此時變成了情況4,當然別忘了,此時的兄弟與孩子的父親兒子身份交換了,現在的兄弟是與原來兄弟的右孩子,此時兄弟右孩子是紅色
第四種情況兄弟右孩子爲紅色,將父親節點左旋,並把將兄弟的黑色傳給右孩子,將父親節點的顏色傳給兄弟,然後將node的額外黑色給父親。這樣NODE去掉了額外的黑色,且保持了黑高度。
代碼如下:
///刪除節點後調整紅黑樹滿足紅黑樹五個特性
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::RBDELETE_Fixup(RB_TreeNode<T> * t)
{
RB_TreeNode<T> * w = NULL;
while (t!=_root&&t->color==black)
{
////要連接的孩子節點是左孩子的情況
if (t == t->p->left)
{
w = t->p->right;//兄弟節點
////第一種情況
if (w->color == red)///兄弟是紅色
{
///交換兄弟與父親的顏色,因爲兄弟顏色是紅色,父親肯定是黑色,所以直接賦值
t->p->color = red;
w->color = black;
Left_Rotate(t->p);
}
else
{
///兄弟右孩子是紅色,就是第四種情況
if (w->right->color == red)
{
w->color = t->p->color;
t->p->color = black;
w->right->color = black;
Left_Rotate(t->p);
t = _root;///這裏是爲了最後一句,出循環後要把t染成黑色,將t設置爲根節點,可以出循環,將根節點染黑沒影響
}
else if (w->left->color == red)///右孩子是黑色,左孩子紅色
{
w->color = red;
w->left->color = black;
Right_Rotate(w);
w = w->p;//別忘了右旋之後更新兄弟
}
else
{
///兩個孩子都是黑色,也就是第二種情況,把兄弟染紅,將另一重黑色往上推,也就是父親節點
w->color = red;
t = t->p;
}
}
}
///這邊是當前節點是右孩子的情況 完全對稱
else
{
w = t->p->left;
if (w->color == red)
{
t->p->color = red;
w->color = black;
Right_Rotate(t->p);
}
else
{
if (w->left != _guard&&w->left->color == red)
{
w->color = t->p->color;
t->p->color = black;
w->left->color = black;
Right_Rotate(t->p);
t = _root;
}
else if (w->right != _guard&&w->right->color == red)
{
w->color = red;
w->right->color = black;
Left_Rotate(w);
w = w->p;
}
else
{
w->color = red;
t = t->p;
}
}
}
}
t->color = black;///出循環要麼是t是紅色,要麼t是根節點,直接染黑。
}
下面是完整代碼,有興趣可以回去用用試試看(哈哈哈)
#pragma once
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<iterator>
#include<algorithm>
using namespace std;
enum color
{
red,
black
};
template<class T>
struct RB_TreeNode
{
RB_TreeNode * left;
RB_TreeNode * right;
RB_TreeNode * p;
T key;
color color;
RB_TreeNode (T x,RB_TreeNode<T>* _Guard) :key(x), left(_Guard), right(_Guard), p(_Guard), color(red) {};
RB_TreeNode () : key(T()),left(NULL), right(NULL), p(NULL), color(black) {};
RB_TreeNode(T val) :key(val),left(NULL), right(NULL), p(NULL), color(black) {};
void operator=(RB_TreeNode<T>& oth) {
left = oth.left;
color = oth.color;
right = oth.right;
key = oth.key;
p = oth.p;
}
//尋找前驅
RB_TreeNode<T>* findFront(RB_TreeNode<T>* _Guard)
{
RB_TreeNode<T>* t = this;
if (t == _Guard) return t;
if (t->left != _Guard)
{
t = t->left;
while (t->right != _Guard)
t = t->right;
return t;
}
else
{
while (t->p != _Guard&&t == t->p->left)
t = t->p;
return t->p;
}
}
//尋找後繼
RB_TreeNode<T>* findSucceed(RB_TreeNode<T>* _Guard)
{
RB_TreeNode<T>* t = this;
if (t == _Guard) return t;
if (t->right != _Guard)
{
t = t->right;
while (t->left != _Guard)
t = t->left;
return t;
}
else
{
while (t->p != _Guard&&t == t->p->right)
t = t->p;
return t->p;
}
}
};
// :public iterator<bidirectional_iterator_tag, value>
template<class value,class ref,class ptr>
struct rbtree_iterator {
typedef rbtree_iterator<value, value&, value*> iterator;
typedef RB_TreeNode<value>* link_type;
typedef rbtree_iterator<value, ref, ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef value value_type;
typedef ptr pointer;
typedef ref reference;
typedef ptrdiff_t difference_type;
link_type node;
link_type _Guard;
rbtree_iterator() {};
rbtree_iterator(const link_type& x,const link_type& g):node(x),_Guard(g) {};
rbtree_iterator(const iterator& it) :node(it.node), _Guard(it._Guard) {};
self& operator=(const self& oth) { node = oth.node; return *this; };
ref operator*() const { if (node == _Guard) { cout << "嘗試訪問邊界迭代器" << endl; throw; } return node->key; };
ptr operator->() const { if (node == _Guard) { cout << "嘗試訪問邊界迭代器" << endl; throw; }return &(node->key); };
self& operator++() { if (node == _Guard) { cout << "迭代器向後越界" << endl; throw; } node = node->findSucceed(_Guard); return *this; };
self operator++(int) { if (node == _Guard) { cout << "迭代器向後越界" << endl; throw; } self tmp = *this; node = node->findSucceed(_Guard); return tmp; };
self& operator--() { if (node == _Guard) { cout << "迭代器向前越界" << endl; throw; } node = node->findFront(_Guard); return *this; };
self operator--(int) { if (node == _Guard) { cout << "迭代器向前越界" << endl; throw; } self tmp = *this; node = node->findFront(_Guard); return tmp; };
bool operator==(const self& oth) { return node == oth.node; };
bool operator!=(const self& oth) { return !(node == oth.node); };
};
template<typename T>
class mycom {
public:
bool operator() (const T& left, const T& right) {
return left < right;
}
};
template<class T, class keycompare = mycom<T>>
class RBTree {
public:
typedef rbtree_iterator<T, T&, T*> iterator;
typedef rbtree_iterator<T, const T&, const T*> const_iterator;
RBTree(const keycompare& comp = keycompare());//默認構造函數
RBTree(const RBTree<T,keycompare>& oth);
RBTree(RBTree<T,keycompare>&& oth);//移動構造函數
template<class _itr>
RBTree(_itr begin, _itr end);//如果傳入的是迭代器
virtual~RBTree();
///操作符重載
RBTree<T,keycompare>& operator=(const RBTree<T, keycompare>& oth);
RBTree<T,keycompare>& operator=(RBTree<T, keycompare>&& oth);
const_iterator operator[](int i);
void clear();//清空樹
int size();//返回樹的數量
bool empty();//判空
int count(T val);//與val相等的元素的數量
void insert(T value);//插入元素,可重複
void insert_unique(T value);//插入元素,如果重複,後來的會代替現在的。
//想怎麼刪除,就怎麼刪除
void erase_unique(T value);//刪除一個等於value的元素
void erase_equal(T value); //刪除所有等於value的元素
void erase(const_iterator& l, const_iterator& r);//刪除迭代器區間的元素
void erase(const_iterator& start, int n);//刪除從指定迭代器開始的n個元素
void erase(const_iterator& it);//刪除迭代器指向的元素
////你要的迭代器 我都有
const_iterator begin();//返回最小元素的迭代器
const_iterator end(); //返回一個邊界,跟STL其他容器的end()差不多
const_iterator back(); //返回最大元素的迭代器
const_iterator start(); //返回一個邊界,只不過是前邊界,實際與end()地址相同,爲了區別寫了這麼個函數
const_iterator find(T val);//尋找指定元素第一次出現,返回一個迭代器;
const_iterator findlast(T val);//尋找指定元素最後一次出現,返回一個迭代器;
const_iterator lower_bound(T val);//如果元素存在,返回它第一次出現時的迭代器,若不存在返回它下邊界迭代器
const_iterator upper_bound(T val);//元素存在,返回最後一次出現迭代器,不存在,返回上邊界迭代器
//測試用的函數
void pre_traverse();
void mid_traverse(T* pt = NULL);
void post_traverse();
void print();
RB_TreeNode<T>* guard();
RB_TreeNode<T> * getroot();
private:
void RBerase(RB_TreeNode<T>* node);//刪除函數
RB_TreeNode<T>* RBTree_serch(T value, RB_TreeNode<T>* beginRoot);//尋找函數
void RBTree_insert(T value, bool isunique);//插入函數
void Left_Rotate(RB_TreeNode<T> * t);//左旋
void Right_Rotate(RB_TreeNode<T> * t);//右旋
void RBDELETE_Fixup(RB_TreeNode<T> * t);//刪除後調整紅黑特性
void RBINSERT_Fixup(RB_TreeNode<T> * t);//插入後調整紅黑特性
RB_TreeNode<T>* findFront(RB_TreeNode<T>* t);//尋找前驅
RB_TreeNode<T>* findSucceed(RB_TreeNode<T> * t);//尋找後繼
const_iterator findFandB(RB_TreeNode<T>* target, bool isForward);//尋找與指定值相等的最前面元素與最後面元素
RB_TreeNode<T> * copyTree(const RB_TreeNode<T>* oth, RB_TreeNode<T>* p, RB_TreeNode<T>*const& Guard);//拷貝
void distroy(RB_TreeNode<T>* root);//銷燬
int findindex(RB_TreeNode<T>* root, int num, RB_TreeNode<T>*& tar, int& index);
void relationGuard();
void printNode(RB_TreeNode<T> * outT);
RB_TreeNode<T>* _guard;
RB_TreeNode<T>* _root;
int _len;
keycompare com;
friend ostream& operator<<(ostream &out, RB_TreeNode<T> * outT);
};
////析構函數與構造函數
template<class T,class keycompare=mycom<T>>
RBTree<T,keycompare>::RBTree(const keycompare& comp=keycompare()):_len(0),com(comp), _guard(new RB_TreeNode<T>())
{
_guard->left = _guard;
_guard->right = _guard;
_root = _guard;
}
template<class T, class keycompare = mycom<T>>
RBTree<T, keycompare>::RBTree(const RBTree<T,keycompare>& oth):_guard(new RB_TreeNode<T>(0)),_len(oth._len){
_root = copyTree(oth._root, _guard,oth._guard);
relationGuard();
}
//移動構造函數
template<class T, class keycompare = mycom<T>>
RBTree<T, keycompare>::RBTree(RBTree<T, keycompare>&& oth):_len(oth._len), _guard(oth._guard), _root(oth._root) {
oth._root = NULL;
oth._guard = NULL;
}
template<class T, class keycompare = mycom<T>>
template<class _itr>
RBTree<T, keycompare>::RBTree(_itr begin,_itr end):_len(0), com(keycompare()), _guard(new RB_TreeNode<T>()), _root(_guard) {
while (begin != end)
insert(*(begin++));
}
template<class T, class keycompare = mycom<T>>
RBTree<T, keycompare>::~RBTree()
{
clear();
}
////操作符重載
template<class T, class keycompare = mycom<T>>
RBTree<T, keycompare>& RBTree<T, keycompare>::operator=(const RBTree<T, keycompare>& oth) {
clear();//在拷貝之前,先要釋放已有資源
_root = copyTree(oth._root, _guard);
return *this;
}
//當參數爲右值引用
template<class T, class keycompare = mycom<T>>
RBTree<T, keycompare>& RBTree<T, keycompare>::operator=(RBTree<T, keycompare>&& oth) {
clear();//在指向傳進來的節點之前,要先釋放原來的資源;
_root = oth.root;
return *this;
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::operator[] (int i) {
if (i<0||i >= _len) {
cout << "訪問越界" << endl;
throw;
}
RB_TreeNode<T>* tar = NULL;
findindex(_root, 0, tar, ++i);
return const_iterator(tar, _guard);
}
//判空,size,清除
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::clear() {
if (_root == NULL)
{
_len = 0;
return;
}
distroy(_root);
_root = NULL;
_len = 0;
}
template<class T, class keycompare = mycom<T>>
int RBTree<T, keycompare>::size()
{
return _len;
}
template<class T, class keycompare = mycom<T>>
bool RBTree<T, keycompare>::empty() {
return _len == 0;
}
template<class T, class keycompare = mycom<T>>
int RBTree<T, keycompare>::count(T val) {
RB_TreeNode<T>* pval = RBTree_serch(val,_root);
if (pval == _guard) return 0;
int num=1;
RB_TreeNode<T>* temp = pval->findFront(_guard);
while (temp!=_guard&&!com(temp->key, val) && !com(val, temp->key)) {
temp = temp->findFront(_guard);
++num;
}
temp = pval->findSucceed(_guard);
while (temp != _guard && !com(temp->key, val) && !com(val, temp->key)) {
temp = temp->findSucceed(_guard);
++num;
}
return num;
}
////各種插入與刪除操作
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::insert(T value)
{
RBTree_insert(value, false);
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::insert_unique(T value) {
RBTree_insert(value, true);
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::erase_unique(T value) {
RBerase(RBTree_serch(value, _root));
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::erase_equal(T value) {
RB_TreeNode<T>* tar = RBTree_serch(value, _root);
if (tar == _guard) return;
erase(findFandB(tar, true), ++findFandB(tar, false));
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::erase(const_iterator& l, const_iterator& r) {
while (l != r&&l != end())
erase(l++);
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::erase(const_iterator& start, int n) {
while (n--&&start != end()) erase(start++);
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::erase(const_iterator& it) {
RBerase(it.node);
}
///必要的迭代器
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::begin() {
return const_iterator(_guard->left, _guard);
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::end() {
return const_iterator(_guard, _guard);
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::back() {
return const_iterator(_guard->right, _guard);
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::start() {
return end();
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::find(T val) {
RB_TreeNode<T>* p = RBTree_serch(val, _root);
if (p == _guard) return end();
return findFandB(p, true);
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::findlast(T val) {
RB_TreeNode<T>* p = RBTree_serch(val, _root);
if (p == _guard) return end();
return findFandB(p, false);
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::lower_bound(T val) {
if (_len == 0) return end();
RB_TreeNode<T>* root = _root;
RB_TreeNode<T>* tmp = NULL;
while (root != _guard) {
tmp = root;
if (com(val, root->key))
root = root->left;
else if (com(root->key, val))
root = root->right;
else {
tmp = root;
break;
}
}
if (root == _guard) {
if (com(tmp->key, val))
return const_iterator(findSucceed(tmp), _guard);
else
return const_iterator(tmp, _guard);
}
/*if (root == _guard) {
if (com(val, tmp->key))
return const_iterator(findFront(tmp), _guard);
else
return const_iterator(tmp, _guard);
}*/
return findFandB(tmp, true);
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::upper_bound(T val) {
RB_TreeNode<T>* root = _root;
RB_TreeNode<T>* tmp = NULL;
while (root != _guard) {
tmp = root;
if (com(val, root->key))
root = root->left;
else if (com(root->key, val))
root = root->right;
else {
tmp = root;
break;
}
}
if (root == _guard) {
if (com(tmp->key, val))
return const_iterator(findSucceed(tmp), _guard);
else
return const_iterator(tmp, _guard);
}
return findFandB(tmp, false);
}
////後面都是爲了實現前面的接口的內部函數
template<class T, class keycompare = mycom<T>>
RB_TreeNode<T>* RBTree<T, keycompare>::guard() {
return _guard;
}
template<class T, class keycompare = mycom<T>>
RB_TreeNode<T> * RBTree<T, keycompare>::getroot()
{
return _root;
}
///插入節點後調整紅黑樹滿足紅黑樹五個特性
//////左旋
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::Left_Rotate(RB_TreeNode<T> * t)
{
if (t == _guard || t->right == _guard)
{
cout << "左旋節點或節點右孩子不應爲空" << endl;
return;
}
RB_TreeNode<T> * tmp = t->right;
tmp->p = t->p;
if (t->p == _guard)
{
_root = tmp;
}
else if (t == t->p->left)
t->p->left = tmp;
else
t->p->right = tmp;
t->p = tmp;
t->right = tmp->left;
if (tmp->left != _guard)
tmp->left->p = t;
tmp->left = t;
}
////右旋
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::Right_Rotate(RB_TreeNode<T> * t)
{
if (!t || !t->left)
{
cout << "右旋節點或節點左孩子不應爲空" << endl;
return;
}
RB_TreeNode<T> * tmp = t->left;
tmp->p = t->p;
if (t->p == _guard)
{
_root = tmp;
}
else if (t == t->p->left)
t->p->left = tmp;
else
t->p->right = tmp;
t->p = tmp;
t->left = tmp->right;
if (tmp->right != _guard)
tmp->right->p = t;
tmp->right = t;
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::RBTree_insert(T value, bool isunique) {
RB_TreeNode<T> * Tnode = new RB_TreeNode<T>(value, _guard);
RB_TreeNode<T> * tmp = _root;
RB_TreeNode<T> * Ptmp = _guard;
if (_root == _guard)//如果插入的節點是第一個節點,相當於初始化根節點
{
_root = Tnode;
_root->color = black;
_len++;
_guard->left = _root;
_guard->right = _root;
return;
}
//如果插入的節點小於最小值,直接插在最左邊,並更新最小值節點
if (com(value, _guard->left->key)) {
Tnode->p = _guard->left;
_guard->left->left = Tnode;
_guard->left = Tnode;
}
//如果插入的節點大於等於最大值,直接插在最右邊,更新最大值節點
else if (!com(value, _guard->right->key)) {
if (!com(_guard->right->key, value) && isunique) {
swap(_guard->right->key, tmp->key);
delete Tnode;
return;
}
Tnode->p = _guard->right;
_guard->right->right = Tnode;
_guard->right = Tnode;
}
else {
///以上三種情況都不屬於尋找合適的插入節點,就一直往下找,直到邊界條件(找到了空節點,在我這是_guard)
while (tmp != _guard)
{
Ptmp = tmp;
if (com(value, tmp->key))
tmp = tmp->left;
else if (com(tmp->key, value))
tmp = tmp->right;
else {
if (isunique) {
swap(Tnode->key, tmp->key);
delete Tnode;
return;
}
tmp = tmp->right;
}
}
///更新插入節點的父親,以及該父親的孩子須得指向它
Tnode->p = Ptmp;
if (com(Tnode->key, Ptmp->key))
Ptmp->left = Tnode;
else
Ptmp->right = Tnode;
}
///如果插入節點的父親是紅色,則違反了紅黑樹紅黑特性,需要調整
if (Tnode->p->color == red)
RBINSERT_Fixup(Tnode);
_len++;///別忘了更新元素數目
}
/////刪除節點
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::RBerase(RB_TreeNode<T>* node)
{
RB_TreeNode<T>* t = node;
if (t == _guard) return;
RB_TreeNode<T>* tmp;
if (t->left != _guard&&t->right != _guard)
{
///節點左右孩子都不是邊界節點,交換信息
RB_TreeNode<T>* succ = findSucceed(t);
if (t == t->p->left)
t->p->left = succ;
else
t->p->right = succ;
if (succ == succ->p->left)
succ->p->left = t;
else
succ->p->right = t;
swap(succ->p, t->p);
swap(succ->color, t->color);
swap(succ->left, t->left);
swap(succ->right, t->right);
succ->left->p = succ;
succ->right->p = succ;
if (t->left != _guard)
t->left->p = t;
if (t->right != _guard)
t->right->p = t;
if (succ->p == _guard) _root = succ;
//這裏其實最簡單的方法是交換兩個key然後直接刪除succ,但是這樣做會令原來指向succ的迭代器失效,所以要逐個交換。
}
///這裏就是的tmp就是我們需要跟刪除節點父親建立聯繫的孩子節點
if (t->left == _guard)
tmp = t->right;
else
tmp = t->left;
///如果刪除的是最小值或者最大值,要更新_guard孩子
if (t == _guard->left)
_guard->left = findSucceed(t);
if (t == _guard->right)
_guard->right = findFront(t);
if (t->p == _guard) _root = tmp;///如果是根,要及時更新根節點
else if (t == t->p->left)///tmp 取代原來t的位置
t->p->left = tmp;
else
t->p->right = tmp;
tmp->p = t->p;
if (t->color == black)///如果被刪除的節點是黑色,需要調整紅黑樹紅黑特性
{
RBDELETE_Fixup(tmp);
}
_len--;
delete t;
t = NULL;
return;
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::RBINSERT_Fixup(RB_TreeNode<T> * t)
{
RB_TreeNode<T> * tmp = t->p;
RB_TreeNode<T> * Pbra = _guard;
//出遞歸的條件,就是節點是黑色
while (tmp->color==red)
{
//這個就是我們討論的當插入節點是左孩子的時候
if (tmp == tmp->p->left)
{
Pbra = tmp->p->right;
///第一種情況 叔叔是紅色
if (Pbra!=_guard&&Pbra->color == red)
{
tmp->color = black;
tmp->p->color = red;
Pbra->color = black;
t = tmp->p;//當前節點變成祖父節點
tmp = t->p;//同時更新父節點爲祖父節點的父親節點
}
else
{
///叔叔是黑色
if (t == tmp->right)///插入節點是右孩子,左旋,變成第三種情況
{
Left_Rotate(tmp);
tmp = t;//注意這裏左旋之後,孩子父親角色換了
}
tmp->color = black;//tmp顏色變黑,達到出循環的條件
tmp->p->color = red;
Right_Rotate(tmp->p);
}
}
else//這邊是插入節點是右孩子的情況,與上面是對稱的
{
Pbra = tmp->p->left;
if (Pbra!=_guard&&Pbra->color == red)
{
tmp->color = black;
tmp->p->color = red;
Pbra->color = black;
t = tmp->p;
tmp = t->p;
}
else
{
if (t == tmp->left)
{
Right_Rotate(tmp);
tmp = t;
}
tmp->color = black;
tmp->p->color = red;
Left_Rotate(tmp->p);
}
}
if (tmp==_guard)//說明當前節點是根節點,因爲只有根節點的父節點是邊界節點_guard
{
///這裏其實可以直接將t的顏色變成黑色,然後直接出循環
tmp = t;
tmp->color = black;
}
}
}
///刪除節點後調整紅黑樹滿足紅黑樹五個特性
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::RBDELETE_Fixup(RB_TreeNode<T> * t)
{
RB_TreeNode<T> * w = NULL;
while (t!=_root&&t->color==black)
{
////要連接的孩子節點是左孩子的情況
if (t == t->p->left)
{
w = t->p->right;//兄弟節點
////第一種情況
if (w->color == red)///兄弟是紅色
{
///交換兄弟與父親的顏色,因爲兄弟顏色是紅色,父親肯定是黑色,所以直接賦值
t->p->color = red;
w->color = black;
Left_Rotate(t->p);
}
else
{
///兄弟右孩子是紅色,就是第四種情況
if (w->right->color == red)
{
w->color = t->p->color;
t->p->color = black;
w->right->color = black;
Left_Rotate(t->p);
t = _root;///這裏是爲了最後一句,出循環後要把t染成黑色,將t設置爲根節點,可以出循環,將根節點染黑沒影響
}
else if (w->left->color == red)///右孩子是黑色,左孩子紅色
{
w->color = red;
w->left->color = black;
Right_Rotate(w);
w = w->p;//別忘了右旋之後更新兄弟
}
else
{
///兩個孩子都是黑色,也就是第二種情況,把兄弟染紅,將另一重黑色往上推,也就是父親節點
w->color = red;
t = t->p;
}
}
}
///這邊是當前節點是右孩子的情況 完全對稱
else
{
w = t->p->left;
if (w->color == red)
{
t->p->color = red;
w->color = black;
Right_Rotate(t->p);
}
else
{
if (w->left != _guard&&w->left->color == red)
{
w->color = t->p->color;
t->p->color = black;
w->left->color = black;
Right_Rotate(t->p);
t = _root;
}
else if (w->right != _guard&&w->right->color == red)
{
w->color = red;
w->right->color = black;
Left_Rotate(w);
w = w->p;
}
else
{
w->color = red;
t = t->p;
}
}
}
}
t->color = black;///出循環要麼是t是紅色,要麼t是根節點,直接染黑。
}
/////以beginRoot爲根的子樹開始尋找節點
template<class T, class keycompare = mycom<T>>
RB_TreeNode<T>* RBTree<T, keycompare>::RBTree_serch(T value, RB_TreeNode<T>* beginRoot)
{
RB_TreeNode<T> * p = beginRoot;
while (p != _guard)
{
if (com(p->key, value))
p = p->right;
else if (com(value, p->key))
p = p->left;
else
return p;
}
return p;
}
///////尋找前驅
template<class T, class keycompare = mycom<T>>
RB_TreeNode<T>* RBTree<T, keycompare>::findFront(RB_TreeNode<T>* t)
{
return t->findFront(_guard);
}
/////尋找後繼
template<class T, class keycompare = mycom<T>>
RB_TreeNode<T>* RBTree<T, keycompare>::findSucceed(RB_TreeNode<T> * t)
{
return t->findSucceed(_guard);
}
template<class T, class keycompare = mycom<T>>
RB_TreeNode<T> * RBTree<T, keycompare>::copyTree(const RB_TreeNode<T>* oth, RB_TreeNode<T>* p, RB_TreeNode<T>* const& Guard) {
if (oth == Guard) return _guard;
RB_TreeNode<T>* root = new RB_TreeNode<T>(oth->key);
root->color = oth->color;
root->p = p;
root->left = copyTree(oth->left, root, Guard);
root->right = copyTree(oth->right, root, Guard);
return root;
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::distroy(RB_TreeNode<T>* root) {
if (root == _guard) return;
distroy(root->left);
distroy(root->right);
delete root;
}
template<class T, class keycompare = mycom<T>>
int RBTree<T, keycompare>::findindex(RB_TreeNode<T>* root, int num, RB_TreeNode<T>*& tar, int& index) {
if (tar != NULL || root == _guard) return 0;
int l = findindex(root->left, 0, tar, index);
if (l + 1 + num == index) {
tar = root;
return 0;
}
int r = findindex(root->right, l + 1+num, tar, index);
return l + r + 1;
}
template<class T, class keycompare = mycom<T>>
rbtree_iterator<T, const T&, const T*> RBTree<T, keycompare>::findFandB(RB_TreeNode<T>* target, bool isForward) {
if (isForward) {
RB_TreeNode<T>* succ = findFront(target);
while (succ != _guard && !com(target->key, succ->key) && !com(succ->key, target->key)) {
target = succ;
succ = findFront(succ);
}
return const_iterator(target, _guard);
}
else {
RB_TreeNode<T>* succ = findSucceed(target);
while (succ != _guard && !com(target->key, succ->key) && !com(succ->key, target->key)) {
target = succ;
succ = findSucceed(succ);
}
return const_iterator(target, _guard);
}
return const_iterator(_guard, _guard);
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::relationGuard() {
RB_TreeNode<T>* node = _root;
while (node->left != _guard)
node = node->left;
_guard->left = node;
node = _root;
while (node->right != _guard)
node = node->right;
_guard->right = node;
}
////自己測試用的函數
/////前序遍歷
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::pre_traverse()
{
}
////中序遍歷
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::mid_traverse(T* pt=NULL)
{
RB_TreeNode<T> * p = _root;
stack<RB_TreeNode<T> *> s;
while (true)
{
while (p!=_guard)
{
s.push(p);
p = p->left;
}
if (s.empty()) break;
p = s.top();
if (pt == NULL)
cout << p->key << " ";
else
*(pt++) = p->key;
s.pop();
p = p->right;
}
cout << endl;
}
/////後序遍歷
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::post_traverse() {
}
/////層次遍歷
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::print() {
RB_TreeNode<T> * pRoot = _root;
if (!pRoot) return;
vector<queue<RB_TreeNode<T> *> > vq(2);
int index = 0;
vq[index].push(pRoot);
while (!vq[index].empty() || !vq[1 - index].empty())
{
while (!vq[index].empty())
{
RB_TreeNode<T> * p = vq[index].front();
vq[index].pop();
printNode(p);
if (p->left != _guard)
vq[1 - index].push(p->left);
if (p->right != _guard)
vq[1 - index].push(p->right);
}
cout << endl;
index = 1 - index;
}
}
template<class T, class keycompare = mycom<T>>
void RBTree<T, keycompare>::printNode(RB_TreeNode<T> * outT) {
if (outT == _guard) return ;
cout << "[" << " " << "key:" << outT->key << " ";
if (outT->color == 0)
cout << "color:" << "red" << " ";
else
cout << "color:" << "black" << " ";
if (outT->left != _guard)
cout << "left:" << outT->left->key << " ";
if (outT->right != _guard)
cout << "right:" << outT->right->key << " ";
if (outT->p != _guard)
cout << "parent:" << outT->p->key << " ";
cout << "]";
}
template<typename T>
ostream& operator<<(ostream &out, RB_TreeNode<T> * outT)
{
return out;
}