国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

編寫html的軟件有哪些網(wǎng)站優(yōu)化培訓(xùn)班

編寫html的軟件有哪些,網(wǎng)站優(yōu)化培訓(xùn)班,wordpress 安裝windows,ppt 做的最好的網(wǎng)站有哪些紅黑樹的概念 紅黑樹(Red-Black Tree)同AVL樹一樣, 也是一種自平衡的二叉搜索樹, 但在每個(gè)結(jié)點(diǎn)上增加一個(gè)存儲(chǔ)位表示結(jié)點(diǎn)的顏色, 可以是Red或Black, 通過對(duì)任何一條從根到葉子的路徑上各個(gè)結(jié)點(diǎn)著色方式的限制, 紅黑樹確保沒有一條路徑會(huì)比其他路徑長(zhǎng)出倆…

紅黑樹的概念

紅黑樹(Red-Black Tree)同AVL樹一樣, 也是一種自平衡的二叉搜索樹,?但在每個(gè)結(jié)點(diǎn)上增加一個(gè)存儲(chǔ)位表示結(jié)點(diǎn)的顏色,?可以是RedBlack, 通過對(duì)任何一條從根到葉子的路徑上各個(gè)結(jié)點(diǎn)著色方式的限制, 紅黑樹確保沒有一條路徑會(huì)比其他路徑長(zhǎng)出倆倍,因而是接近平衡的. (最長(zhǎng)路徑也不會(huì)超出最短路徑的兩倍, 因此紅黑樹的平衡性要求相對(duì)寬松. 沒有AVL樹那樣嚴(yán)格)

紅黑樹的性質(zhì)(重要)

1. 每個(gè)結(jié)點(diǎn)不是紅色就是黑色
2. 根結(jié)點(diǎn)是黑色的
3. 如果一個(gè)結(jié)點(diǎn)是紅色的, 則它的兩個(gè)孩子結(jié)點(diǎn)是黑色的(不能有連續(xù)的紅色結(jié)點(diǎn)).
4. 對(duì)于每個(gè)結(jié)點(diǎn), 從該結(jié)點(diǎn)到其所有后代葉結(jié)點(diǎn)的簡(jiǎn)單路徑上,均包含相同數(shù)目的黑色結(jié)點(diǎn).
5. 每個(gè)葉子結(jié)點(diǎn)都是黑色的(此處的葉子結(jié)點(diǎn)指的是空結(jié)點(diǎn)NIL).

為什么滿足上面的性質(zhì), 紅黑樹就能保證:其最長(zhǎng)路徑中節(jié)點(diǎn)個(gè)數(shù)不會(huì)超過最短路徑節(jié)點(diǎn)個(gè)數(shù)的兩倍??

?我們可以先來分析一種極端的情況,如果一顆紅黑樹有紅有黑,?那它的最短路徑一定是一條全黑的路徑,?想要獲取最長(zhǎng)的路徑, 就可以在此基礎(chǔ)上繼續(xù)添加紅色結(jié)點(diǎn), 因?yàn)橹灰t色結(jié)點(diǎn)不相鄰, 添加紅色結(jié)點(diǎn)能保證路徑的黑色結(jié)點(diǎn)數(shù)不變, 那就可以創(chuàng)建一條一黑一紅一黑一紅..的路徑, 這條路徑就是最長(zhǎng)的路徑,?所以最長(zhǎng)路徑最多是最短路徑的兩倍, 不可能超過最短路徑兩倍, 最長(zhǎng)的路徑都超不過其它的路徑更超不過.

另一個(gè)問題, 性質(zhì)5中每個(gè)葉子結(jié)點(diǎn)都是黑色的(此處的葉子結(jié)點(diǎn)指的是空結(jié)點(diǎn), 也被稱為NIL節(jié)點(diǎn)), 有什么用??

?這個(gè)紅黑樹有多少條路徑?

如果不帶空的話, 我們可能會(huì)認(rèn)為有5條,?但是這里計(jì)算路徑其實(shí)應(yīng)該走到空(NIL),所以正確的應(yīng)該是有11條路徑,?我們可以認(rèn)為這條規(guī)則就是為了更好的幫我們區(qū)分不同路徑的。?

結(jié)點(diǎn)的黑高(黑色高度):從某結(jié)點(diǎn)出發(fā)(不含該結(jié)點(diǎn))到達(dá)任一空葉結(jié)點(diǎn)的路徑上經(jīng)過的黑結(jié)點(diǎn)總數(shù) .


有了AVL樹, 為啥還要有紅黑樹?

對(duì)于一棵紅黑樹來說, 如果它里面全部的黑色結(jié)點(diǎn)一共有N個(gè)的話, 那它的最短路徑長(zhǎng)度就差不多是log{_{2}}^{N}, 然后整棵樹的節(jié)點(diǎn)數(shù)量就是在N-2N之間

設(shè)紅黑樹的高度為h, 總結(jié)點(diǎn)數(shù)為n,?首先, 從任意節(jié)點(diǎn)出發(fā), 到其子樹的葉子節(jié)點(diǎn)的路徑中黑色節(jié)點(diǎn)的數(shù)量稱為該節(jié)點(diǎn)的黑高, 即bh,?設(shè)根節(jié)點(diǎn)為T,那么根節(jié)點(diǎn)的黑高就是bh(T), 假設(shè)一棵紅黑樹全部都是黑色節(jié)點(diǎn),?那么它的黑高bh(T)就是它的樹高,我們可得這樣一棵樹的結(jié)點(diǎn)數(shù)為(根據(jù)滿二叉樹的高度與節(jié)點(diǎn)數(shù)量的關(guān)系):n = 2_{}^{bh(T)}-1,?我們還要考慮紅色節(jié)點(diǎn),?所以在此基礎(chǔ)上加上紅色節(jié)點(diǎn)的數(shù)量, 那么不論加幾個(gè)紅色節(jié)點(diǎn), 只要增加, 一定滿足下式:?n >= 2_{}^{bh(T)}-1

根據(jù)紅黑樹的性質(zhì),我們可知根節(jié)點(diǎn)的黑高bh(T)至少為h/2? ??(h為樹高),也就是說:?bh(T) >= h/2, 所以n >= 2_{}^{h/2} -1, 所以?h > = 2log{_{2}}^{n+1}.

AVL樹
平衡標(biāo)準(zhǔn)比較嚴(yán)格:每個(gè)左右子樹的高度差不超過1
最大高度是 1.44 ? log2 n + 2 ? 1.328(100W個(gè)節(jié)點(diǎn),AVL樹最大樹高28)
搜索、添加、刪除都是 O(logn) 復(fù)雜度,其中添加僅需 O(1) 次旋轉(zhuǎn)調(diào)整、刪除最多需要 O(logn) 次旋轉(zhuǎn)調(diào)整
紅黑樹
平衡標(biāo)準(zhǔn)比較寬松:沒有一條路徑會(huì)大于其他路徑的2倍
最大高度是 2 ? log2(n + 1)( 100W個(gè)節(jié)點(diǎn),紅黑樹最大樹高40)
搜索、添加、刪除都是 O(logn) 復(fù)雜度,其中添加、刪除都僅需 O(1) 次旋轉(zhuǎn)調(diào)整
如何選擇
搜索的次數(shù)遠(yuǎn)遠(yuǎn)大于插入和刪除,選擇AVL樹;搜索、插入、刪除次數(shù)幾乎差不多,選擇紅黑樹
相對(duì)于AVL樹來說,紅黑樹犧牲了部分平衡性以換取插入/刪除操作時(shí)少量的旋轉(zhuǎn)操作,整體來說性能要優(yōu)于AVL樹
紅黑樹的平均統(tǒng)計(jì)性能優(yōu)于AVL樹,實(shí)際應(yīng)用中更多選擇使用紅黑樹


紅黑樹結(jié)構(gòu)的定義

先來定義一下紅黑樹的結(jié)構(gòu):?

結(jié)點(diǎn)的顏色我們可以用一個(gè)枚舉:?

enum COLOR
{RED,BLACK
};

結(jié)點(diǎn)的結(jié)構(gòu):

template<class T>
struct RBTreeNode
{RBTreeNode<T>* _parent;RBTreeNode<T>* _right;RBTreeNode<T>* _left;T _val;COLOR _col;RBTreeNode(const T& val): _parent(nullptr), _right(nullptr), _left(nullptr), _val(val), _col(RED){}};

這里結(jié)點(diǎn)的顏色我們默認(rèn)給的是紅色, 為什么要選擇紅色, 黑色不可以嗎????

如果我們插入一個(gè)新結(jié)點(diǎn)給的是黑色, 那它一定會(huì)違反上面提到的紅黑樹的性質(zhì)——每條路徑上黑色結(jié)點(diǎn)的數(shù)量一致:?

因?yàn)樵瓉砻織l路徑黑色結(jié)點(diǎn)數(shù)量是相同的,現(xiàn)在新插入一個(gè)黑色結(jié)點(diǎn)的話, 那插入的這條路徑會(huì)增加一個(gè)黑色結(jié)點(diǎn), 但是其它路徑數(shù)量不變, 所以其它所有的路徑黑色結(jié)點(diǎn)數(shù)量都和這一條不相等, 這樣再調(diào)整就比較麻煩了, 相當(dāng)于影響了這棵樹"全家"。

那如果我們插入結(jié)點(diǎn)默認(rèn)給紅色呢?
紅色的話要看具體情況了:

如果它的父親是黑色, 那就沒問題, 不需要進(jìn)行什么處理:


如果插入一個(gè)紅色結(jié)點(diǎn), 但是它的父親也是紅色, 那就出事了, 因?yàn)榧t黑樹里面不能出現(xiàn)連續(xù)的紅色結(jié)點(diǎn),那這種情況就需要調(diào)整了:

但是這樣的調(diào)整的代價(jià)相對(duì)來說比較小, 因?yàn)榭赡懿恍枰膭?dòng)全局, 只是改變一個(gè)局部, 下面再具體說.

樹的結(jié)構(gòu):?

template<class T>
class RBTree
{
public://成員函數(shù)
private:RBTreeNode<T>* _root = nullptr;
};

?插入

由于紅黑樹也是一種二叉搜索樹, 是在二叉搜索樹的基礎(chǔ)上加上其平衡限制條件來實(shí)現(xiàn)平衡,所以紅黑樹插入的邏輯也根搜索二叉樹一樣:

如果插入的是根結(jié)點(diǎn), 根結(jié)點(diǎn)要手動(dòng)設(shè)置為黑色.?

?

bool Insert(const pair<K,V>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_col= BLACK;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);//cur->_col = RED; //默認(rèn)cur就是紅色if (parent->_kv.first > kv.first){parent->_left = cur;cur->_parent = parent; //記得要鏈接父親}else if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent; //記得要鏈接父親}elseassert(false);//下面是調(diào)整//....
}

根據(jù)顏色開始調(diào)整

對(duì)于紅黑樹來說, 插入新結(jié)點(diǎn)之后, 我們要檢查紅黑樹的性質(zhì)是否遭到破壞, 如果遭到破壞的話, 就需要進(jìn)行相應(yīng)的調(diào)整, 因?yàn)樾鹿?jié)點(diǎn)的默認(rèn)顏色是紅色, 因此:

如果其雙親節(jié)點(diǎn)的顏色是黑色, 沒有違反紅黑樹任何性質(zhì), 則不需要調(diào)整;
但當(dāng)新插入節(jié)點(diǎn)的父親節(jié)點(diǎn)是紅色時(shí), 就違反了性質(zhì)不能有連續(xù)紅色結(jié)點(diǎn)出現(xiàn),?此時(shí)需要對(duì)紅黑樹的顏色進(jìn)行調(diào)整:

?約定:?cur為當(dāng)前節(jié)點(diǎn),p為父節(jié)點(diǎn),g為祖父節(jié)點(diǎn),u為叔叔節(jié)點(diǎn)

而出現(xiàn)連續(xù)的紅色結(jié)點(diǎn)的情況可以分為2種:

1. cur為紅, p為紅, g為黑, u存在且為紅?

2. cur為紅, p為紅, g為黑, u不存在或?yàn)楹?/strong>

可以看到關(guān)鍵就在于叔叔結(jié)點(diǎn), 為什么? 因?yàn)榈竭@種情況了cur和parent此時(shí)一定是紅色, grandfather結(jié)點(diǎn)一定是黑色, 唯一有區(qū)別的只是叔叔結(jié)點(diǎn).


情況一: cur為紅,p為紅,g為黑,u存在且為紅?

?

解決方式:將p,u改為黑, g改為紅, 然后把g當(dāng)成cur, 繼續(xù)向上調(diào)整。?

??

??

可以看到叔叔為紅的這種情況下只需要調(diào)整顏色就能又滿足規(guī)則.

可以簡(jiǎn)單討論一下子樹路徑黑結(jié)點(diǎn)和為1和2時(shí)候共有幾種情況:?

當(dāng)a,b,c,d,e都是0的時(shí)候,有四種情況:

??

當(dāng)a,b,c,d,e都是1的時(shí)候:

?

while (parent && parent->_col == RED)
{Node* grandparent = parent->_parent;//parent在grandparent的左if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}}//如果parent在grandparent的右,邏輯類似else if (parent == grandparent->_right){Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}}_root->_col = BLACK;//不管中間調(diào)了多少次,最后的根一定是黑,//如果被調(diào)整到根變紅了,需要調(diào)為黑,如果沒調(diào)到,重新賦值一遍也沒有影響
}

parent顏色為黑不需要單獨(dú)去判斷, 因?yàn)楸緛砭筒恍枰魏尾僮? 根本不會(huì)進(jìn)入循環(huán).


情況二: ?cur為紅,p為紅,g為黑,u不存在/u存在且為黑

??

說明: u的情況有兩種

1.如果u節(jié)點(diǎn)不存在, 則cur一定是新插入節(jié)點(diǎn), 因?yàn)榇藭r(shí)c,a,b,d,e都是空, 因?yàn)橐獫M足一個(gè)路徑的黑色結(jié)點(diǎn)個(gè)數(shù)相同.

?

2.如果u節(jié)點(diǎn)存在, 則其一定是黑色的, 那么cur節(jié)點(diǎn)原來的顏色一定是黑色的, 上面看到其是紅色的原因是因?yàn)閏ur的子樹在調(diào)整的過程中將cur節(jié)點(diǎn)的顏色由黑色改成紅色。

?

在這里又可以再細(xì)分為兩種子情況:

1. p為g的左孩子,cur為p的左孩子(左左)和p為g的右孩子, cur為p的右孩子(右右).

2.? p為g的左孩子,cur為p的右孩子(左右)和p為g的右孩子, cur為p的左孩子(右左).


1.左左和右右?

那對(duì)于這種情況我們要進(jìn)行的單旋轉(zhuǎn)+變色.

旋轉(zhuǎn):?

為什么要旋轉(zhuǎn)?

因?yàn)檫@種情況的話最長(zhǎng)路徑有可能已經(jīng)超過最短路徑的兩倍了, 比如上面這個(gè)圖如果如果d/e是空的話就已經(jīng)超過了, 所以要先旋轉(zhuǎn)降高度, 再去調(diào)整顏色使它符合紅黑樹.

進(jìn)行什么旋轉(zhuǎn)呢?

那就要看具體情況了, 其實(shí)還是我們AVL樹那里的四種情況:

當(dāng)前我們是 p為g的左孩子, cur為p的左孩子, 是在較高左子樹的左側(cè)插入(左左), 所以要進(jìn)行的旋轉(zhuǎn)是右單旋;

同理p為g的右孩子, cur為p的右孩子,是在較高右子樹的右側(cè)插入(右右),進(jìn)行左單旋.

變色:

變色的話不論那種旋轉(zhuǎn)是統(tǒng)一的:p、g變色–p變黑,g變紅

?

為什么不直接把cur變黑呢?

這樣也滿足路徑黑結(jié)點(diǎn)和保持不變啊:?

??

此時(shí)parent的顏色又變成了紅色, 又需要再繼續(xù)向上調(diào)整, 而一開始的方法中parent調(diào)整完就是黑的, 就結(jié)束了, 不需要再向上調(diào)整, 更簡(jiǎn)便!

代碼:?

while (parent && parent->_col == RED)
{Node* grandparent = parent->_parent;//parent在grandparent的左if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_left){rotateR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}}}//parent在grandparent的左else if (parent == grandparent->_right){Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){rotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}}}_root->_col = BLACK;
}

這里的旋轉(zhuǎn)復(fù)用AVL的旋轉(zhuǎn)即可, 去掉更新平衡因子的部分.?


2.左右和右左

雙旋+變色?

前提條件根上面一樣,還是cur為紅,p為紅,g為黑,u不存在/u存在且為黑?

''

進(jìn)行什么旋轉(zhuǎn)呢??

1.p為g的左孩子,cur為p的右孩子,則針對(duì)p做左單旋, g作右單旋
2.相反,p為g的右孩子,cur為p的左孩子,則針對(duì)p做右單旋, g作左單旋.

以左右單旋圖中為例, 先進(jìn)行一個(gè)左單旋:?

再進(jìn)行一個(gè)右單旋:?

?再變色:

這樣就調(diào)整好了?

代碼:?

while (parent && parent->_col == RED)
{Node* grandparent = parent->_parent;//parent在grandparent的左if (parent == grandparent->_left){Node* uncle = grandparent->_right;//叔叔存在且為紅直接變色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}//叔叔不存在或者叔叔是黑進(jìn)行旋轉(zhuǎn)else{/右單旋if (cur == parent->_left){rotateR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//左右雙旋else if (cur == parent->_right){rotateL(parent);rotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;}}}//parent在grandparent的左else if (parent == grandparent->_right){//叔叔存在且為紅直接變色Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}//叔叔不存在或者叔叔是黑進(jìn)行旋轉(zhuǎn)else{//左單旋if (cur == parent->_right){rotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//右左雙旋else if (cur == parent->_left){rotateR(parent);rotateL(grandparent);grandparent->_col = RED;cur->_col = BLACK;}}}_root->_col = BLACK;
}

紅黑樹的測(cè)試

驗(yàn)證其為搜索二叉樹

首先我們還是先來驗(yàn)證他是否是二叉搜索樹,看它中序是否有序就行了:

void InOrderPrint()
{_InOrder(_root);
}void _InOrder(Node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);
}
int main()
{//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };RBTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));}t.InOrderPrint();cout << endl;return 0;
}

順序是正確的


?驗(yàn)證其是否平衡且滿足紅黑樹性質(zhì)

如何判斷它是否滿足是一棵紅黑樹呢?

其實(shí)就是去檢查那幾條規(guī)則(性質(zhì)):

1.首先結(jié)點(diǎn)顏色要么是黑色, 要么是紅色, 這沒什么好檢查的。
2.然后根結(jié)點(diǎn)必須是黑色,?這個(gè)可以檢查一下,如果根結(jié)點(diǎn)不是黑色(是紅色)直接就不符合了

3.然后如果出現(xiàn)連續(xù)的紅色結(jié)點(diǎn), 那也不符合。
那怎么檢查有沒有出現(xiàn)連續(xù)紅色結(jié)點(diǎn)呢?
我們可以去遍歷這棵樹, 然后遇到紅色結(jié)點(diǎn)判斷它的孩子是不是紅色結(jié)點(diǎn), 如果存在紅色結(jié)點(diǎn)它的孩子也是紅色, 那就不符合, 這樣可以,但是不太好, 因?yàn)楹⒆拥脑捯獧z查兩個(gè),而且結(jié)點(diǎn)的孩子有還有可能不存在, 為空, 那還得再加一個(gè)判斷。
所以我們可以這樣做: 遍歷遇到紅色結(jié)點(diǎn)我們?nèi)タ此母赣H, 如果它的父親也為紅色那就不行。而判斷父親的話, 只有根結(jié)點(diǎn)沒有父親, 但是根結(jié)點(diǎn)是黑色的也不會(huì)去檢查它。

bool IsBalance()
{if (_root == nullptr)return true;if (_root->_col == RED)return false;return _Check(_root);
}bool _Check(Node* root)
{if (root == nullptr){return true;}if (root->_col == RED && root->_parent->_col == RED)return false;return _Check(root->_left, blacknum, ref)&& _Check(root->_right, blacknum, ref);
}

然后還剩一個(gè), 我們要檢查每條路徑黑色結(jié)點(diǎn)數(shù)量是否相等,?存在不相等的情況就不符合。
那這個(gè)要如何檢查呢?
我們可以先求出一條路徑的黑色結(jié)點(diǎn)數(shù)量, 把它作為基準(zhǔn)值, 然后再遞歸求出每條路徑的黑色結(jié)點(diǎn)數(shù)量和它比較, 如果存在不相等的情況, 就不符合, 不用管這個(gè)基準(zhǔn)值是不是正確的, 只要其他路徑和這個(gè)值不相同, 那就不符合.

bool IsBalance()
{if (_root == nullptr)return true;if (_root->_col == RED)return false;//找基準(zhǔn)值,這里以最左路為基準(zhǔn)Node* cur = _root;int ref = 0;while (cur){if (cur->_col == BLACK){ref++;}cur = cur->_left;}//定義一個(gè)blacknum來記錄路徑的黑色結(jié)點(diǎn)數(shù)目int blacknum = 0;return _Check(_root, blacknum,ref);
}bool _Check(Node* root,int blacknum, const int ref)
{if (root == nullptr){//root為空說明該路徑已經(jīng)找完,開始比較blacknum和ref,不相等就不符合if (blacknum != ref)return false;return true;}//如果節(jié)點(diǎn)是黑的blacknum就++if (root->_col == BLACK)blacknum++;//結(jié)點(diǎn)是紅色判斷它與父親結(jié)點(diǎn)是否為連續(xù)的紅if (root->_col == RED && root->_parent->_col == RED)return false;//繼續(xù)判斷左右子樹return _Check(root->_left, blacknum, ref)&& _Check(root->_right, blacknum, ref);
}

?注意這里的blacknum傳遞的非常巧妙, 因?yàn)槊恳粚拥腷lacknum都是獨(dú)立的, 所以向下一層傳遞blacknum的后blacknum的修改不會(huì)影響上一層, 為什么不想去影響上一層呢? 因?yàn)樯弦粚拥腷lacknum傳遞給了左子樹后還要傳遞給右子樹進(jìn)行判斷, 在左子樹中修改了上一層的值那再傳給右子樹就一定錯(cuò)了.


大量隨機(jī)數(shù)構(gòu)建紅黑樹進(jìn)行測(cè)試?

int main()
{const int N = 10000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand());}size_t begin2 = clock();RBTree<int, int> t;for (auto e : v){t.Insert(make_pair(e, e));}size_t end2 = clock();cout << "Insert_time:" << end2 - begin2 << endl;cout << t.IsBalance() << endl;return 0;
}

?


插入和查找的時(shí)間測(cè)試:?

Node* Find(const pair<K, V>& kv)
{Node* cur = _root;while (cur){if (kv.first > cur->_kv.first){cur = cur->_right;}else if (kv.first < cur->_kv.first){cur = cur->_left;}else{return cur;}}return nullptr;
}
int main()
{const int N = 100000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand());}size_t begin2 = clock();RBTree<int, int> t;for (auto e : v){t.Insert(make_pair(e, e));}size_t end2 = clock();size_t begin1 = clock();for (auto e : v){t.Find(make_pair(e,e));}size_t end1 = clock();cout << "Find_time:" << end1 - begin1 << endl;cout << "Insert_time:" << end2 - begin2 << endl;cout << "是否平衡:"<<t.IsBalance() << endl;return 0;
}

?


插入相同數(shù)量隨機(jī)數(shù)比較AVL樹和紅黑樹的高度?

void test3()
{const int N = 100000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand()+i);}RBTree<int, int> rbt;AVLTree<int, int> avlt;for (auto e : v){rbt.Insert(make_pair(e, e));avlt.Insert(make_pair(e, e));}cout << "插入了" << rbt.Size() << "個(gè)值" << endl;cout << "紅黑樹高度: " << rbt.Height()<<endl;cout << "AVL樹高度: " << avlt.Height() << endl;}

當(dāng)N為10w:?

插入10萬個(gè)數(shù)據(jù), 對(duì)產(chǎn)生的隨機(jī)數(shù)都加個(gè)i(減少重復(fù)值), 我們看到就有一些差異了?

當(dāng)N為100w:

?

100w個(gè)數(shù)據(jù)的差異就更大了, 還是紅黑樹要高一點(diǎn)

可以發(fā)現(xiàn)AVL樹對(duì)平衡的控制是比較嚴(yán)格的, 而紅黑樹是相對(duì)寬松的。?


紅黑樹的刪除

簡(jiǎn)單分析:

刪除節(jié)點(diǎn)一定都在最后一到兩層, 因?yàn)樯蠈佣伎梢蕴娲氯?

結(jié)點(diǎn)有紅色節(jié)點(diǎn)和黑色節(jié)點(diǎn), 我們就以刪除節(jié)點(diǎn)的顏色來區(qū)分刪除操作的所有情況

刪除紅色節(jié)點(diǎn)

如果刪除的節(jié)點(diǎn)是紅色直接刪除, 不用作任何調(diào)整。因?yàn)閯h除最后一層的紅色節(jié)點(diǎn), 并沒有影響紅黑樹的任何性質(zhì)。

刪除黑色節(jié)點(diǎn)

有3種情況:

1. 擁有 2 個(gè)紅色子節(jié)點(diǎn)的黑色節(jié)點(diǎn)

不可能被直接刪除,因?yàn)闀?huì)找它的子節(jié)點(diǎn)替代刪除,因此不用考慮這種情況

2. 擁有 1 個(gè)紅色子節(jié)點(diǎn)的黑色節(jié)點(diǎn)

修復(fù)步驟總結(jié):

  1. 用刪除節(jié)點(diǎn)的唯一子節(jié)點(diǎn)對(duì)其進(jìn)行替代
  2. 將替代節(jié)點(diǎn)染成黑色

3. 黑色葉子節(jié)點(diǎn)

1.?刪除節(jié)點(diǎn)為根節(jié)點(diǎn),?直接刪除該節(jié)點(diǎn), 無需做其他操作。

2. 刪除節(jié)點(diǎn)的兄弟節(jié)點(diǎn)為黑色?

2.1兄弟節(jié)點(diǎn)至少有1個(gè)紅色子節(jié)點(diǎn)

? ? ? ? 2.1.1?兄弟節(jié)點(diǎn)有一個(gè)右子節(jié)點(diǎn):

? ? ? ? 2.1.2 兄弟節(jié)點(diǎn)有一個(gè)左子節(jié)點(diǎn):

? ? ? ? 2.1.3?兄弟節(jié)點(diǎn)有兩個(gè)左右子節(jié)點(diǎn):

修復(fù)步驟總結(jié):

? ? ? ? 1 進(jìn)行旋轉(zhuǎn)操作

? ? ? ? 2 旋轉(zhuǎn)之后的中心節(jié)點(diǎn)繼承父節(jié)點(diǎn)(刪除節(jié)點(diǎn)的父節(jié)點(diǎn))的顏色

? ? ? ? 3 旋轉(zhuǎn)之后的左右節(jié)點(diǎn)染為黑色

2.2?兄弟節(jié)點(diǎn)沒有紅色子節(jié)點(diǎn)

? ? ? ? 2.2.1父節(jié)點(diǎn)為紅色

? ? ? ? 2.2.2父節(jié)點(diǎn)為黑色

修復(fù)步驟總結(jié):

  1. 父節(jié)點(diǎn)向下與兄弟節(jié)點(diǎn)進(jìn)行合并
  2. 將兄弟染成紅色、父節(jié)點(diǎn)染成黑色即可修復(fù)紅黑樹性質(zhì)
    • 如果父節(jié)點(diǎn)是黑色,直接將父節(jié)點(diǎn)當(dāng)成被刪除的節(jié)點(diǎn)處理,來修復(fù)父節(jié)點(diǎn)的下溢情況

3.?刪除節(jié)點(diǎn)的兄弟節(jié)點(diǎn)為紅色? ??

修復(fù)步驟總結(jié):

  1. 兄弟節(jié)點(diǎn)染成 BLACK, 父節(jié)點(diǎn)染成染成 RED, 對(duì)父節(jié)點(diǎn)進(jìn)行右旋
  2. 于是又回到兄弟節(jié)點(diǎn)是黑色的情況(侄子節(jié)點(diǎn)變?yōu)樾值芄?jié)點(diǎn)),繼續(xù)使用兄弟節(jié)點(diǎn)為黑色的方法進(jìn)行修復(fù)

?具體可查看:

【精選】【數(shù)據(jù)結(jié)構(gòu)】史上最好理解的紅黑樹講解,讓你徹底搞懂紅黑樹_小七mod的博客-CSDN博客


完整代碼:

#pragma once
#include<assert.h>
enum COLOR
{RED,BLACK
};template<class K, class V>
struct RBTreeNode
{RBTreeNode<K,V>* _parent;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _left;pair<K,V> _kv;COLOR _col;RBTreeNode(const pair<K,V>& kv): _parent(nullptr), _right(nullptr), _left(nullptr), _kv(kv), _col(RED){}};template<class K,class V>
class RBTree
{typedef RBTreeNode<K,V> Node;
public:bool Insert(const pair<K,V>& kv){if (_root == nullptr){_root = new Node(kv);_root->_col= BLACK;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);//cur->_col = RED;if (parent->_kv.first > kv.first){parent->_left = cur;cur->_parent = parent;}else if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}elseassert(false);//插入完成, 調(diào)整顏色parent的顏色是黑,不需要調(diào)整//if (parent->_col == BLACK)//{//	return true;//}//parent的顏色是紅,需要調(diào)整while (parent && parent->_col == RED){Node* grandparent = parent->_parent;//parent在grandparent的左//		 g			      g//   p	u		   p 	  u//c					  cif (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else{//		 g//   p	u//cif (cur == parent->_left){rotateR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//		 g//   p	u//      celse if (cur == parent->_right){rotateL(parent);rotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;}}}//parent在grandparent的左//		 g			      g//   u 	p		   u 	  p//				c			celse if (parent == grandparent->_right){Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else{//		 g//   u		p//				cif (cur == parent->_right){rotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//		 g//   u		p//      celse if (cur == parent->_left){rotateR(parent);rotateL(grandparent);grandparent->_col = RED;cur->_col = BLACK;}}}_root->_col = BLACK;}return true;}void InOrderPrint(){_InOrder(_root);}bool IsBalance(){if (_root == nullptr)return true;if (_root->_col == RED)return false;Node* cur = _root;int ref = 0;while (cur){if (cur->_col == BLACK){ref++;}cur = cur->_left;}int blacknum = 0;return _Check(_root, blacknum,ref);}Node* Find(const pair<K, V>& kv){Node* cur = _root;while (cur){if (kv.first > cur->_kv.first){cur = cur->_right;}else if (kv.first < cur->_kv.first){cur = cur->_left;}else{return cur;}}return nullptr;}int Height(){return _Height(_root);}private:Node* _root = nullptr;bool _Check(Node* root,int blacknum, const int ref){if (root == nullptr){if (blacknum != ref)return false;return true;}if (root->_col == BLACK)blacknum++;if (root->_col == RED && root->_parent->_col == RED)return false;return _Check(root->_left, blacknum, ref)&& _Check(root->_right, blacknum, ref);}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}int _Height(Node* root){if (root == nullptr)return 0;int leftH = _Height(root->_left);int rightH = _Height(root->_right);return leftH > rightH ? leftH + 1 : rightH + 1;}void rotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;Node* parentParent = parent->_parent;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_right)parentParent->_right = subR;else if (parent == parentParent->_left)parentParent->_left = subR;subR->_parent = parentParent;}}void rotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;Node* parentParent = parent->_parent;subL->_right = parent;parent->_left = subLR;parent->_parent = subL;if (subLR)subLR->_parent = parent;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subL;}else if (parentParent->_right == parent){parentParent->_right = subL;}subL->_parent = parentParent;}}
};

?test.cpp:

#include <iostream>
#include <vector>
using namespace std;
#include "RBTree.h"
#include "AVL.h"void test1()
{//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };RBTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));}t.InOrderPrint();cout << endl;cout << t.IsBalance() << endl;
}void test2()
{const int N = 100000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand());}size_t begin2 = clock();RBTree<int, int> t;for (auto e : v){t.Insert(make_pair(e, e));}size_t end2 = clock();size_t begin1 = clock();for (auto e : v){t.Find(make_pair(e, e));}size_t end1 = clock();cout << "Find_time:" << end1 - begin1 << endl;cout << "Insert_time:" << end2 - begin2 << endl;cout << "是否平衡:" << t.IsBalance() << endl;
}void test3()
{const int N = 100000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand()+i);}RBTree<int, int> rbt;AVLTree<int, int> avlt;for (auto e : v){rbt.Insert(make_pair(e, e));avlt.Insert(make_pair(e, e));}cout << "紅黑樹高度: " << rbt.Height()<<endl;cout << "AVL樹高度: " << avlt.Height() << endl;}
int main()
{test3();return 0;
}

?

http://aloenet.com.cn/news/42770.html

相關(guān)文章:

  • 機(jī)關(guān)網(wǎng)站內(nèi)容建設(shè)查關(guān)鍵詞排名工具app
  • 外國服務(wù)器的網(wǎng)站搜索引擎排名的三大指標(biāo)
  • 手機(jī)網(wǎng)站設(shè)計(jì)尺寸大小福州關(guān)鍵詞快速排名
  • 影視網(wǎng)站建設(shè)需要學(xué)什么網(wǎng)站收錄批量查詢
  • 上海專業(yè)網(wǎng)站建設(shè)平臺(tái)最新網(wǎng)絡(luò)推廣平臺(tái)
  • 株洲網(wǎng)站優(yōu)化網(wǎng)站制作的費(fèi)用
  • l5手機(jī)網(wǎng)站模板如何發(fā)布一個(gè)網(wǎng)站
  • 石家莊微信網(wǎng)站建設(shè)公司互聯(lián)網(wǎng)營銷師考證多少錢
  • 先進(jìn)的網(wǎng)站建設(shè)百度推廣客服電話人工服務(wù)
  • 中小型企業(yè)網(wǎng)站的設(shè)計(jì)與開發(fā)百度搜索競(jìng)價(jià)
  • 重慶網(wǎng)站公司淘寶指數(shù)網(wǎng)站
  • wordpress mb_strimwidth htmlseo優(yōu)化工具大全
  • 網(wǎng)站制作策劃今日熱點(diǎn)
  • 南寧微信網(wǎng)站制作網(wǎng)頁制作軟件推薦
  • 去哪兒網(wǎng)站開發(fā)中國國家培訓(xùn)網(wǎng)靠譜嗎
  • 福州手機(jī)網(wǎng)站建設(shè)最新國內(nèi)新聞事件今天
  • 網(wǎng)站店鋪分布圖怎么做網(wǎng)絡(luò)營銷專業(yè)是學(xué)什么的
  • java做的k線圖網(wǎng)站源碼下載seo搜索引擎是什么
  • 為什么做電影網(wǎng)站沒有流量嗎東莞百度seo電話
  • 做網(wǎng)站搞什么流量百度競(jìng)價(jià)點(diǎn)擊軟件奔奔
  • 網(wǎng)站是如何建立的山東做網(wǎng)站
  • 網(wǎng)站企業(yè)備案代理短視頻拍攝剪輯培訓(xùn)班
  • 溫州網(wǎng)站制作多少錢谷歌google 官網(wǎng)下載
  • 手機(jī)html5網(wǎng)站源碼廣告投放的方式有哪些
  • 深圳網(wǎng)站建設(shè)培訓(xùn)班深圳最新通告今天
  • 技術(shù)支持:淄博網(wǎng)站建設(shè)優(yōu)化設(shè)計(jì)三年級(jí)上冊(cè)語文答案
  • 山東省建設(shè)工程招標(biāo)中心網(wǎng)站當(dāng)日網(wǎng)站收錄查詢統(tǒng)計(jì)
  • 網(wǎng)站建設(shè)需求分析寫什么茶葉seo網(wǎng)站推廣與優(yōu)化方案
  • 網(wǎng)站程序組成seo搜狗排名點(diǎn)擊
  • 辛集seo網(wǎng)站優(yōu)化電話靠譜的免費(fèi)建站