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

詳解數(shù)據(jù)結(jié)構(gòu)中的堆

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


本篇文章主要講解如何構(gòu)建一個堆(本文講的是二叉堆),堆排序以及TOP-K問題。

1.構(gòu)建堆

首先,儲存堆我們用到的是數(shù)組,我們把它封裝為一個結(jié)構(gòu)體

typedef int HDataType;

typedef struct Heap
{
	HDataType* arr;
	int size;
	int capacity;
}Heap;

size是數(shù)組里面有效數(shù)據(jù)的個數(shù),capacity是數(shù)組的容量大小。

雖然堆在物理結(jié)構(gòu)上是一個數(shù)組,但在邏輯結(jié)構(gòu)上我們把它想象做一個完全二叉樹,如下圖
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言
這樣我們可以通過下標來訪問這棵樹。
下面是通過父親訪問孩子:
我們定義父節(jié)點的下標為parent,那左孩子節(jié)點的下標就是parent * 2 + 1,右孩子節(jié)點的下標是parent * 2 + 2,比如上圖中的26 下標是1,1 * 2 + 1是下標為3的左孩子36。
下面是通過孩子訪問父親:
定義孩子下標為child,如果child是左孩子,那么(child - 1) / 2就可以得到父節(jié)點的下標,如果child是右孩子的話,本來我們應(yīng)該是(child - 2) / 2,因為如果減一除二的話可能會得到一個小數(shù),比如(4 - 1) / 2 = 1.5,但這是我們數(shù)學(xué)上的算法,在C語言里,整數(shù)除法是向下取整的,因此結(jié)果還是1,不是1.5,所以無論是左右孩子我們都可以減一除二得到父節(jié)點的下標。

另外,堆分為大堆和小堆,大堆滿足父節(jié)點的數(shù)不小于子節(jié)點,小堆滿足父節(jié)點不大于子節(jié)點。

1.1 向下調(diào)整算法

要想構(gòu)建一個堆,我們得先學(xué)習(xí)向下調(diào)整算法,假設(shè)我們現(xiàn)在有一個堆,左子樹和右子樹都是小堆,只有堆頂不滿足小堆的性質(zhì),比如這棵樹
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言
我們只需要把堆頂?shù)臄?shù)據(jù)調(diào)到合適的位置,它就是一個小堆了,我們可以這樣做:先找出堆頂?shù)淖笥液⒆又行〉哪且粋€,再讓它和堆頂數(shù)據(jù)比較,如果孩子小,就讓它和父節(jié)點進行交換,比如這里的29是父節(jié)點,它的左右孩子是26和16,其中小的是16,然后16和29比,孩子小,就讓16和29進行交換
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言
此時我們交換的是右孩子和父節(jié)點,左邊沒有動過,因此左邊依然是小堆,我們只需要改右邊就可以了,現(xiàn)在新的29是我們下一個要進行比較的父節(jié)點,找出它的左右孩子中小的那一個,當(dāng)然這里只有左孩子20,比較得父節(jié)點大,再交換左孩子和父節(jié)點
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言
此時,我們已經(jīng)成功得到了一個小堆。
下面是代碼實現(xiàn)(建小堆,如果要建大堆改掉一些小于號就可以),參數(shù)中arr是要調(diào)整的數(shù)組,n是數(shù)組的大小,root是堆頂?shù)南聵?/p>

void AdjustDown(HDataType* arr, int n, int root)
{
	int parent = root;
	int child = 2 * parent + 1;
	while (child < n)
	{
		if (child + 1 < n && arr[child] < arr[child + 1]) //child + 1 < n 防止越界
		{
			child = child + 1;
		}
		//到這child下標是兩個孩子中小的呢個的下標
		if (arr[parent] < arr[child])
		{
			swap(&arr[parent], &arr[child]);
		}
		else 
		{
			break;
		}
		parent = child;
		child = 2 * parent + 1;
	}
}

但這樣調(diào)整只適合左子樹和右子樹都已經(jīng)是堆的情況啊,那一般的情況又怎么辦呢?
其實,一棵樹的每個葉節(jié)點可以看做只有它自己的一個堆,因為只有自己,所以它已經(jīng)滿足堆的條件
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言
比如這里的52,11,35,15,73。
如果我們對29進行向下調(diào)整算法,算法就會把29調(diào)到合適的位置,使得這個堆變成小堆,調(diào)完之后我們再調(diào)27,又可以把這個堆調(diào)成小堆,接下來繼續(xù)往回走,再調(diào)46,直到把所有父節(jié)點都調(diào)完,整個堆就變成了小堆。
因為我們是用數(shù)組維護的堆,所以上面這個遍歷父節(jié)點的過程我們可以通過下標減1來遍歷。那怎么找到第一個父節(jié)點29呢,前面我們提到了size是數(shù)組里有效數(shù)據(jù)的個數(shù),所以最后一個數(shù)據(jù)的下標就是size - 1,(size - 1)/ 2就是最后一個父節(jié)點的下標。

下面是利用向下調(diào)整建堆的代碼

	for (int i = (size -1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, size, i);
	}

我們構(gòu)建堆一般是放在堆的初始化函數(shù)里面的,堆的初始化一般就是給你一個數(shù)組,把數(shù)組里面的元素弄成堆。
ph是我們堆的結(jié)構(gòu)體指針,使用前記得先創(chuàng)建一個結(jié)構(gòu)體變量,這里是把它的地址傳進去,s是我們要修改成堆的數(shù)組,n是數(shù)組的大小

void HeapInit(Heap* ph, HDataType* s, int n)
{
	ph->arr = (HDataType*)malloc(sizeof(HDataType) * n);
	memcpy(ph->arr, s, sizeof(HDataType) * n);//把s里面的數(shù)據(jù)復(fù)制到我們的數(shù)組里面
	ph->capacity = ph->size = n;

	//構(gòu)建堆
	for (int i = (n - 1) / 2; i >= 0; i--)
	{
		AdjustDown(ph->arr, n, i);
	}
}

1.2 構(gòu)建堆的時間復(fù)雜度分析

分析建堆的時間復(fù)雜度就是看它運行了多少次,向下調(diào)整算法每次需要移動樹的高度-1次,設(shè)高度為h
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言建堆的時間復(fù)雜度就是每一層的節(jié)點個數(shù)乘以移動的次數(shù),再把每一層相加,設(shè)和為S,即
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言

求這個和我們用到錯位相減法
詳解數(shù)據(jù)結(jié)構(gòu)中的堆,數(shù)據(jù)結(jié)構(gòu),算法,c語言同時,h = logN(默認以2為底),所以時間復(fù)雜度為O(N - logN),因為logN很小,所以也就是O(N)

2.堆排序

2.1 堆排序的實現(xiàn)

堆排序就是用堆這個數(shù)據(jù)結(jié)構(gòu)來對一些數(shù)據(jù)進行排序,如果我們有一個小堆,那么堆頂?shù)臄?shù)就是最小的數(shù),我們需要再找一個次小的數(shù),該怎么找呢?
我們可以這樣做:把堆頂?shù)臄?shù)和數(shù)組中最后一個數(shù)互換,然后把數(shù)組長度減1,認為最后一個數(shù)不是數(shù)組里面的,這樣再對新的堆頂進行向下調(diào)整構(gòu)建新的堆,這個時候的堆頂就是次小的數(shù),再重復(fù)之前的操作,直到數(shù)組里只有一個數(shù)據(jù),這個時候數(shù)組里面的數(shù)據(jù)就排好序了。
需要注意,這種排序 建大堆排升序,建小堆排降序。
代碼實現(xiàn):

void HeapSort(HDataType* arr,int n)
{
	//構(gòu)建堆
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(arr, n, i);
	}
	//開始排序
	int end = n - 1;   //數(shù)組最后一個數(shù)的下標
	while (end > 0)
	{
		swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
		end--;
	}
}

2.2 堆排序的時間復(fù)雜度

堆排序的執(zhí)行次數(shù)是數(shù)據(jù)個數(shù)乘以向下調(diào)整的時間復(fù)雜度,即
O(N * logN),就算加上建堆的時間復(fù)雜度O(N),N 和 N * logN相比,N也比較小,所以直接取O(N * logN)。

3. TOP-K問題

這類問題是給出N個數(shù),求出最?。ㄗ畲螅┑那癒個數(shù),或者是第K?。ù螅┑臄?shù)。
這中問題用堆可以很好地解決,我們用N個數(shù)中的前K個數(shù)構(gòu)建一個大小為K的堆,如果要最大的前K個數(shù),就建小堆,然后再讓堆頂?shù)臄?shù)和剩下的N-K個數(shù)一一比較,如果堆頂?shù)臄?shù)小,就把堆頂?shù)臄?shù)換成大的,再繼續(xù)比較,最終堆里面的K個數(shù)就是最大的前K個數(shù)。
這種方法優(yōu)點是可以解決數(shù)據(jù)太多內(nèi)存放不下的問題,同時時間復(fù)雜度很小,為O(N*logK)。文章來源地址http://www.zghlxwxcb.cn/news/detail-827888.html

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

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

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

相關(guān)文章

  • 初識Go語言25-數(shù)據(jù)結(jié)構(gòu)與算法【堆、Trie樹、用go中的list與map實現(xiàn)LRU算法、用go語言中的map和堆實現(xiàn)超時緩存】

    初識Go語言25-數(shù)據(jù)結(jié)構(gòu)與算法【堆、Trie樹、用go中的list與map實現(xiàn)LRU算法、用go語言中的map和堆實現(xiàn)超時緩存】

    ??堆是一棵二叉樹。大根堆即任意節(jié)點的值都大于等于其子節(jié)點。反之為小根堆。 ??用數(shù)組來表示堆,下標為 i 的結(jié)點的父結(jié)點下標為(i-1)/2,其左右子結(jié)點分別為 (2i + 1)、(2i + 2)。 構(gòu)建堆 ??每當(dāng)有元素調(diào)整下來時,要對以它為父節(jié)點的三角形區(qū)域進行調(diào)整。 插入元素

    2024年02月12日
    瀏覽(93)
  • 【數(shù)據(jù)結(jié)構(gòu)】由完全二叉樹引申出的堆的實現(xiàn)

    【數(shù)據(jù)結(jié)構(gòu)】由完全二叉樹引申出的堆的實現(xiàn)

    關(guān)于“堆”,百度百科上是這么說的: ——————————引自百度百科 由上面可知,我們可以將堆理解成一個數(shù)組,也可以理解成一個完全二叉樹。 其實由于完全二叉樹的特殊性,其本身就可以使用一個數(shù)組來存儲。 在之前的二叉樹的實現(xiàn)中,我們已經(jīng)知道完全二叉樹

    2024年02月08日
    瀏覽(22)
  • 【數(shù)據(jù)結(jié)構(gòu)和算法初階(C語言)】復(fù)雜鏈表(隨機指針,隨機鏈表的復(fù)制)題目詳解+鏈表順序表結(jié)尾

    【數(shù)據(jù)結(jié)構(gòu)和算法初階(C語言)】復(fù)雜鏈表(隨機指針,隨機鏈表的復(fù)制)題目詳解+鏈表順序表結(jié)尾

    目錄 ?1.隨機鏈表的復(fù)制 1.2題目描述? 1.3題目分析 1.4解題: 2.順序表和鏈表對比 2.1cpu高速緩存利用率 3.結(jié)語 一個長度為? n ?的鏈表,每個節(jié)點包含一個額外增加的隨機指針? random ? 該指針可以指向鏈表中的任何節(jié)點或空節(jié)點。? ? ? ? 構(gòu)造這個鏈表的? 深拷貝 。?深拷貝

    2024年03月10日
    瀏覽(93)
  • 數(shù)據(jù)結(jié)構(gòu)--》掌握數(shù)據(jù)結(jié)構(gòu)中的查找算法

    數(shù)據(jù)結(jié)構(gòu)--》掌握數(shù)據(jù)結(jié)構(gòu)中的查找算法

    ????????當(dāng)你需要從大量數(shù)據(jù)中查找某個元素時,查找算法就變得非常重要。 ??????? 無論你是初學(xué)者還是進階者,本文將為你提供簡單易懂、實用可行的知識點,幫助你更好地掌握查找在數(shù)據(jù)結(jié)構(gòu)和算法中的重要性,進而提升算法解題的能力。接下來讓我們開啟數(shù)據(jù)

    2024年02月08日
    瀏覽(31)
  • 數(shù)據(jù)結(jié)構(gòu)--》掌握數(shù)據(jù)結(jié)構(gòu)中的排序算法

    數(shù)據(jù)結(jié)構(gòu)--》掌握數(shù)據(jù)結(jié)構(gòu)中的排序算法

    ????????當(dāng)我們面對海量數(shù)據(jù)時,如何高效地將其排序是數(shù)據(jù)結(jié)構(gòu)領(lǐng)域中一個重要的問題。排序算法作為其中的關(guān)鍵部分,扮演著至關(guān)重要的角色。 ??????? 無論你是初學(xué)者還是進階者,本文將為你提供簡單易懂、實用可行的知識點,幫助你更好地掌握排序算法在數(shù)據(jù)

    2024年02月08日
    瀏覽(32)
  • 【數(shù)據(jù)結(jié)構(gòu)】C語言結(jié)構(gòu)體詳解

    【數(shù)據(jù)結(jié)構(gòu)】C語言結(jié)構(gòu)體詳解

    目錄 前言 一、結(jié)構(gòu)體的定義 二、定義結(jié)構(gòu)體變量 三、結(jié)構(gòu)體變量的初始化 四、使用typedef聲明新數(shù)據(jù)類型名 五、指向結(jié)構(gòu)體變量的指針 總結(jié) ??嗨!我是Filotimo__??。很高興與大家相識,希望我的博客能對你有所幫助。 ??本文由Filotimo__??原創(chuàng),首發(fā)于CSDN??。 ??如需轉(zhuǎn)

    2024年02月04日
    瀏覽(24)
  • 數(shù)據(jù)結(jié)構(gòu)(五)數(shù)據(jù)結(jié)構(gòu)與算法中的經(jīng)典題

    本文是在原本數(shù)據(jù)結(jié)構(gòu)與算法闖關(guān)的基礎(chǔ)上總結(jié)得來,加入了自己的理解和部分習(xí)題講解。至此數(shù)據(jù)結(jié)構(gòu)介紹已完結(jié),后續(xù)會把數(shù)據(jù)結(jié)構(gòu)算法題系列更完。 原活動鏈接 邀請碼: JL57F5 根據(jù)要求完成題目 Q1. (單選)以下哪些數(shù)據(jù)結(jié)構(gòu)支持隨機訪問? A. 數(shù)組 B. 單鏈表 C. 雙向鏈表

    2024年01月20日
    瀏覽(26)
  • 數(shù)據(jù)結(jié)構(gòu)與算法——數(shù)據(jù)結(jié)構(gòu)有哪些,常用數(shù)據(jù)結(jié)構(gòu)詳解

    數(shù)據(jù)結(jié)構(gòu)與算法——數(shù)據(jù)結(jié)構(gòu)有哪些,常用數(shù)據(jù)結(jié)構(gòu)詳解

    數(shù)據(jù)結(jié)構(gòu)是學(xué)習(xí)數(shù)據(jù)存儲方式的一門學(xué)科,那么,數(shù)據(jù)存儲方式有哪幾種呢?下面將對數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)內(nèi)容做一個簡要的總結(jié)。 數(shù)據(jù)結(jié)構(gòu)大致包含以下幾種存儲結(jié)構(gòu): 線性表,還可細分為順序表、鏈表、棧和隊列; 樹結(jié)構(gòu),包括普通樹,二叉樹,線索二叉樹等; 圖存儲結(jié)構(gòu)

    2024年02月15日
    瀏覽(19)
  • R語言中的常用數(shù)據(jù)結(jié)構(gòu)

    R語言中的常用數(shù)據(jù)結(jié)構(gòu)

    目錄 R對象的基本類型 R對象的屬性 R的數(shù)據(jù)結(jié)構(gòu) 向量 矩陣 數(shù)組 列表 因子 缺失值NA 數(shù)據(jù)框 R的數(shù)據(jù)結(jié)構(gòu)總結(jié) R語言可以進行探索性數(shù)據(jù)分析,統(tǒng)計推斷,回歸分析,機器學(xué)習(xí),數(shù)據(jù)產(chǎn)品開發(fā) R語言對象有五種基本類型,分別是字符,數(shù)值,整數(shù),復(fù)數(shù),邏輯 你可能有疑問,整

    2024年04月12日
    瀏覽(15)
  • C語言數(shù)據(jù)結(jié)構(gòu)與算法

    冒泡排序 例題 順序表下的 冒泡排序 注意:冒泡排序 穩(wěn)定,最多執(zhí)行n(n-1)/2次 選擇排序不穩(wěn)定,平均比較次數(shù)n(n-1)/2 直接插入排序,是在有序基礎(chǔ)上,速度最快且穩(wěn)定的排序方法。 希爾排序是 不穩(wěn)定的 順序查找 二分查找(非遞歸) 二分查找(遞歸) 數(shù)組 鏈表 查詢 快 慢

    2024年02月06日
    瀏覽(92)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包