深入紅黑樹插入刪除,並寫出一個自己的“set”(速度比STL快很多 )

寫一個自己想要的“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;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章