日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

算法导论:堆排序

發(fā)布時(shí)間:2025/3/8 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法导论:堆排序 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

堆是一個(gè)數(shù)組,它可以被看成一個(gè)近似的完全二叉樹(shù),樹(shù)上的每一個(gè)結(jié)點(diǎn)對(duì)應(yīng)數(shù)組中的一個(gè)元素。除去最底層外,該樹(shù)是完全充滿的,而且從左到右填充。

用數(shù)組A表示堆,從數(shù)組第1個(gè)元素開(kāi)始,數(shù)組中第i(1<=i <=n)個(gè)元素,其父結(jié)點(diǎn),左孩子,右孩子的下標(biāo)如下

// 父結(jié)點(diǎn)public int parent( int i){return i/2;}// 左孩子public int left(int i){return 2*i;}// 右孩子public int right(int i){return 2*i+1;}

?當(dāng)數(shù)組起始下標(biāo)是0的時(shí)候,其父結(jié)點(diǎn),左右孩子結(jié)點(diǎn)如下

// 父結(jié)點(diǎn)public int parent( int i){return (i-1)/2;}// 左孩子public int left(int i){return 2*i+1;}// 右孩子public int right(int i){return 2*i+2;}

?

堆可以分為大頂堆和小頂堆

大頂堆:結(jié)點(diǎn) i 的值 都大于其左右孩子結(jié)點(diǎn)的值

小頂堆:結(jié)點(diǎn) i 的值 都小于其左右孩子結(jié)點(diǎn)的值

二叉樹(shù)的形式與數(shù)組形式表達(dá)堆之間元素的關(guān)系

?

練習(xí)1,高度為h的堆,元素最少和最多是多少?

最多:這個(gè)完全二叉樹(shù)第h層元素填滿:2^h - 1

最少:第h-1層填滿,第h層只有一個(gè)元素:2^(h-1) -1 + 1 = 2^(h-1)

說(shuō)明:h=1 表示第一層

練習(xí)2,含有n個(gè)元素的堆的高度是 [lgn]

練習(xí)3,當(dāng)用數(shù)組存放堆的時(shí)候,堆的元素時(shí)候n,求葉子結(jié)點(diǎn)下標(biāo)

?

構(gòu)建大頂堆

max-heapify 用于維護(hù)一個(gè)大頂堆。它的輸入是一個(gè)數(shù)組A和下標(biāo)i。在調(diào)用max-heapify的時(shí)候,假定根結(jié)點(diǎn)left(i) 和right(i) 的二叉樹(shù)都是大頂堆,但這時(shí)A[i]有可能小于其中的一個(gè)孩子,這樣就違背大頂堆的性質(zhì)。我們需要進(jìn)行調(diào)整,選取left(i) right(i) 對(duì)應(yīng)結(jié)點(diǎn)較大的一個(gè)和 i 位置處的結(jié)點(diǎn)進(jìn)行互換。

建堆代碼如下

/*** 調(diào)整堆元素* @param A* @param n* @param i*/public void max_heapify(int[] A ,int n,int i){// 左孩子結(jié)點(diǎn)int l = left(i);// 右孩子結(jié)點(diǎn)int r = right(i);// 最大結(jié)點(diǎn)下標(biāo)int largest = -1;// 與左孩子判斷if(l<= n && A[l] > A[i])largest = l;elselargest = i;// 與右孩子判斷if(r <=n && A[r] > A[largest])largest = r;// i 結(jié)點(diǎn)不是最大值maxId 和i 結(jié)點(diǎn)進(jìn)行交換if(largest != i ){swap(A,largest,i); max_heapify(A,n,largest);}}/*** 交換* @param A* @param l* @param r*/public void swap(int [] A,int l,int r){int tmp = A[l];A[l] = A[r];A[r] = tmp;}

?

?時(shí)間復(fù)雜度:O(lg(n))

說(shuō)明:

在 i left(i) right(i) 三個(gè)結(jié)點(diǎn)中,選取其對(duì)應(yīng)的值最大的結(jié)點(diǎn)和 i 結(jié)點(diǎn)的值進(jìn)行交換。在交換后,下標(biāo)為largest的結(jié)點(diǎn)的值是原來(lái)的A[i] 的值,largest所在的結(jié)點(diǎn)的子樹(shù)可能違反大頂堆的性質(zhì),需要對(duì)該子樹(shù)遞歸調(diào)用max-heapify

這里的假設(shè)是 以left(i) right(i) 為結(jié)點(diǎn)的堆已經(jīng)是大頂堆,所以這個(gè)時(shí)候,我們只需要上面的三個(gè)元素就好了

算法導(dǎo)論例子

?

改成循環(huán)代碼

/*** 調(diào)整堆元素* @param A 數(shù)組存放堆* @param n 數(shù)組的數(shù)量 從 1 - n 開(kāi)始* @param i 需要調(diào)整的堆 元素 位置 */public void max_heapify1(int[] A ,int n,int i){int l = -1;int r = -1;int largest = -1;while(true){l = left(i);r = right(i);if(l<=n && A[l] > A[i])largest = l;else largest = i;if(r <=n && A[r] > A[largest])largest = r;if(largest!=i){swap(A,largest,i);//更新i 的值相當(dāng)?shù)倪f歸調(diào)用i = largest;// 相等 對(duì)左右子樹(shù)不影響}else{break;} }}

?

建堆

自底向上的方法,利用max-heapify 把一個(gè)大小為n 的數(shù)組A[1,...,n] 轉(zhuǎn)換成大頂堆。子數(shù)組A[[n/2] +1,...,n] 中的元素是樹(shù)的葉子結(jié)點(diǎn)。每個(gè)葉子結(jié)點(diǎn)可以看成一個(gè)大頂堆,所有在建堆的時(shí)候從 n/2 的元素開(kāi)始 一直到 第 1 的元素。

為什么這樣做?因?yàn)閷?duì)當(dāng)前結(jié)點(diǎn)進(jìn)行操作時(shí)能夠保證以當(dāng)前結(jié)點(diǎn)為根的樹(shù)的子樹(shù)都已經(jīng)是最大頂堆。這是從后像前的過(guò)程,先把底層的大頂堆構(gòu)建好,再逐步的構(gòu)建上層的大頂堆,在一定程度上減少了不比較的操作。如果是從1 到 n/2 的時(shí)候,對(duì)于新加入的元素,前面已經(jīng)構(gòu)建好的大頂堆可能都需要進(jìn)行更新。比如,我們已經(jīng)在第100層, 新插入的元素比之前堆內(nèi)的元素都大,如100000,前面已經(jīng)構(gòu)建好的99層都要進(jìn)行調(diào)整。

/*** 建立大頂堆* @param A* @param n*/public void build_max_heap(int[] A,int n){for(int i = n/2;i>=1;i--){max_heapify(A,n,i);}}

?

時(shí)間復(fù)雜度:O(nlog(n))

算法導(dǎo)論建堆例子

堆排序算法

初始時(shí)候,利用build_max_heap將輸入數(shù)組A[1,..,n] 建成大頂堆,這里A[1]一定是最大的元素,將A[1]與A[n]互換,再對(duì)A[1,...,n-1] 調(diào)整為大頂堆,然后A[1]與A[n-1]元素互換,再對(duì)A[1,...,n-2] 調(diào)整為大頂堆,如此循環(huán)下去

/*** 堆排序 升序* @param A* @param n */public void heap_sort(int[] A,int n){build_max_heap(A,n);for(int i = n;i>=2;i--){swap(A,i,1);max_heapify(A,i-1,1);}}

堆排序的時(shí)間復(fù)雜度:O(nlogn)

算法導(dǎo)論例子

?

所有程序

package heapSort;class heap{/*** 堆排序 升序* @param A* @param n */public void heap_sort(int[] A,int n){build_max_heap(A,n);for(int i = n;i>=2;i--){swap(A,i,1);max_heapify(A,i-1,1);}}/*** 建立大頂堆* @param A* @param n*/public void build_max_heap(int[] A,int n){for(int i = n/2;i>=1;i--){max_heapify(A,n,i);}}/*** 調(diào)整堆元素* @param A 數(shù)組存放堆* @param n 數(shù)組的數(shù)量 從 1 - n 開(kāi)始* @param i 需要調(diào)整的堆 元素 位置 */public void max_heapify1(int[] A ,int n,int i){int l = -1;int r = -1;int largest = -1;while(true){l = left(i);r = right(i);if(l<=n && A[l] > A[i])largest = l;else largest = i;if(r <=n && A[r] > A[largest])largest = r;if(largest!=i){swap(A,largest,i);//更新i 的值相當(dāng)?shù)倪f歸調(diào)用i = largest;// 相等 對(duì)左右子樹(shù)不影響}else{break;} }}/*** 調(diào)整堆元素* @param A* @param n* @param i*/public void max_heapify(int[] A ,int n,int i){// 左孩子結(jié)點(diǎn)int l = left(i);// 右孩子結(jié)點(diǎn)int r = right(i);// 最大結(jié)點(diǎn)下標(biāo)int largest = -1;// 與左孩子判斷if(l<= n && A[l] > A[i])largest = l;elselargest = i;// 與右孩子判斷if(r <=n && A[r] > A[largest])largest = r;// i 結(jié)點(diǎn)不是最大值maxId 和i 結(jié)點(diǎn)進(jìn)行交換if(largest != i ){swap(A,largest,i); max_heapify(A,n,largest);}}/*** 交換* @param A* @param l* @param r*/public void swap(int [] A,int l,int r){int tmp = A[l];A[l] = A[r];A[r] = tmp;}// 父結(jié)點(diǎn)public int parent( int i){return i/2;}// 左孩子public int left(int i){return 2*i;}// 右孩子public int right(int i){return 2*i+1;} } public class heapSort {public static void main(String[] args) {heap h = new heap();// 第一個(gè)元素不考慮int[] A = new int[]{-1,4,1,3,2,16,9,10,14,8,7};int n = A.length-1;//h.build_max_heap(A, n);//printA(A);//16 14 10 8 7 9 3 2 4 1 //16 14 10 8 7 9 3 2 4 1 h.heap_sort(A, n);System.out.println();printA(A);}public static void printA(int[] A){for(int i:A){System.out.print(i+" ");}}} View Code

?

總結(jié)

以上是生活随笔為你收集整理的算法导论:堆排序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。