国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C++雜貨鋪】一文帶你走進RBTree

這篇具有很好參考價值的文章主要介紹了【C++雜貨鋪】一文帶你走進RBTree。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言

一、紅黑樹的概念

紅黑樹是一種二叉搜索樹,但在每個結點上增加一個存儲位表示結點的顏色,可以是 Red 或 Black。通過對任何一條從根到葉子的路徑上各個結點著色方式的限制,紅黑樹確保沒有一條路徑會比其他路徑長出兩倍,這句話換個意思就是:紅黑樹中最長路徑不超過最短路徑的 2 倍。因而是接近平衡的,而 AVL 樹是嚴格平衡的,這就導致,紅黑樹的高度會比 AVL 樹高一些,但是效率并不會比 AVL 樹差。
【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言

二、紅黑樹的性質(zhì)

  • 每個結點不是紅色就是黑色。

  • 根節(jié)點是黑色。

  • 如果一個結點是紅色,則它的兩個孩子結點必須是黑色的。

  • 對于每個結點,從該結點到其所有后代葉結點的簡單路徑上,均包含相同數(shù)目的黑色結點。

  • 每個 NIL 葉子結點都是黑色的(此處的葉子結點指的是空節(jié)點)。

小Tips:第三點決定了一顆紅黑樹的任何路徑?jīng)]有連續(xù)的紅色結點。在紅黑樹中計算路徑一定是計算到 NIL 結點。一顆紅黑樹中的最短路徑是全為黑結點的路徑,最長路徑是一黑一紅相間的路徑。任意一條路徑上黑色結點的占比一定是大于等于 1 / 2 1/2 1/2 的。這就決定了,紅黑樹中其最長路徑中結點個數(shù)不會超過最短路徑結點個數(shù)的兩倍。

三、紅黑樹結點的定義

//紅黑樹的結點
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(const& pair<K, V> kv = pair<K, V>(), Color color = RED)
		:_kv(kv)
		,_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_col(color)
	{}

	pair<K, V> _kv;//結點中存的值
	RBTreeNode<K, V>* _left;//結點的左孩子
	RBTreeNode<K, V>* _right;//結點的右孩子
	RBTreeNode<K, V>* _parent;//結點的父親
	Color _col;//結點的顏色
};

小Tips:新節(jié)點默認顏色是 RED。這是因為,如果新插入結點的顏色是 BLACK,那意味著當前路徑上新增了一個黑色結點,為了保證二叉樹的第四條性質(zhì),我們要對這顆紅黑樹其他的所有路徑進行檢查,可見新插入結點如果默認是 BLACK,會存在著牽一發(fā)而動全身的影響。而讓新插入結點默認是 RED 則不會出現(xiàn)這樣的結果。假如新插入結點的 parent 恰好是 BLACK,那這次插入就沒有什么問題。如果新插入結點是 parentRED,此時需要對這顆紅黑樹稍作調(diào)整。

四、紅黑樹的插入操作

紅黑樹是在二叉搜索樹的基礎上加上平衡限制條件,因此紅黑樹的插入可以分為兩步:

  • 按照二叉搜索樹的規(guī)則插入結點。

  • 檢測新節(jié)點插入后,紅黑樹的性質(zhì)是否遭到破壞。

因為新結點的默認顏色是 RED,因此:如果其雙親結點的顏色是 BLACK,沒有違反紅黑樹任何性質(zhì),則不需要調(diào)整;但是當新插入節(jié)點的雙親結點顏色為 RED 時,就違反了性質(zhì)三不能有連在一起的紅色結點,此時需要對紅黑樹分情況來討論:

約定cur為當前結點,parent 為父結點,grandp 為祖父結點,uncle 為叔叔結點。如果 parent 為紅那 grandp 一定為黑。所以當前唯一不確定的就是 uncle,主要分以下三種情況

4.1 情況一:uncle 存在且為紅

【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言
小Tips:此處看到的樹,可能是一顆完整的樹,也可能是一顆子樹。

解決方式:將 parentuncle 改為黑,grandp 改成紅。然后把 grandp 當成 cur,繼續(xù)向上調(diào)整。

  • 如果 grandp 是根結點,將 grandp 再改成黑色,本次插入就算結束。

  • 如果 grandp 是子樹,則其一定也有雙親,且 grandp 的雙親如果是紅色,需要繼續(xù)向上調(diào)整。

【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言

4.2 情況二:uncle 不存在

如果 uncle 結點不存在,則 cur 一定是新插入結點,因為如果 cur 不是新插入結點,則 curparent 一定有一個結點的顏色是黑色,就不滿足性質(zhì)四:每條路徑黑色結點個數(shù)相同。
【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言
解決方法:直接進行旋轉(zhuǎn)即可。

4.3 情況三:uncle 存在且為黑

【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言
叔叔存在且為黑,那么 cur 一定不是新插入的結點,并且 cur 結點原來的顏色一定是黑色,現(xiàn)在看到是紅色的原因是因為 cur 的子樹在調(diào)整的過程中將 cur 結點的顏色由黑色改成了紅色。

4.4 插入完整源碼

public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;//插入成功
		}

		//找插入位置
		Node* cur = _root;
		Node* parent = nullptr;

		while (cur)
		{
			if (kv.first < cur->_kv.first)//小于往左走
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first)//大于往右走
			{
				parent = cur;
				cur = cur->_right;
			}
			else//相等插入不了
			{
				return false;
			}
		}

		//找到待插入位置了,進行插入
		cur = new Node(kv);
		cur->_col = RED;
		if (kv.first < parent->_kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}

		cur->_parent = parent;

		//檢測新結點插入后,紅黑樹的性質(zhì)是否遭到破壞
		while (parent && parent->_col == RED)
		{
			Node* grandp = parent->_parent;
			if (parent == grandp->_left)
			{
				Node* uncle = grandp->_right;
				if (uncle && uncle->_col == RED)//叔叔存在且為紅
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandp->_col = RED;

					//繼續(xù)向上處理
					cur = grandp;
					parent = cur->_parent;
				}
				else //uncle不存在或者存在為黑
				{
					if (cur == parent->_left)
					{
						RotateR(grandp);
						parent->_col = BLACK;//parent當了根
						grandp->_col = RED;
					}
					else if (cur == parent->_right)
					{
						RotateLR(grandp);
						cur->_col = BLACK;//cur當了根節(jié)點
						grandp->_col = RED;
					}

					break;
				}
			}
			else if (parent == grandp->_right)
			{
				Node* uncle = grandp->_left;
				if (uncle && uncle->_col == RED)//叔叔存在且為紅
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandp->_col = RED;

					//繼續(xù)向上處理
					cur = grandp;
					parent = cur->_parent;
				}
				else //uncle不存在或者存在為黑
				{
					if (cur == parent->_right)
					{
						RotateL(grandp);
						parent->_col = BLACK;//parent當了根
						grandp->_col = RED;
					}
					else if (cur == parent->_left)
					{
						RotateRL(grandp);
						cur->_col = BLACK;//cur當了根節(jié)點
						grandp->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;//根結點始終變黑
		return true;
	}
private:
	//左單旋
	void RotateL(Node* parent)
	{
		++_rotatecount;
		Node* cur = parent->_right;
		Node* curleft = cur->_left;

		parent->_right = curleft;
		cur->_left = parent;

		if (curleft)
		{
			curleft->_parent = parent;
		}

		Node* ppnode = parent->_parent;
		parent->_parent = cur;

		if (parent == _root)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
			}
			else
			{
				ppnode->_right = cur;
			}
			cur->_parent = ppnode;
		}

	}

	//右單旋
	void RotateR(Node* parent)
	{
		++_rotatecount;
		Node* cur = parent->_left;
		Node* curright = cur->_right;//此時的情況是curright比cur大,比parent小

		parent->_left = curright;
		cur->_right = parent;

		if (curright)
		{
			curright->_parent = parent;
		}

		Node* ppnode = parent->_parent;
		parent->_parent = cur;

		if (ppnode)
		{
			cur->_parent = ppnode;
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
			}
			else
			{
				ppnode->_right = cur;
			}
		}
		else
		{
			_root = cur;
			cur->_parent = nullptr;
		}
	}

	//右左雙旋
	void RotateRL(Node* parent)
	{
		Node* cur = parent->_right;
		Node* curleft = cur->_left;

		RotateR(parent->_right);
		RotateL(parent);

	}

	//左右雙旋
	void RotateLR(Node* parent)
	{
		Node* cur = parent->_left;
		Node* curright = cur->_right;

		RotateL(cur);
		RotateR(parent);

	}

五、紅黑樹的驗證

紅黑樹的檢測分為兩步:

  • 檢測其是否滿足二叉搜索樹(中序遍歷是否為有序序列)。

  • 檢測其是否滿足紅黑樹的性質(zhì)(主要是性質(zhì)三和性質(zhì)四)。

public:
	bool Isblance()
	{
		if (_root == nullptr)
			return true;

		//根節(jié)點如果不是黑色說明就不是紅黑樹
		if (_root->_col != BLACK)
		{
			return false;
		}

		//計算紅黑樹中任意一條路徑上黑色結點的個數(shù)作為一個基準值
		Node* cur = _root;
		int count = 0;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				++count;
			}
			cur = cur->_left;
		}

		return CheckColour(_root, 0, count);
	}
private:
	//檢查顏色
	bool CheckColour(Node* root, int blacknum, int stand)
	{
		if (root == nullptr)
		{
			//到這里說明一條路徑結束,那么這條路徑上的黑色結點數(shù)也一定統(tǒng)計出來了
			if (blacknum != stand)
			{
				cout << "當前路徑上黑色結點的個數(shù)有問題" << endl;
				return false;
			}

			return true;
		}

		//檢查是否出現(xiàn)連續(xù)的紅色結點
		if (root->_col == RED && root->_parent && root->_parent->_col == RED)
		{
			cout << root->_kv.first << ":為紅色節(jié)點,并且孩子結點也是紅色" << endl;
		}

		//統(tǒng)計一條路徑上黑色結點個數(shù)
		if (root->_col == BLACK)
		{
			++blacknum;
		}

		return CheckColour(root->_left, blacknum, stand) && CheckColour(root->_right, blacknum, stand);
	}	

六、紅黑樹與 AVL 樹的比較

紅黑樹和 AVL 樹都是高效的平衡二叉樹,增刪查改的時間復雜度都是 O ( l o g 2 N ) O(log2^N) O(log2N),紅黑樹不追求絕對平衡,其只需要保證最長路徑不超過最短路徑的 2 倍,相對而言,降低了插入過程中旋轉(zhuǎn)的次數(shù),所以在經(jīng)常進行增刪查改的結構中性能比 AVL 樹更優(yōu),而且紅黑樹實現(xiàn)比較簡單,所以實際運用中紅黑樹更多。紅黑樹主要會應用在以下幾個地方:

  • C++ STL 庫----map、set、mutilmap、mutilset。

  • Java 庫。

  • Linux 內(nèi)核。

  • 其它一些庫。

七、結語

今天的分享到這里就結束啦!如果覺得文章還不錯的話,可以三連支持一下,春人的主頁還有很多有趣的文章,歡迎小伙伴們前去點評,您的支持就是春人前進的動力!

【C++雜貨鋪】一文帶你走進RBTree,C++雜貨鋪,c++,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-713413.html

到了這里,關于【C++雜貨鋪】一文帶你走進RBTree的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【C++雜貨鋪】模板

    【C++雜貨鋪】模板

    ?? 實現(xiàn)一個通用的交換函數(shù) 想要實現(xiàn)一個通用的交換函數(shù)不難,借助函數(shù)重載就可以。函數(shù)重載小伙伴們還記得嘛??,忘了的小伙伴可以走傳送門回去復習一下。如上面代碼所示,我們借助函數(shù)重載實現(xiàn)了三份 Swap 函數(shù),分別用來交換兩個整型變量、兩個雙精度浮點型變量

    2024年02月09日
    瀏覽(17)
  • 【C++雜貨鋪】引用

    【C++雜貨鋪】引用

    前言: ?相信大家在學習C語言的時候,最頭疼的就是指針,經(jīng)常會碰到一級指針、二級指針,這些指針使用起來,稍有不慎就會等導致程序崩潰,為了讓廣大程序員少掉點頭發(fā),C++中提出了 引用 這一概念。當然,在C++的代碼中,仍然可以兼容C語言的指針。 ?在語法上 引用

    2024年02月16日
    瀏覽(25)
  • 【C++雜貨鋪】內(nèi)存管理

    【C++雜貨鋪】內(nèi)存管理

    從用途和存儲的角度來看,在C/C++程序中有 局部數(shù)據(jù)、靜態(tài)數(shù)據(jù)、全局數(shù)據(jù)、常量數(shù)據(jù)、動態(tài)申請的數(shù)據(jù) 五種主要的數(shù)據(jù),各種數(shù)據(jù)的特點如下: 局部數(shù)據(jù) :隨用隨創(chuàng)建,存儲在棧區(qū),作用域只在局部,生命周期在局部,出了作用域就銷毀。 靜態(tài)數(shù)據(jù) :存儲在數(shù)據(jù)段,作

    2024年02月16日
    瀏覽(20)
  • 【C++雜貨鋪】詳解string

    【C++雜貨鋪】詳解string

    目錄 ???前言?? ?? 為什么學習string ?? 認識string(了解) ?? string的常用接口 ??? 構造函數(shù) ??? string類對象的容量操作 ??? string類對象的訪問以及遍歷操作?編輯 ??? string類對象的修改操作 ?? 模擬實現(xiàn)string ?? 總結 ? ? ? ? 歡迎觀看本期【C++雜貨鋪】,本期內(nèi)容

    2024年03月20日
    瀏覽(25)
  • 【C++雜貨鋪】內(nèi)管管理

    【C++雜貨鋪】內(nèi)管管理

    目錄 ??前言?? ?? C/C++中內(nèi)存分布 ?? new 和 delete的使用 ?? new 和 delete的優(yōu)點 ?? new 和 delete的原理 ??? operator new 和 operator delete函數(shù) ??? 內(nèi)置類型 ??? 自定義類型 ?? 內(nèi)存泄漏 ?? 總結 ? ? ? ? 歡迎收看本期【C++雜貨鋪】,本期內(nèi)容講解C++內(nèi)存管理。包含了C++中內(nèi)存

    2024年04月14日
    瀏覽(34)
  • 【C++雜貨鋪】拷貝構造函數(shù)

    【C++雜貨鋪】拷貝構造函數(shù)

    ?? 定義 拷貝構造函數(shù) 是構造函數(shù)的一個重載 ,它的本質(zhì)還是 構造函數(shù) ,那就意味著,只有在創(chuàng)建對象的時候,編譯器才會自動調(diào)用它,那他和普通的構造函數(shù)有什么區(qū)別呢? 拷貝構造函數(shù),是創(chuàng)建對象的時候,用一個已存在的對象,去初始化待創(chuàng)建的對象 。簡單來說,

    2024年02月16日
    瀏覽(22)
  • 【C++雜貨鋪】運算符重載

    【C++雜貨鋪】運算符重載

    本文將以日期類為基礎,去探尋運算符重載的特性與使用方法,下面先給出日期類的基礎定義: 備注 :拷貝構造函數(shù)和析構函數(shù),均可以不寫,因為當前日期類的三個成員變量都是內(nèi)置類型,沒有動態(tài)申請空間,使用淺拷貝就可以。 ?? 如何比較兩個日期的大??? 現(xiàn)如今,

    2024年02月16日
    瀏覽(21)
  • 【C++雜貨鋪】缺省參數(shù)、函數(shù)重載

    【C++雜貨鋪】缺省參數(shù)、函數(shù)重載

    ?缺省參數(shù)是 聲明或定義函數(shù)時為函數(shù)的參數(shù)指定一個缺省值 。在調(diào)用該函數(shù)時,如果沒有指定實參則采用該形參的缺省值,否則使用指定的實參。 ?上面代碼在 fun 函數(shù)的形參部分給了缺省值10,這意味著在調(diào)用 fun 函數(shù)的時候可以傳參,也可以不傳參,如果傳參了那形參

    2024年02月16日
    瀏覽(18)
  • 【C++雜貨鋪】詳解list容器

    【C++雜貨鋪】詳解list容器

    目錄 ??前言?? ?? 介紹 ?? 使用 ??? 構造 ??? 迭代器iterator ??? capacity ??? modifiers ??? 迭代器失效 ?? 模擬實現(xiàn) ??? 迭代器的實現(xiàn) ?? 代碼展示 ?? 和vector的區(qū)別 ?? 總結 ? ? ? ? 歡迎收看本期【C++雜貨鋪】,本期內(nèi)容將講解STL中關于list的內(nèi)容,會分為一下幾個方

    2024年04月14日
    瀏覽(22)
  • 【C++雜貨鋪】C++介紹、命名空間、輸入輸出

    【C++雜貨鋪】C++介紹、命名空間、輸入輸出

    ?C語言是 結構化 和 模塊化 的語言,適合處理 較小規(guī)模 的程序。對于復雜的問題,規(guī)模較大的程序,需要高度的抽象和建模時,C語言則不合適。為了解決軟件危機,20世紀80年代,計算機界提出了 OOP (object oriented programming: 面向?qū)ο?)思想,支持面向?qū)ο蟮某绦蛟O計語言應

    2024年02月16日
    瀏覽(31)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包