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

【C++庖丁解牛】自平衡二叉搜索樹--AVL樹

這篇具有很好參考價值的文章主要介紹了【C++庖丁解?!孔云胶舛嫠阉鳂?-AVL樹。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

【C++庖丁解牛】自平衡二叉搜索樹--AVL樹,c++,java,開發(fā)語言
??你好,我是 RO-BERRY
?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫等等一系列知識
??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個完美的句號,讓我們一起加油

【C++庖丁解?!孔云胶舛嫠阉鳂?-AVL樹,c++,java,開發(fā)語言



前言

前面對map/multimap/set/multiset進(jìn)行了簡單的介紹,在其文檔介紹中發(fā)現(xiàn),這幾個容器有個共同點(diǎn)是:其底層都是按照二叉搜索樹來實(shí)現(xiàn)的,但是二叉搜索樹有其自身的缺陷,假如往樹中插入的元素有序或者接近有序,二叉搜索樹就會退化成單支樹,時間復(fù)雜度會退化成O(N),因此map、set等關(guān)聯(lián)式容器的底層結(jié)構(gòu)是對二叉樹進(jìn)行了平衡處理,即采用平衡樹來實(shí)現(xiàn)。

1 AVL樹的概念

二叉搜索樹雖可以縮短查找的效率,但如果數(shù)據(jù)有序或接近有序二叉搜索樹將退化為單支樹,查找元素相當(dāng)于在順序表中搜索元素,效率低下。因此,兩位俄羅斯的數(shù)學(xué)家G.M.Adelson-Velskii和E.M.Landis在1962年發(fā)明了一種解決上述問題的方法:當(dāng)向二叉搜索樹中插入新結(jié)點(diǎn)后,如果能保證每個結(jié)點(diǎn)的左右子樹高度之差的絕對值不超過1(需要對樹中的結(jié)點(diǎn)進(jìn)行調(diào)整),即可降低樹的高度,從而減少平均搜索長度。

一棵AVL樹或者是空樹,或者是具有以下性質(zhì)的二叉搜索樹:

  1. 它的左右子樹都是AVL樹
  2. 左右子樹高度之差(簡稱平衡因子)的絕對值不超過1(-1/0/1)
  3. 平衡因子 = 右子樹高度 - 左子樹高度

平衡因子并不是必須的,它只是一種控制方式,幫助我們更便捷的控制樹

【擴(kuò)充】
這里為什么高度差為1?如果高度相等不是更平衡嗎?

節(jié)點(diǎn)是一個一個插入的,有些情況是無法做到相等的,最優(yōu)就是高度差是1;比如:兩個節(jié)點(diǎn)的樹和四個節(jié)點(diǎn)的樹等等。

【C++庖丁解牛】自平衡二叉搜索樹--AVL樹,c++,java,開發(fā)語言

2. AVL樹節(jié)點(diǎn)的定義

AVL樹節(jié)點(diǎn)的定義:

template<class T>
struct AVLTreeNode
{
	AVLTreeNode(const T& data)
		: _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
		, _data(data), _bf(0)
		{}
	AVLTreeNode<T>* _pLeft;   // 該節(jié)點(diǎn)的左孩子
	AVLTreeNode<T>* _pRight;  // 該節(jié)點(diǎn)的右孩子
	AVLTreeNode<T>* _pParent; // 該節(jié)點(diǎn)的雙親
	T _data;
	int _bf;                  // 該節(jié)點(diǎn)的平衡因子
};

3. AVL樹的插入

AVL樹就是在二叉搜索樹的基礎(chǔ)上引入了平衡因子,因此AVL樹也可以看成是二叉搜索樹。那么AVL樹的插入過程可以分為兩步:

  1. 按照二叉搜索樹的方式插入新節(jié)點(diǎn)
  2. 調(diào)整節(jié)點(diǎn)的平衡因子

插入節(jié)點(diǎn)會影響新增節(jié)點(diǎn)的部分祖先
更新原則:

  • 若是插入的是左節(jié)點(diǎn)則父節(jié)點(diǎn)的平衡因子減1
  • 若是插入的是右節(jié)點(diǎn)則父節(jié)點(diǎn)的平衡因子加1

是否要繼續(xù)更新取決于新增節(jié)點(diǎn)會不會影響父節(jié)點(diǎn)的高度,從而決定會不會影響爺爺節(jié)點(diǎn)

  • 更新后,父節(jié)點(diǎn)所在的子樹高度不變則不會影響爺爺節(jié)點(diǎn)

說明父節(jié)點(diǎn)的平衡因子是1或者-1,父節(jié)點(diǎn)在矮的那邊插入了節(jié)點(diǎn),左右均衡了,于是父節(jié)點(diǎn)的高度不變,則不會影響到爺爺,更新結(jié)束

  • 更新后,父節(jié)點(diǎn)所在的子樹高度改變則會影響爺爺節(jié)點(diǎn)

說明更新前,父節(jié)點(diǎn)的平衡因子是0,父節(jié)點(diǎn)變得不均衡,但是不違反規(guī)則,高度改變,會影響爺爺節(jié)點(diǎn)繼續(xù)往上更新

更新后,父節(jié)點(diǎn)的平衡因子為2或-2,說明該子樹違反了平衡規(guī)則,需要處理->旋轉(zhuǎn)
代碼實(shí)現(xiàn):

	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;
		
		//新節(jié)點(diǎn)插入后,AVL樹的平衡性可能會遭到破壞,此時就需要更新平衡因子,并檢測是否破壞了AVL樹的平衡性

		/*
		pCur插入后,pParent的平衡因子一定需要調(diào)整,在插入之前,pParent的平衡因子分為三種情況:-1,0, 1, 分以下兩種情況:
		 1. 如果pCur插入到pParent的左側(cè),只需給pParent的平衡因子-1即可
		 2. 如果pCur插入到pParent的右側(cè),只需給pParent的平衡因子+1即可
 
		 此時:pParent的平衡因子可能有三種情況:0,正負(fù)1, 正負(fù)2
		 1. 如果pParent的平衡因子為0,說明插入之前pParent的平衡因子為正負(fù)1,插入后被調(diào)整成0,此時滿足AVL樹的性質(zhì),插入成功
		 2. 如果pParent的平衡因子為正負(fù)1,說明插入前pParent的平衡因子一定為0,插入后被更新成正負(fù)1,此時以pParent為根的樹的高度增加,需要繼續(xù)向上更新
		 3. 如果pParent的平衡因子為正負(fù)2,則pParent的平衡因子違反平衡樹的性質(zhì),需要對其進(jìn)行旋轉(zhuǎn)處理
		 */
		while (parent)
		{
			 // 更新雙親的平衡因子
			if (cur == parent->left)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}
			// 更新后檢測雙親的平衡因子
			if (parent->_bf == 0)
			{
				break;
			}

			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				// 插入前雙親的平衡因子是0,插入后雙親的平衡因?yàn)闉? 或者 -1 ,說明以雙親為根的二叉樹的高度增加了一層,因此需要繼續(xù)向上調(diào)整
				cur = cur->_parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				// 雙親的平衡因子為正負(fù)2,違反了AVL樹的平衡性,需要對以pParent為根的樹進(jìn)行旋轉(zhuǎn)處理
				if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				else
				{
					RotateRL(parent);
				}

				break;
			}
			else
			{
				// 插入之前AVL樹就有問題
				assert(false);
			}
		}

		return true;
	}

4. AVL樹的旋轉(zhuǎn)

如果在一棵原本是平衡的AVL樹中插入一個新節(jié)點(diǎn),可能造成不平衡,此時必須調(diào)整樹的結(jié)構(gòu),
使之平衡化。根據(jù)節(jié)點(diǎn)插入位置的不同,AVL樹的旋轉(zhuǎn)分為四種:

  1. 新節(jié)點(diǎn)插入較高左子樹的左側(cè)—左左:右單旋

【C++庖丁解牛】自平衡二叉搜索樹--AVL樹,c++,java,開發(fā)語言
上圖在插入前,AVL樹是平衡的,新節(jié)點(diǎn)插入到30的左子樹(注意:此處不是左孩子)中,30左子樹增加了一層,導(dǎo)致以60為根的二叉樹不平衡,要讓60平衡,只能將60左子樹的高度減少一層,右子樹增加一層,即將左子樹往上提,這樣60轉(zhuǎn)下來,因?yàn)?0比30大,只能將其放在30的右子樹,而如果30有右子樹,右子樹根的值一定大于30,小于60,只能將其放在60的左子樹,旋轉(zhuǎn)完成后,更新節(jié)點(diǎn)的平衡因子即可。

在旋轉(zhuǎn)過程中,有以下幾種情況需要考慮:

  1. 30節(jié)點(diǎn)的右孩子可能存在,也可能不存在
  2. 60可能是根節(jié)點(diǎn),也可能是子樹
  • 如果是根節(jié)點(diǎn),旋轉(zhuǎn)完成后,要更新根節(jié)點(diǎn)
  • 如果是子樹,可能是某個節(jié)點(diǎn)的左子樹,也可能是右子樹
void _RotateR(PNode pParent)
{
	// pSubL: pParent的左孩子
	// pSubLR: pParent左孩子的右孩子
	PNode pSubL = pParent->_pLeft;
	PNode pSubLR = pSubL->_pRight;
	
	// 旋轉(zhuǎn)完成之后,30的右孩子作為雙親的左孩子
	pParent->_pLeft = pSubLR;
	// 如果30的左孩子的右孩子存在,更新親雙親
	if (pSubLR)
		pSubLR->_pParent = pParent;
	// 60 作為 30的右孩子
	pSubL->_pRight = pParent;

	// 因?yàn)?0可能是棵子樹,因此在更新其雙親前必須先保存60的雙親
	PNode pPParent = pParent->_pParent;

	// 更新60的雙親
	pParent->_pParent = pSubL;

	// 更新30的雙親
	pSubL->_pParent = pPParent;
	// 如果60是根節(jié)點(diǎn),根新指向根節(jié)點(diǎn)的指針
	if (NULL == pPParent)
	{
		_pRoot = pSubL;
		pSubL->_pParent = NULL;
	}
	else
	{
	// 如果60是子樹,可能是其雙親的左子樹,也可能是右子樹
	if (pPParent->_pLeft == pParent)
		pPParent->_pLeft = pSubL;
	else
		pPParent->_pRight = pSubL;
	}
	// 根據(jù)調(diào)整后的結(jié)構(gòu)更新部分節(jié)點(diǎn)的平衡因子
	pParent->_bf = pSubL->_bf = 0;
}
  1. 新節(jié)點(diǎn)插入較高右子樹的右側(cè)—右右:左單旋
    【C++庖丁解?!孔云胶舛嫠阉鳂?-AVL樹,c++,java,開發(fā)語言
    實(shí)現(xiàn)及情況考慮可參考右單旋。

  2. 新節(jié)點(diǎn)插入較高左子樹的右側(cè)—左右:先左單旋再右單旋

【C++庖丁解?!孔云胶舛嫠阉鳂?-AVL樹,c++,java,開發(fā)語言
將雙旋變成單旋后再旋轉(zhuǎn),即:先對30進(jìn)行左單旋,然后再對90進(jìn)行右單旋,旋轉(zhuǎn)完成后再考慮平衡因子的更新。

// 旋轉(zhuǎn)之前,60的平衡因子可能是-1/0/1,旋轉(zhuǎn)完成之后,根據(jù)情況對其他節(jié)點(diǎn)的平衡因子進(jìn)行調(diào)整
void _RotateLR(PNode pParent)
{
	PNode pSubL = pParent->_pLeft;
	PNode pSubLR = pSubL->_pRight;
    
    // 旋轉(zhuǎn)之前,保存pSubLR的平衡因子,旋轉(zhuǎn)完成之后,需要根據(jù)該平衡因子來調(diào)整其他節(jié)點(diǎn)的平衡因子
	int bf = pSubLR->_bf;
    
    // 先對30進(jìn)行左單旋
	_RotateL(pParent->_pLeft);
    
    // 再對90進(jìn)行右單旋
	_RotateR(pParent);
	if(1 == bf)
	pSubL->_bf = -1;
	else if(-1 == bf)
	pParent->_bf = 1;
}
  1. 新節(jié)點(diǎn)插入較高右子樹的左側(cè)—右左:先右單旋再左單旋

【C++庖丁解?!孔云胶舛嫠阉鳂?-AVL樹,c++,java,開發(fā)語言
參考右左雙旋。
總結(jié):
假如以pParent為根的子樹不平衡,即pParent的平衡因子為2或者-2,分以下情況考慮

  1. pParent的平衡因子為2,說明pParent的右子樹高,設(shè)pParent的右子樹的根為pSubR
  • 當(dāng)pSubR的平衡因子為1時,執(zhí)行左單旋
  • 當(dāng)pSubR的平衡因子為-1時,執(zhí)行右左雙旋
  1. pParent的平衡因子為-2,說明pParent的左子樹高,設(shè)pParent的左子樹的根為pSubL
  • 當(dāng)pSubL的平衡因子為-1是,執(zhí)行右單旋
  • 當(dāng)pSubL的平衡因子為1時,執(zhí)行左右雙旋

旋轉(zhuǎn)完成后,原pParent為根的子樹個高度降低,已經(jīng)平衡,不需要再向上更新。

實(shí)現(xiàn)代碼

#pragma once

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	int _bf; // balance factor
	pair<K, V> _kv;

	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
		, _kv(kv)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		while (parent)
		{
			if (cur == parent->left)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}

			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				// 旋轉(zhuǎn)處理
				if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				else
				{
					RotateRL(parent);
				}

				break;
			}
			else
			{
				// 插入之前AVL樹就有問題
				assert(false);
			}
		}

		return true;
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		subR->_left = parent;
		Node* ppnode = parent->_parent;
		parent->_parent = subR;

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

		parent->_bf = 0;
		subR->_bf = 0;
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		subL->_right = parent;

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

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

		subL->_bf = 0;
		parent->_bf = 0;
	}

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		int bf = subLR->_bf;
		RotateL(parent->_left);
		RotateR(parent);

		if (bf == -1)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 1;
		}
		else if (bf == 1)
		{
			subLR->_bf = 0;
			subL->_bf = -1;
			parent->_bf = 0;
		}
		else if (bf == 0)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

private:
	Node* _root = nullptr;
};

5 AVL樹的驗(yàn)證

AVL樹是在二叉搜索樹的基礎(chǔ)上加入了平衡性的限制,因此要驗(yàn)證AVL樹,可以分兩步:

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

如果中序遍歷可得到一個有序的序列,就說明為二叉搜索樹

  1. 驗(yàn)證其為平衡樹
  • 每個節(jié)點(diǎn)子樹高度差的絕對值不超過1(注意節(jié)點(diǎn)中如果沒有平衡因子)
  • 節(jié)點(diǎn)的平衡因子是否計(jì)算正確
int _Height(PNode pRoot);
bool _IsBalanceTree(PNode pRoot)
{
	// 空樹也是AVL樹
	if (nullptr == pRoot) return true;
    
	// 計(jì)算pRoot節(jié)點(diǎn)的平衡因子:即pRoot左右子樹的高度差
	int leftHeight = _Height(pRoot->_pLeft);
	int rightHeight = _Height(pRoot->_pRight);
	int diff = rightHeight - leftHeight;
 	// 如果計(jì)算出的平衡因子與pRoot的平衡因子不相等,或者
	// pRoot平衡因子的絕對值超過1,則一定不是AVL樹
	if (diff != pRoot->_bf || (diff > 1 || diff < -1))
	return false;
	// pRoot的左和右如果都是AVL樹,則該樹一定是AVL樹
	return _IsBalanceTree(pRoot->_pLeft) && _IsBalanceTree(pRoot->_pRight);
 }

6 AVL樹的刪除(了解)

因?yàn)锳VL樹也是二叉搜索樹,可按照二叉搜索樹的方式將節(jié)點(diǎn)刪除,然后再更新平衡因子,只不錯與刪除不同的時,刪除節(jié)點(diǎn)后的平衡因子更新,最差情況下一直要調(diào)整到根節(jié)點(diǎn)的位置。具體實(shí)現(xiàn)學(xué)生們可參考《算法導(dǎo)論》或《數(shù)據(jù)結(jié)構(gòu)-用面向?qū)ο蠓椒ㄅcC++描述》殷人昆版。

AVL樹是一種自平衡的二叉搜索樹,它的刪除操作與插入操作類似,但需要在刪除節(jié)點(diǎn)后進(jìn)行平衡操作以保持樹的平衡性。
AVL樹的刪除操作可以分為以下幾種情況:

  1. 如果待刪除的節(jié)點(diǎn)是葉子節(jié)點(diǎn),直接刪除即可。
  2. 如果待刪除的節(jié)點(diǎn)只有一個子節(jié)點(diǎn),將子節(jié)點(diǎn)替代待刪除節(jié)點(diǎn)的位置。

如果待刪除的節(jié)點(diǎn)有兩個子節(jié)點(diǎn),可以選擇以下兩種方式進(jìn)行刪除:

  • 找到待刪除節(jié)點(diǎn)的前驅(qū)或后繼節(jié)點(diǎn),將其值復(fù)制到待刪除節(jié)點(diǎn),并將前驅(qū)或后繼節(jié)點(diǎn)刪除。
  • 找到待刪除節(jié)點(diǎn)的左子樹中的最大值或右子樹中的最小值,將其值復(fù)制到待刪除節(jié)點(diǎn),并將最大值或最小值節(jié)點(diǎn)刪除。

刪除節(jié)點(diǎn)后,需要從被刪除節(jié)點(diǎn)的父節(jié)點(diǎn)開始向上回溯,檢查每個祖先節(jié)點(diǎn)是否平衡。如果發(fā)現(xiàn)某個祖先節(jié)點(diǎn)不平衡,需要進(jìn)行相應(yīng)的旋轉(zhuǎn)操作來恢復(fù)平衡。

7 AVL樹的性能

AVL樹是一棵絕對平衡的二叉搜索樹,其要求每個節(jié)點(diǎn)的左右子樹高度差的絕對值都不超過1,這樣可以保證查詢時高效的時間復(fù)雜度,即 l o g 2 ( N ) log_2 (N) log2?(N)。但是如果要對AVL樹做一些結(jié)構(gòu)修改的操作,性能非常低下,比如:插入時要維護(hù)其絕對平衡,旋轉(zhuǎn)的次數(shù)比較多,更差的是在刪除時,有可能一直要讓旋轉(zhuǎn)持續(xù)到根的位置。因此:如果需要一種查詢高效且有序的數(shù)據(jù)結(jié)構(gòu),而且數(shù)據(jù)的個數(shù)為靜態(tài)的(即不會改變),可以考慮AVL樹,但一個結(jié)構(gòu)經(jīng)常修改,就不太適合。

AVL樹是一種自平衡二叉搜索樹,它的性能相對于普通的二叉搜索樹更加穩(wěn)定。AVL樹的性能可以從以下幾個方面來介紹:

  1. 查找操作:AVL樹的查找操作與普通的二叉搜索樹相同,時間復(fù)雜度為O(log n),其中n為樹中節(jié)點(diǎn)的數(shù)量。由于AVL樹是平衡的,所以查找操作的性能是穩(wěn)定的。

  2. 插入和刪除操作:AVL樹在插入和刪除節(jié)點(diǎn)時會進(jìn)行自平衡操作,以保持樹的平衡性。這些自平衡操作包括旋轉(zhuǎn)和重新計(jì)算節(jié)點(diǎn)的平衡因子。插入和刪除操作的時間復(fù)雜度也是O(log n),但由于需要進(jìn)行自平衡操作,所以相對于普通二叉搜索樹,AVL樹的插入和刪除操作可能會更耗時。

  3. 平衡性:AVL樹的平衡性保證了樹的高度始終保持在一個較小的范圍內(nèi)。具體來說,AVL樹的任意節(jié)點(diǎn)的左右子樹高度差不超過1。這種平衡性保證了查找、插入和刪除操作的時間復(fù)雜度都能夠保持在O(log n)。

  4. 空間復(fù)雜度:AVL樹的空間復(fù)雜度與節(jié)點(diǎn)數(shù)量成正比,即O(n)。每個節(jié)點(diǎn)需要存儲鍵值對以及額外的平衡因子信息。

總的來說,AVL樹在查找操作上具有較好的性能,但在插入和刪除操作上可能會稍微慢一些。然而,AVL樹的平衡性保證了樹的高度始終保持在一個較小的范圍內(nèi),從而保證了整體的性能穩(wěn)定性。文章來源地址http://www.zghlxwxcb.cn/news/detail-844997.html

到了這里,關(guān)于【C++庖丁解?!孔云胶舛嫠阉鳂?-AVL樹的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C++庖丁解牛】STL之vector容器的介紹及使用 | vector迭代器的使用 | vector空間增長問題

    【C++庖丁解?!縎TL之vector容器的介紹及使用 | vector迭代器的使用 | vector空間增長問題

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫等等一系列知識 ??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個完美的句號,讓我們一起加油 vector的文檔介紹 vector是表示可變大小數(shù)組的序列容器。 就像數(shù)組一樣,vector也采用的連續(xù)存儲空間來存

    2024年03月14日
    瀏覽(36)
  • 【C++庖丁解牛】面向?qū)ο蟮娜筇匦灾欢鄳B(tài) | 抽象類 | 多態(tài)的原理 | 單繼承和多繼承關(guān)系中的虛函數(shù)表

    【C++庖丁解?!棵嫦?qū)ο蟮娜筇匦灾欢鄳B(tài) | 抽象類 | 多態(tài)的原理 | 單繼承和多繼承關(guān)系中的虛函數(shù)表

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫等等一系列知識 ??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個完美的句號,讓我們一起加油 需要聲明的,本節(jié)課件中的代碼及解釋都是在vs2013下的x86程序中,涉及的指針都是4bytes。如果要其他平臺

    2024年04月10日
    瀏覽(28)
  • 庖丁解牛函數(shù)知識---C語言《1》

    庖丁解牛函數(shù)知識---C語言《1》

    目錄 前言: 1.程序中的函數(shù) 2.庫函數(shù)的學(xué)習(xí)和使用 3.自定義函數(shù) 4.傳值調(diào)用與傳址調(diào)用 5.形參與實(shí)參 6.練習(xí)---二分查找函數(shù) ?博主CSDN:啊蘇要學(xué)習(xí) ? ?專欄分類:C語言? ? C語言的學(xué)習(xí),是為我們今后學(xué)習(xí)其它語言打好基礎(chǔ),C生萬物! ? 開始我們的C語言之旅吧!? ? 在計(jì)

    2024年02月02日
    瀏覽(16)
  • 庖丁解牛函數(shù)知識---C語言《2》

    庖丁解牛函數(shù)知識---C語言《2》

    目錄 前言: 1.嵌套調(diào)用函數(shù) 2.鏈?zhǔn)皆L問 3.函數(shù)的聲明與定義 4.*遞歸 5.遞歸與非遞歸 ?博主CSDN:啊蘇要學(xué)習(xí) ? ?專欄分類:C語言? ? C語言的學(xué)習(xí),是為我們今后學(xué)習(xí)其它語言打好基礎(chǔ),C生萬物! ? 開始我們的C語言之旅吧!? ? 在第一篇的基礎(chǔ)上,我們接著學(xué)習(xí)函數(shù)相關(guān)的

    2024年02月02日
    瀏覽(24)
  • 【數(shù)據(jù)結(jié)構(gòu)】 隊(duì)列詳解!庖丁解牛般細(xì)致講解!

    【數(shù)據(jù)結(jié)構(gòu)】 隊(duì)列詳解!庖丁解牛般細(xì)致講解!

    ?? 嶼小夏 : 個人主頁 ??個人專欄 : 數(shù)據(jù)結(jié)構(gòu)解析 ?? 莫道桑榆晚,為霞尚滿天! 什么是隊(duì)列?隊(duì)列有什么樣的特性?它的應(yīng)用場景有哪些? 本文會對隊(duì)列這種數(shù)據(jù)結(jié)構(gòu)進(jìn)行進(jìn)行庖丁解牛般的講解,讓你徹底學(xué)會數(shù)據(jù)結(jié)構(gòu)! 隊(duì)列是一種常見的數(shù)據(jù)結(jié)構(gòu),它按照先進(jìn)先出

    2024年02月06日
    瀏覽(20)
  • 【數(shù)據(jù)結(jié)構(gòu)---排序】庖丁解牛式剖析常見的排序算法

    【數(shù)據(jù)結(jié)構(gòu)---排序】庖丁解牛式剖析常見的排序算法

    排序在我們生活中處處可見,所謂排序,就是使一串記錄,按照其中的某個或某些的大小,遞增或遞減的排列起來的操作。 常見的排序算法可以分為四大類:插入排序,選擇排序,交換排序,歸并排序;其中,插入排序分為直接插入排序和希爾排序;選擇排序分為直接

    2024年02月16日
    瀏覽(32)
  • C生萬物 | 操作符匯總大全【庖丁解牛,精細(xì)講解】

    C生萬物 | 操作符匯總大全【庖丁解牛,精細(xì)講解】

    本篇博客全站熱榜最高排名:2 因?yàn)镸arkDown的語法,所以用圖片的形式顯示 對于算術(shù)操作符而言有上面這五種,對于前面的【+】、【-】、【*】來說操作數(shù)可以是整數(shù)或者浮點(diǎn)數(shù) 對于【/】來說,叫做 整除 ,結(jié)果就是我們在數(shù)學(xué)中說到的 商 。若是兩邊都是整數(shù),則執(zhí)行執(zhí)行

    2023年04月08日
    瀏覽(25)
  • 【數(shù)據(jù)結(jié)構(gòu)】庖丁解牛,圖文結(jié)合帶你輕松上手帶頭循環(huán)鏈表

    【數(shù)據(jù)結(jié)構(gòu)】庖丁解牛,圖文結(jié)合帶你輕松上手帶頭循環(huán)鏈表

    君兮_的個人主頁 勤時當(dāng)勉勵 歲月不待人 C/C++ 游戲開發(fā) Hello,米娜桑們,這里是君兮_,我們今天接著上回的單鏈表來講講帶頭雙向循環(huán)鏈表,這種鏈表也是我們在實(shí)際應(yīng)用中最常用的幾種鏈表之一,學(xué)好這種鏈表是是非常重要的,我會盡量用通俗易懂的文字配合邏輯圖來幫助

    2024年02月14日
    瀏覽(24)
  • 【C++】AVL(平衡二叉搜索樹)樹的原理及實(shí)現(xiàn)

    【C++】AVL(平衡二叉搜索樹)樹的原理及實(shí)現(xiàn)

    文章目錄 一、引言 二、AVL樹的概念 三、AVL樹的插入 3、1?AVL樹的簡單插入 3、2 旋轉(zhuǎn)分類 ?3、2、1 新節(jié)點(diǎn)插入較高右子樹的右側(cè):左單旋 3、2、2?新節(jié)點(diǎn)插入較高左子樹的左側(cè):右單旋 3、2、3?新節(jié)點(diǎn)插入較高左子樹的右側(cè):左右雙旋(先左后右) 3、2、4?新節(jié)點(diǎn)插入較高右

    2024年02月13日
    瀏覽(21)
  • 【庖丁解?!縱ue-element-admin前端CRUD通用操作組件詳解,對,核心就是crud.js文件

    【庖丁解?!縱ue-element-admin前端CRUD通用操作組件詳解,對,核心就是crud.js文件

    vue-element-admin 框架之所以能夠快速定制應(yīng)用,得益于其通配的CRUD操作,屬性配置多樣化且個性化,能夠滿足絕大部分開發(fā)需求,也方便了代碼生成。 可以深入學(xué)習(xí)重點(diǎn)源文件是: src/components/Crud/crud.js ,一共 863 行代碼,以及下圖中其它四個vue組件,形成了對通用CRUD操作的高

    2024年01月18日
    瀏覽(26)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包