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

【高階數(shù)據(jù)結構】跳表

這篇具有很好參考價值的文章主要介紹了【高階數(shù)據(jù)結構】跳表。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


一、什么是跳表

skiplist本質(zhì)上也是一種查找結構,用于解決算法中的查找問題,跟平衡搜索樹和哈希表的價值是
一樣的,可以作為key或者key/value的查找模型。那么相比而言它的優(yōu)勢是什么的呢?這么等我
們學習完它的細節(jié)實現(xiàn),我們再來對比。

skiplist 是由 William Pugh 發(fā)明的,最早出現(xiàn)于他在1990年發(fā)表的論文 《Skip Lists: AProbabilistic Alternative to Balanced Trees》

skiplist,顧名思義,首先它是一個list。實際上,它是在有序鏈表的基礎上發(fā)展起來的。如果是一
個有序的鏈表,查找數(shù)據(jù)的時間復雜度是O(N)

William Pugh開始的優(yōu)化思路:

  1. 假如我們每相鄰兩個節(jié)點升高一層,增加一個指針,讓指針指向下下個節(jié)點,如下圖b所示。這樣所有新增加的指針連成了一個新的鏈表,但它包含的節(jié)點個數(shù)只有原來的一半。由于新增加的指針,我們不再需要與鏈表中每個節(jié)點逐個進行比較了,需要比較的節(jié)點數(shù)大概只有原來的一半。
  2. 以此類推,我們可以在第二層新產(chǎn)生的鏈表上,繼續(xù)為每相鄰的兩個節(jié)點升高一層,增加一個指針,從而產(chǎn)生第三層鏈表。如下圖c,這樣搜索效率就進一步提高了。
  3. skiplist正是受這種多層鏈表的想法的啟發(fā)而設計出來的。實際上,按照上面生成鏈表的方式,上面每一層鏈表的節(jié)點個數(shù),是下面一層的節(jié)點個數(shù)的一半,這樣查找過程就非常類似二分查找,使得查找的時間復雜度可以降低到O(log n)。但是這個結構在插入刪除數(shù)據(jù)的時候有很大的問題,插入或者刪除一個節(jié)點之后,就會打亂上下相鄰兩層鏈表上節(jié)點個數(shù)嚴格的2:1的對應關系。如果要維持這種對應關系,就必須把新插入的節(jié)點后面的所有節(jié)點(也包括新插入的節(jié)點)重新進行調(diào)整,這會讓時間復雜度重新蛻化成O(n)。
    【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis
    查找的過程:假如要查找的值是key,那么需要看下一個節(jié)點的值是否比key大,如果比key大, 就向下走。如果比key小,就向右走。如果沒有找到,就會走到第-1層。
    skiplist的設計為了避免這種問題,做了一個大膽的處理,不再嚴格要求對應比例關系,而是插入一個節(jié)點的時候隨機出一個層數(shù)。這樣每次插入和刪除都不需要考慮其他節(jié)點的層數(shù),這樣就好處理多了。細節(jié)過程入下圖:
    【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

二、跳表的效率如何保證?

上面我們說到,skiplist插入一個節(jié)點時隨機出一個層數(shù),聽起來怎么這么隨意,如何保證搜索時的效率呢?
這里首先要細節(jié)分析的是這個隨機層數(shù)是怎么來的。一般跳表會設計一個最大層數(shù)maxLevel的限制,其次會設置一個多增加一層的概率p。那么計算這個隨機層數(shù)的偽代碼如下圖:
【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

在 Redis 的 skiplist 實現(xiàn)中,這兩個參數(shù)的取值為:p = 1/4maxLevel = 32。注:谷歌的開源項目 LevelDB(小型的 KV 型數(shù)據(jù)庫)也采用了 skiplist,有興趣的大佬可以了解一下!

根據(jù)前面randomLevel()的偽碼,我們很容易看出,產(chǎn)生越高的節(jié)點層數(shù),概率越低。定量的分析
如下:

  • 節(jié)點層數(shù)至少為1。而大于1的節(jié)點層數(shù),滿足一個概率分布。
  • 節(jié)點層數(shù)恰好等于1的概率為1-p。
  • 節(jié)點層數(shù)大于等于2的概率為p,而節(jié)點層數(shù)恰好等于2的概率為p(1-p)。
  • 節(jié)點層數(shù)大于等于3的概率為p2,而節(jié)點層數(shù)恰好等于3的概率為p2*(1-p)。
  • 節(jié)點層數(shù)大于等于4的概率為p3,而節(jié)點層數(shù)恰好等于4的概率為p3*(1-p)

因此,一個節(jié)點的平均層數(shù)(也包含的平均指針數(shù)目)計算如下:

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis
現(xiàn)在很容易計算出:

  • 當p=1/2時,每個節(jié)點所包含的平均指針數(shù)目為2;
  • 當p=1/4時,每個節(jié)點所包含的平均指針數(shù)目為1.33。

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

跳表的平均時間復雜度為O(logN),這個推導的過程比較復雜,這里我們稍微提一下。


三、skiplist的實現(xiàn)

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

結點的設計

struct SkiplistNode
{
	int _val;
	vector<SkiplistNode*> _nextV;

	SkiplistNode(int val, int level)
		:_val(val)
		, _nextV(level, nullptr)
	{}
};

因為每個結點的層數(shù)是隨機的,所以申請一個新節(jié)點需要知道其層數(shù)和存儲的值,通過vector的下標可以表示層數(shù)。

整體設計

class Skiplist {
	typedef SkiplistNode Node;
public:
	Skiplist() {
		srand(time(0));

		// 頭節(jié)點,層數(shù)是1
		_head = new SkiplistNode(-1, 1);
	}

private:
	Node* _head; // 哨兵位頭節(jié)點
	size_t _maxLevel = 32; // 最高的層數(shù)
	double _p = 0.25; // 增加一層的概率
};

哨兵位頭節(jié)點的層數(shù)是該跳表中最高的,初始時讓哨兵位的層數(shù)為1.增加一層的概率是0.25,理論而言,概率越大,效率越高。

節(jié)點的隨機層數(shù)

計算這個隨機層數(shù)的偽代碼如下圖:

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

C語言產(chǎn)生隨機數(shù)

int RandomLevel()
{
	size_t level = 1;
	// rand() ->[0, RAND_MAX]之間
	// rand() 《= RAND_MAX*_p 可以保證增加一層的概率是_p
	// level <= maxLevel 保證隨機層數(shù)不超過最高層數(shù)maxLevel
	while (rand() <= RAND_MAX*_p && level < _maxLevel)
	{
		++level;
	}
	return level;
}

C++產(chǎn)生隨機數(shù)

int RandomLevel()
{
	static std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());
	static std::uniform_real_distribution<double> distribution(0.0, 1.0);

	size_t level = 1;
	while (distribution(generator) <= _p && level < _maxLevel)
	{
		++level;
	}

	return level;
}

這里我們需要注意的是:因為C語言產(chǎn)生的隨機數(shù)范圍是0到32767之間的數(shù),范圍比較小。不過可以通過加減一些數(shù)來擴大隨機數(shù)的范圍。

skiplist的查找

查找的過程:查找是要和下一個節(jié)點的值相比,并不是和當前節(jié)點的值相比一開始cur在哨兵位頭節(jié)點的最高層 head,開始進行比較。假如要查找的值為target,如果下一個節(jié)點為空或者下一個節(jié)點的值比target大,那么cur需要向下一層走;如果下一個節(jié)點的值比target下,那么cur向右走。重復上述過程,直至找到或者沒找到(沒找到的話,cur會去到第-1層,注:層數(shù)是從第0層開始的)

bool search(int target) {
	Node* cur = _head;
	int level = _head->_nextV.size() - 1;
	while (level >= 0)
	{
		// 目標值比下一個節(jié)點值要大,向右走
		// 下一個節(jié)點是空(尾),目標值比下一個節(jié)點值要小,向下走
		if (cur->_nextV[level] && cur->_nextV[level]->_val < target)
		{
			// 向右走
			cur = cur->_nextV[level];
		}
		else if (cur->_nextV[level] == nullptr || cur->_nextV[level]->_val > target)
		{
			// 向下走
			--level;
		}
		else
		{
			return true;
		}
	}
	
	return false;
}

skiplist的插入

無論是插入值還是刪除值,都需要找到該值的前面的節(jié)點,這樣才能修改指針的指向關系。我們可以將這個保存前一個指針的操作封裝成一個函數(shù),提供給插入和刪除接口使用。

vector<Node*> FindPrevNode(int num)
{
	Node* cur = _head;
	int level = _head->_nextV.size() - 1;

	// 插入位置每一層前一個節(jié)點指針
	vector<Node*> prevV(level + 1, _head);

	while (level >= 0)
	{
		// 目標值比下一個節(jié)點值要大,向右走
		// 下一個節(jié)點是空(尾),目標值比下一個節(jié)點值要小,向下走
		if (cur->_nextV[level] && cur->_nextV[level]->_val < num)
		{
			// 向右走
			cur = cur->_nextV[level];
		}
		else if (cur->_nextV[level] == nullptr
			|| cur->_nextV[level]->_val >= num)
		{
			// 更新level層前一個
			prevV[level] = cur;

			// 向下走
			--level;
		}
	}

	return prevV;
}

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

void add(int num) {
	vector<Node*> prevV = FindPrevNode(num);
	
	int n = RandomLevel();
	Node* newnode = new Node(num, n);
	
	// 如果n超過當前最大的層數(shù),那就升高一下_head的層數(shù)
	if (n > _head->_nextV.size())
	{
		_head->_nextV.resize(n, nullptr);
		prevV.resize(n, _head);
	}
	
	// 鏈接前后節(jié)點
	for (size_t i = 0; i < n; ++i)
	{
		newnode->_nextV[i] = prevV[i]->_nextV[i];
		prevV[i]->_nextV[i] = newnode;
	}
}

刪除節(jié)點
【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

bool erase(int num) {
	vector<Node*> prevV = FindPrevNode(num);

	// 第一層下一個不是val,val不在表中
	if (prevV[0]->_nextV[0] == nullptr || prevV[0]->_nextV[0]->_val != num)
	{
		return false;
	}
	else
	{
		Node* del = prevV[0]->_nextV[0];
		// del節(jié)點每一層的前后指針鏈接起來
		for (size_t i = 0; i < del->_nextV.size(); i++)
		{
			prevV[i]->_nextV[i] = del->_nextV[i];
		}
		delete del;

		// 如果刪除最高層節(jié)點,把頭節(jié)點的層數(shù)也降一下
		int i = _head->_nextV.size() - 1;
		while (i >= 0)
		{
			if (_head->_nextV[i] == nullptr)
				--i;
			else
				break;
		}
		_head->_nextV.resize(i + 1);

		return true;
}

注意:如果刪除的節(jié)點的層數(shù)是最高的,那么可以將哨兵位頭結點的層數(shù)降一降。如何判斷刪除的節(jié)點層數(shù)是不是最高的呢?從哨兵位頭結點的最高層其,如果該層的指針指向空,那么就說明刪除的節(jié)點層數(shù)最高。當前層指針指向空,那么就需要看下一層指針是否指向空。以此類推,直至指針不在指向空,那么就可以求出刪除最高節(jié)點后剩余節(jié)點的最高層數(shù)了。

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis

打印跳表

void Print()
{
	Node* cur = _head;
	while (cur)
	{
		printf("%2d\n", cur->_val);
		// 打印每個每個cur節(jié)點
		for (auto e : cur->_nextV)
		{
			printf("%2s", "↓");
		}	
		printf("\n");

		cur = cur->_nextV[0];
	}
}

打印跳表函數(shù)可以讓我們更好的觀察跳表的樣子。

完整代碼

#include <iostream>
#include <vector>
#include <time.h>
#include <random>
#include <chrono>
using namespace std;

struct SkiplistNode
{
	int _val;
	vector<SkiplistNode*> _nextV;

	SkiplistNode(int val, int level)
		:_val(val)
		, _nextV(level, nullptr)
	{}
};

class Skiplist {
	typedef SkiplistNode Node;
public:
	Skiplist() {
		srand(time(0));

		// 頭節(jié)點,層數(shù)是1
		_head = new SkiplistNode(-1, 1);
	}

	bool search(int target) {
		Node* cur = _head;
		int level = _head->_nextV.size() - 1;
		while (level >= 0)
		{
			// 目標值比下一個節(jié)點值要大,向右走
			// 下一個節(jié)點是空(尾),目標值比下一個節(jié)點值要小,向下走
			if (cur->_nextV[level] && cur->_nextV[level]->_val < target)
			{
				// 向右走
				cur = cur->_nextV[level];
			}
			else if (cur->_nextV[level] == nullptr || cur->_nextV[level]->_val > target)
			{
				// 向下走
				--level;
			}
			else
			{
				return true;
			}
		}

		return false;
	}

	vector<Node*> FindPrevNode(int num)
	{
		Node* cur = _head;
		int level = _head->_nextV.size() - 1;

		// 插入位置每一層前一個節(jié)點指針
		vector<Node*> prevV(level + 1, _head);

		while (level >= 0)
		{
			// 目標值比下一個節(jié)點值要大,向右走
			// 下一個節(jié)點是空(尾),目標值比下一個節(jié)點值要小,向下走
			if (cur->_nextV[level] && cur->_nextV[level]->_val < num)
			{
				// 向右走
				cur = cur->_nextV[level];
			}
			else if (cur->_nextV[level] == nullptr
				|| cur->_nextV[level]->_val >= num)
			{
				// 更新level層前一個
				prevV[level] = cur;

				// 向下走
				--level;
			}
		}

		return prevV;
	}

	void add(int num) {
		vector<Node*> prevV = FindPrevNode(num);

		int n = RandomLevel();
		Node* newnode = new Node(num, n);

		// 如果n超過當前最大的層數(shù),那就升高一下_head的層數(shù)
		if (n > _head->_nextV.size())
		{
			_head->_nextV.resize(n, nullptr);
			prevV.resize(n, _head);
		}

		// 鏈接前后節(jié)點
		for (size_t i = 0; i < n; ++i)
		{
			newnode->_nextV[i] = prevV[i]->_nextV[i];
			prevV[i]->_nextV[i] = newnode;
		}
	}

	bool erase(int num) {
		vector<Node*> prevV = FindPrevNode(num);

		// 第一層下一個不是val,val不在表中
		if (prevV[0]->_nextV[0] == nullptr || prevV[0]->_nextV[0]->_val != num)
		{
			return false;
		}
		else
		{
			Node* del = prevV[0]->_nextV[0];
			// del節(jié)點每一層的前后指針鏈接起來
			for (size_t i = 0; i < del->_nextV.size(); i++)
			{
				prevV[i]->_nextV[i] = del->_nextV[i];
			}
			delete del;

			// 如果刪除最高層節(jié)點,把頭節(jié)點的層數(shù)也降一下
			int i = _head->_nextV.size() - 1;
			while (i >= 0)
			{
				if (_head->_nextV[i] == nullptr)
					--i;
				else
					break;
			}
			_head->_nextV.resize(i + 1);

			return true;
		}

		
	}

	//int RandomLevel()
	//{
	//	size_t level = 1;
	//	// rand() ->[0, RAND_MAX]之間
	//	while (rand() <= RAND_MAX*_p && level < _maxLevel)
	//	{
	//		++level;
	//	}

	//	return level;
	//}

	int RandomLevel()
	{
		static std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());
		static std::uniform_real_distribution<double> distribution(0.0, 1.0);

		size_t level = 1;
		while (distribution(generator) <= _p && level < _maxLevel)
		{
			++level;
		}

		return level;
	}

	void Print()
	{
		/*int level = _head->_nextV.size();
		for (int i = level - 1; i >= 0; --i)
		{
			Node* cur = _head;
			while (cur)
			{
				printf("%d->", cur->_val);
				cur = cur->_nextV[i];
			}
			printf("\n");
		}*/

		Node* cur = _head;
		while (cur)
		{
			printf("%2d\n", cur->_val);
			// 打印每個每個cur節(jié)點
			for (auto e : cur->_nextV)
			{
				printf("%2s", "↓");
			}	
			printf("\n");

			cur = cur->_nextV[0];
		}
	}
	
private:
	Node* _head;
	size_t _maxLevel = 32;
	double _p = 0.5;
};

四、skiplist跟平衡搜索樹和哈希表的對比

  • skiplist 相比平衡搜索樹(AVL 樹和紅黑樹)對比,都可以做到遍歷數(shù)據(jù)有序,時間復雜度也差不多。skiplist 的優(yōu)勢是:a、skiplist 實現(xiàn)簡單,容易控制。平衡樹增刪查改遍歷都更復雜。b、skiplist 的額外空間消耗更低。平衡樹節(jié)點存儲每個值有三叉鏈,平衡因子或者顏色等消耗。skiplist 中 p = 1 / 2 時,每個節(jié)點所包含的平均指針數(shù)目為 2;skiplist 中 p = 1 / 4 時,每個節(jié)點所包含的平均指針數(shù)目為 1.33;
  • skiplist 相比哈希表而言,就沒有那么大的優(yōu)勢了。相比而言,a、哈希表平均時間復雜度是 O(1),比 skiplist快。b、哈希表空間消耗略多一點。skiplist 優(yōu)勢如下:a、遍歷數(shù)據(jù)有序。b、skiplist 空間消耗略小一點,哈希表存在鏈接指針和表空間消耗。c、哈希表擴容有性能損耗。d、哈希表在極端場景下哈希沖突高,效率下降厲害,需要紅黑樹補足接力。

【高階數(shù)據(jù)結構】跳表,數(shù)據(jù)結構,數(shù)據(jù)結構,redis文章來源地址http://www.zghlxwxcb.cn/news/detail-600168.html


到了這里,關于【高階數(shù)據(jù)結構】跳表的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關文章

  • Redis從入門到精通【高階篇】之底層數(shù)據(jù)結構整數(shù)集(IntSet)詳解

    Redis從入門到精通【高階篇】之底層數(shù)據(jù)結構整數(shù)集(IntSet)詳解

    上個篇章回顧,我們上個章節(jié)我們學習了《Redis從入門到精通【高階篇】之底層數(shù)據(jù)結構字典(Dictionary)詳解》,我們從源碼層了解字典是一種以鍵值對(key-value)形式存儲數(shù)據(jù)的數(shù)據(jù)結構。在 Redis 中,字典使用哈希表來實現(xiàn)。哈希表是一種以常數(shù)時間復雜度 O(1) 進行插入、刪

    2024年02月09日
    瀏覽(19)
  • Redis從入門到精通【高階篇】之底層數(shù)據(jù)結構壓縮列表(ZipList)詳解

    Redis從入門到精通【高階篇】之底層數(shù)據(jù)結構壓縮列表(ZipList)詳解

    前面的Redis從入門到精通的基礎篇和進階篇都是在使用層面和概念層面,本章節(jié),我們了解一下redis的底層數(shù)據(jù)結構,上幾個章節(jié),我們講了SDS,字典 。本章節(jié)我們聊一下ZipList。 壓縮列表(ZipList)就是redis為了節(jié)約內(nèi)存而設計開發(fā)的數(shù)據(jù)結構,并且作為列表鍵和哈希鍵的底層

    2024年02月08日
    瀏覽(25)
  • 數(shù)據(jù)結構---跳表

    數(shù)據(jù)結構---跳表

    在前面的學習過程中我們學習過鏈表這個容器,這個容器在頭部和尾部插入數(shù)據(jù)的時間復雜度為O(1),但是該容器存在一個缺陷就是不管數(shù)據(jù)是否有序查找數(shù)據(jù)是否存在的時間復雜度都是O(N),我們只能通過暴力循環(huán)的方式查找數(shù)據(jù)是否存在,盡管數(shù)據(jù)是有序的我們也不能通過二

    2024年02月13日
    瀏覽(24)
  • 數(shù)據(jù)結構:跳表講解

    數(shù)據(jù)結構:跳表講解

    1.1簡介 skiplist本質(zhì)上也是一種 查找結構 ,用于解決算法中的查找問題,跟 平衡搜索樹和哈希表 的價值是一樣的,可以 作為key或者key/value的查找模型 。后面我會進行比對。 skiplist是由 William Pugh發(fā)明 的,最早出現(xiàn)于他在1990年發(fā)表的論文《Skip Lists: A Probabilistic Alternative to Ba

    2024年02月22日
    瀏覽(16)
  • 算法與數(shù)據(jù)結構-跳表

    算法與數(shù)據(jù)結構-跳表

    對于一個單鏈表來講,即便鏈表中存儲的數(shù)據(jù)是有序的,如果我們要想在其中查找某個數(shù)據(jù),也只能從頭到尾遍歷鏈表。這樣查找效率就會很低,時間復雜度會很高,是 O(n)。 那怎么來提高查找效率呢?如果像圖中那樣,對鏈表建立一級“索引”,查找起來是不是就會更快一

    2024年02月13日
    瀏覽(11)
  • 【數(shù)據(jù)結構】3.跳表和散列

    【數(shù)據(jù)結構】3.跳表和散列

    跳表可以近似實現(xiàn)二分查找的效果 以下面長度為7的鏈表舉例,該跳表通過3條鏈表進行存儲。假設要查找元素80: 首先在第2級鏈表查找,因為80大于40,所以在第3個節(jié)點右側查找 然后在第1級鏈表查找,因為80大于75,所以在第5個節(jié)點右側查找 最后在第0級鏈表查找,找到元素

    2024年02月08日
    瀏覽(29)
  • 數(shù)據(jù)結構:跳表的原理和運用

    數(shù)據(jù)結構:跳表的原理和運用

    本篇總結的是跳表的相關內(nèi)容 skiplist 本質(zhì)上也是一種查找結構,用于解決算法中的查找問題,跟平衡搜索樹和哈希表的價值是一樣的,可以作為 key 或者 key/value 的查找模型 假如我們每相鄰兩個節(jié)點升高一層,增加一個指針,讓指針指向下下個節(jié)點,如下圖所示。這樣所有新

    2024年02月22日
    瀏覽(19)
  • 數(shù)據(jù)結構與算法05:跳表和散列表

    數(shù)據(jù)結構與算法05:跳表和散列表

    目錄 【跳表】 跳表的實現(xiàn)原理 如何確定跳表的層高? 【散列表】 散列函數(shù)的設計 散列沖突 (1)開放尋址法(Open Addressing) (2)鏈表法(chaining) 裝載因子 如何設計一個比較合理高效的散列表? 散列表的應用:單詞拼寫檢查 散列表的應用:LRU緩存淘汰算法 【每日一練

    2024年02月07日
    瀏覽(27)
  • 【算法&數(shù)據(jù)結構體系篇class36】有序表 (中篇)SB樹、跳表

    1 )讓每一個叔叔節(jié)點為頭的數(shù),節(jié)點個數(shù)都不少于其任何一個侄子節(jié)點 2 )也是從底層被影響節(jié)點開始向上做路徑每個節(jié)點檢查 3 )與 AVL 樹非常像,也是四種違規(guī)類型: LL 、 RR 、 LR 、 RL 4 )與 AVL 樹非常像,核心點是: LL (做一次右旋)、 RR (做一次左旋) LR 和 RL (利

    2024年02月03日
    瀏覽(25)
  • 高階數(shù)據(jù)結構 ——— 并查集

    高階數(shù)據(jù)結構 ——— 并查集

    并查集是一種樹型的數(shù)據(jù)結構,用于處理一些不相交集合的合并及查詢問題。 并查集通常用森林來表示,森林中的每棵樹表示一個集合,樹中的結點對應一個元素。 說明一下: 雖然利用其他數(shù)據(jù)結構也能完成不相交集合的合并及查詢,但在數(shù)據(jù)量極大的情況下,其耗費的時

    2024年02月03日
    瀏覽(66)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領取紅包

二維碼2

領紅包