數(shù)據(jù)結(jié)構(gòu)之堆詳解
1. 概述
堆(也叫優(yōu)先隊(duì)列),是一棵完全二叉樹,它的特點(diǎn)是父節(jié)點(diǎn)的值大于(小于)兩個(gè)子節(jié)點(diǎn)的值(分別稱為大頂堆和小頂堆)。它常用于管理算法執(zhí)行過程中的信息,應(yīng)用場景包括堆排序,優(yōu)先隊(duì)列等。
2. 堆的基本操作
堆是一棵完全二叉樹,高度為O(lg n),其基本操作至多與樹的高度成正比。在介紹堆的基本操作之前,先介紹幾個(gè)基本術(shù)語:
A:用于表示堆的數(shù)組,下標(biāo)從1開始,一直到n
PARENT(t):節(jié)點(diǎn)t的父節(jié)點(diǎn),即floor(t/2)
RIGHT(t):節(jié)點(diǎn)t的左孩子節(jié)點(diǎn),即:2*t
LEFT(t):節(jié)點(diǎn)t的右孩子節(jié)點(diǎn),即:2*t+1
HEAP_SIZE(A):堆A當(dāng)前的元素?cái)?shù)目
下面給出其主要的四個(gè)操作(以大頂堆為例):
2.1 Heapify(A,n,t)
該操作主要用于維持堆的基本性質(zhì)。假定以RIGHT(t)和LEFT(t)為根的子樹都已經(jīng)是堆,然后調(diào)整以t為根的子樹,使之成為堆。
void Heapify(int A[], int n, int t)
{
int left = LEFT(t);
int right = RIGHT(t);
int max = t;
if(left <= n) max = A[left] > A[max] ? left : max;
if(right <= n) max = A[right] > A[max] ? right : max;
if(max != A[t])
{
swap(A, max, t);
Heapify(A, n, max);
}
}
2.2 BuildHeap(A,n)
該操作主要是將數(shù)組A轉(zhuǎn)化成一個(gè)大頂堆。思想是,先找到堆的最后一個(gè)非葉子節(jié)點(diǎn)(即為第n/2個(gè)節(jié)點(diǎn)),然后從該節(jié)點(diǎn)開始,從后往前逐個(gè)調(diào)整每個(gè)子樹,使之稱為堆,最終整個(gè)數(shù)組便是一個(gè)堆。
void BuildHeap(int A[], int n)
{
int i;
for(i = n/2; i<=n; i++)
Heapify(A, n, i);
}
2.3 GetMaximum(A,n)
該操作主要是獲取堆中最大的元素,同時(shí)保持堆的基本性質(zhì)。堆的最大元素即為第一個(gè)元素,將其保存下來,同時(shí)將最后一個(gè)元素放到A[1]位置,之后從上往下調(diào)整A,使之成為一個(gè)堆。
void GetMaximum(int A[], int n)
{
int max = A[1];
A[1] = A[n];
n--;
Heapify(A, n, 1);
return max;
}
2.4 Insert(A, n, t)
向堆中添加一個(gè)元素t,同時(shí)保持堆的性質(zhì)。算法思想是,將t放到A的最后,然后從該元素開始,自下向上調(diào)整,直至A成為一個(gè)大頂堆。
void Insert(int A[], int n, int t)
{
n++;
A[n] = t;
int p = n;
while(p >1 && A[PARENT(p)] < t)
{
A[p] = A[PARENT(p)];
p = PARENT(p);
}
A[p] = t;
return max;
}
3. 堆的應(yīng)用
3.1 堆排序
堆的最常見應(yīng)用是堆排序,時(shí)間復(fù)雜度為O(N lg N)。如果是從小到大排序,用大頂堆;從大到小排序,用小頂堆。
3.2 在O(n lg k)時(shí)間內(nèi),將k個(gè)排序表合并成一個(gè)排序表,n為所有有序表中元素個(gè)數(shù)。
【解析】取前100 萬個(gè)整數(shù),構(gòu)造成了一棵數(shù)組方式存儲的具有小頂堆,然后接著依次取下一個(gè)整數(shù),如果它大于最小元素亦即堆頂元素,則將其賦予堆頂元素,然后用Heapify調(diào)整整個(gè)堆,如此下去,則最后留在堆中的100萬個(gè)整數(shù)即為所求 100萬個(gè)數(shù)字。該方法可大大節(jié)約內(nèi)存。
3.3 一個(gè)文件中包含了1億個(gè)隨機(jī)整數(shù),如何快速的找到最大(小)的100萬個(gè)數(shù)字?(時(shí)間復(fù)雜度:O(n lg k))
4. 總結(jié)
堆是一種非?;A(chǔ)但很實(shí)用的數(shù)據(jù)結(jié)構(gòu),很多復(fù)雜算法或者數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)就是堆,因而,了解和掌握堆這種數(shù)據(jù)結(jié)構(gòu)顯得尤為重要。
5. 參考資料
(1)經(jīng)典算法教程《算法導(dǎo)論》
上一篇:數(shù)據(jù)結(jié)構(gòu)之AVL樹詳解
欄 目:C語言
下一篇:深入理解C++中public、protected及private用法
本文標(biāo)題:數(shù)據(jù)結(jié)構(gòu)之堆詳解
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3436.html
您可能感興趣的文章
- 01-10求子數(shù)組最大和的解決方法詳解
- 01-10深入二叉樹兩個(gè)結(jié)點(diǎn)的最低共同父結(jié)點(diǎn)的詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)- 解析最少換車次數(shù)的問題詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)-用棧實(shí)現(xiàn)表達(dá)式求值的方法詳解
- 01-10HDOJ 1443 約瑟夫環(huán)的最新應(yīng)用分析詳解
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10如何查看進(jìn)程實(shí)際的內(nèi)存占用情況詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10APUE筆記之:進(jìn)程環(huán)境詳解
- 01-10深入第K大數(shù)問題以及算法概要的詳解


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 04-02jquery與jsp,用jquery
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁面的局部加載