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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

算法导论笔记:06堆排序

發(fā)布時間:2024/9/5 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法导论笔记:06堆排序 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? ? ?滿二叉樹:除最后一層無任何子節(jié)點外,每一層上的所有結(jié)點都有兩個子結(jié)點(也可以這樣理解,除葉子節(jié)點外的所有結(jié)點均有兩個子結(jié)點。節(jié)點數(shù)達(dá)到最大值。所有葉子結(jié)點必須在同一層上)

?

? ? ? ?1:堆排序的時間復(fù)雜度為O(nlgn)。具有空間原址性的特點,也就是任意時刻只需常數(shù)個額外元素空間存儲臨時數(shù)據(jù)。

?

? ? ? ?2:堆是一顆近似完全二叉樹:除了最底層外,該樹是完全充滿的,最底層是從左向右填充的。

?

? ? ? ?3:堆可以用數(shù)組存儲,對于元素下標(biāo)i,可以很快得出它的父節(jié)點,左孩子,右孩子的下標(biāo)(i從0開始):

PARENT(i) = (i-1)/2? ?

LEFT(i) = 2i + 1 ? ?

RIGHT(i) = 2i + 2 ? ?

?

?????? 一般而言,上述計算父母,左孩子,右孩子索引的函數(shù)都是通過宏或者內(nèi)聯(lián)函數(shù)實現(xiàn)

?

? ? ???4:堆有兩種:最大堆和最小堆。

?????? 最大堆是:除了根節(jié)點之外,所有節(jié)點i都要滿足:A[PARENT(i)]?>=?A[i]。即某個節(jié)點的值最多與父節(jié)點一樣大。因此,最大堆中的最大元素放在根節(jié)點中,任意一個子樹中所包含的所有節(jié)點的值都小于等于子樹根節(jié)點的值。如果是從小到大排序,一般用最大堆。

?????? 最小堆是:除了根節(jié)點之外,所有節(jié)點i都要滿足:A[PARENT(i)] <= A[i]。最小堆的最小值放在根節(jié)點中。如果是從大到小排序,用最小堆。

?

? ? ???5:一個包含n個元素的堆,高度為lgn 。堆結(jié)構(gòu)上的一些基本操作的運(yùn)行時間與堆高度成正比,所以時間復(fù)雜度為O(lg n)。

?

? ? ???6:當(dāng)用數(shù)組表示n個元素的堆時,葉節(jié)點的下標(biāo)分別是:((n-2)/2)+1, ((n-2)/2)+2,……,n。(默認(rèn)元素下標(biāo)從0開始,所以,最后一個結(jié)點的父節(jié)點一定是最后一個內(nèi)部結(jié)點。)

?

? ? ? ?7:最大堆上的操作有:

?????? MAX-HEAPIFY???? :維護(hù)最大堆的性質(zhì),時間復(fù)雜度為O(lg n)。

?????? BUILD-MAX-HEAP:從無序的數(shù)組構(gòu)造一個最大堆,時間復(fù)雜度為O(n)。

?????? HEAPSORT: 對數(shù)組進(jìn)行原址排序,時間復(fù)雜度為O(nlg n)

?????? MAX-HEAP-INSERT, HEAP-EXTRACT-MAX, ?HEAP-INCREASE-KEY, ?HEAP-MAXIMUM

??????

? ? ? ?8:MAX-HEAPIFY:維護(hù)最大堆性質(zhì),輸入為數(shù)組A和下標(biāo)i。調(diào)用MAX-HEAPIFY時,始終假定以LEFT(i)RIGHT(i)為根的左右子樹都已經(jīng)是最大堆了。MAX-HEAPIFY通過讓A[i]的值在最大堆中“逐級下降”,從而使得以A[i]為根節(jié)點的子樹成為最大堆。

?????? 該算法中,每一步都是從A[i],RIGHT[i],LEFT[i]這三者中選出最大值。如果A[i]是最大值,則算法結(jié)束,否則,將A[i]與最大值A(chǔ)[j](j= RIGHT[i] or LEFT[i])交換,從而使i及其孩子滿足最大堆的性質(zhì)。然后針對j再次調(diào)用MAX-HEAPIFY過程,直到堆的末尾。代碼如下:

//from up to down to keep the property of max ?heap (recursion)
void ?maxheapify(int ?*set, ?int ?index, ?int ?size)
{
? ? ???int ?left = LEFT(index);
? ? ???int ?right = RIGHT(index);


? ? ???int ?largest;
? ? ???if(left < size && set[index] < set[left])
? ? ???{
? ? ???? ? ???largest = left;
? ? ???}
? ? ???else
? ? ???{
? ? ???? ? ???largest = index;
? ? ???}

? ? ???if(right < size && set[largest] < set[right])
? ? ???{
? ? ???? ? ???largest = right;
? ? ???}



? ? ???if(largest != index)
? ? ???{
? ? ???? ? ???exchange(set+index, set+largest);
? ? ???? ? ???maxheapify(set, largest, size);
? ? ???}
}


//from up to down to keep the property of max ?heap (loop)
void maxheapify2(int *set, int index, int size)
{
? ? ???int left;
? ? ???int right;

? ? ???int largest;

? ? ???while(index < size)
? ? ???{
? ? ???? ? ???left = LEFT(index);
? ? ???? ? ???right = RIGHT(index);

? ? ???? ? ???if(left < size && set[index] < set[left])
? ? ???? ? ???{
? ? ???? ? ???? ? ???largest = left;
? ? ???? ? ???}
? ? ???? ? ???else
? ? ???? ? ???{
? ? ???? ? ???? ? ???largest = index;
? ? ???? ? ???}

? ? ???? ? ???if(right < size && set[largest] < set[right])
? ? ???? ? ???{
? ? ???? ? ???? ? ???largest = right;
? ? ???? ? ???}

? ? ???? ? ???if(largest != index)
? ? ???? ? ???{
? ? ???? ? ???? ? ???exchange(set + index, set + largest);
? ? ???? ? ???? ? ???index = largest;
? ? ???? ? ???}
? ? ???? ? ???else
? ? ???? ? ???{
? ? ???? ? ???? ? ???return;
? ? ???? ? ???}
? ? ???}
}

?

?????? 若以i為根節(jié)點的子樹元素個數(shù)為n,則其左孩子結(jié)點的個數(shù)最多為2/3 * n證明如下:假設(shè)左子樹節(jié)點數(shù)為x,右子樹節(jié)點數(shù)為y,所以n = x + y + 1。因堆是從左向右填充的,所以x >= y。如果要使x達(dá)到最大值,那么這種情況就是堆的最底層元素恰好半滿。

?????? 假設(shè)堆的高度為h,那么左子樹高度為h-1,右子樹高度為h-2。所以,n <= 2^(h+1) - 1,

x = 2^h - 1, y = 2^(h-1) - 1。所以 x/y ?≈ 2/1 ?。所以,x ≈ 2n/3

?????? 所以,遞歸的算法:T(n) = T(2n/3) + Θ(1)。從而T(n) = O(lg n)。

?

? ? ???9:因為MAX-HEAPIFY(A,i)包含一個假設(shè),就是i的左右子樹都已經(jīng)是最大堆了,所以一般情況下,都是自底向上的調(diào)用MAX-HEAPIFY比如建堆函數(shù)BUILD-MAX-HEAP,該算法把一個大小為n的數(shù)組轉(zhuǎn)換為最大堆。因為葉子節(jié)點可以認(rèn)為已經(jīng)是最大堆了,所以建堆的過程從最后一個內(nèi)部結(jié)點開始,也就是下標(biāo)為(size-2)/2的元素。從該節(jié)點開始,依次向前調(diào)用MAX-HEAPIFY,建立最大堆。

?????? 在BUILD-MAX-HEAP中,需要調(diào)用n次MAX-HEAPIFY過程,所以錯略計算該算法的時間復(fù)雜度為O(nlg n)。這不是一個緊缺的上界,因為MAX-HEAPIFY的時間跟高度h有關(guān),h的范圍是[0,lg n],而且高度為h的元素個數(shù)最多為n/2^(h+1) 。所以,實際上BUILD-MAX-HEAP的時間復(fù)雜度為O(n)。代碼如下:

?//build the max heap from set with call maxheapify
void buildmaxheap(int *set, int size)
{
? ? ???int index = size-1;
? ? ???int parent = PARENT(index);
? ? ???int i;

? ? ???for(i = parent; i >= 0; i--)
? ? ???{
? ? ???? ? ???maxheapify2(set, i, size);
? ? ???}
}


? ? ???10:利用最大堆進(jìn)行排序的算法HEAPSORT的基本思想是:

?????? 首相利用BUILD-MAX-HEAP算法將一個n元素數(shù)組轉(zhuǎn)換為最大堆,此時該數(shù)組的最大元素就是A[0],所以,交換A[0]A[n-1]

?????? 然后,將數(shù)組A[0…n-2]看成新的數(shù)組,該數(shù)組中,除了根節(jié)點之外,其他左右子樹依然滿足最大堆的性質(zhì),只是根節(jié)點因為發(fā)生了交換所以有可能不滿足最大堆性質(zhì),所以,對根節(jié)點調(diào)用MAX-HEAPIFY即可。

?????? 重復(fù)以上這個過程直到堆的大小變?yōu)?。

?????? 該算法的時間復(fù)雜度為O(n lg n)。代碼如下:

//sort use max heap
void maxheapsort(int *heap, int size)
{
? ? ???int heapsize = size;
? ? ???int i;
? ? ???buildmaxheap(heap, size);

? ? ???for(i = size - 1; i > 0; i--)
? ? ???{
? ? ???? ? ???exchange(heap, heap+i);
? ? ???? ? ???heapsize--;
? ? ???? ? ???maxheapify2(heap, 0, heapsize);
? ? ???}
}

?

11:優(yōu)先隊列

?????? 堆排序是一個優(yōu)秀的算法,但是在實際應(yīng)用中,快速排序一般會快于堆排序堆還可以作為優(yōu)先隊列的實現(xiàn)。最大堆和最小堆分別對應(yīng)于最大優(yōu)先隊列和最小優(yōu)先隊列。優(yōu)先隊列是一個集合,集合中的元素都有一個關(guān)鍵字(key),此關(guān)鍵字標(biāo)識該元素的優(yōu)先級。最大優(yōu)先隊列的例子是進(jìn)程調(diào)度,每次調(diào)度進(jìn)程時,都是從隊列中選擇優(yōu)先級最高的進(jìn)程進(jìn)行運(yùn)行。最小優(yōu)先隊列的例子是事件驅(qū)動的模擬器,每個事件以發(fā)生時間為關(guān)鍵字,每次選擇到時的事件進(jìn)行模擬。

?????? 優(yōu)先隊列支持的操作有(優(yōu)先隊列可用堆來實現(xiàn),下面的優(yōu)先隊列的操作實際上是針對最大堆的):

?????? INSERT:向優(yōu)先隊列中插入元素。

?????? MAXIMUM:返回優(yōu)先隊列中優(yōu)先級最大的元素。

?????? EXTRACT-MAX:返回優(yōu)先級最大的元素,并且將鈣元素刪除。

?????? INCREASE-KEY:將某個元素的關(guān)鍵字增加為k,重新構(gòu)造優(yōu)先隊列。

?????? DELETE:從優(yōu)先隊列中刪除元素。

?

12:EXTRACT-MAX:返回優(yōu)先級最大的元素,并且將該元素刪除。

???? 該算法將A[1]記錄,然后將最后的元素A[heapsize]存儲到A[1]中,然后減少heapsize,然后調(diào)用MAXHEAPIFY重新調(diào)整最大堆。最后返回記錄的A[1]的值。該算法的時間復(fù)雜度與MAXHEAPIFY相同,為O(lg n)。代碼如下:

//return the max elements and del it
int heap_extractmax(int *set, int size)
{
? ? ???if(size < 1)
? ? ???{
? ? ???? ? ???printf("heap size error\n");
? ? ???? ? ???return -1;
? ? ???}
? ? ???int max = set[0];
? ? ???int heapsize = size;

? ? ???set[0] = set[size-1];
? ? ???set[size-1] = NEINFINITE;
? ? ???heapsize = size - 1;
? ? ???maxheapify(set,0,heapsize);
? ? ???return max;
}

?

? ? ???14:INCREASE-KEY:將某個元素的關(guān)鍵字增加為key,重新構(gòu)造優(yōu)先隊列。

?? ? ???該算法將A[i]的關(guān)鍵字置為key,然后從索引i開始向上比較,如果A[i] > A[PARENT(i)],則交換A[i] 和 A[PARENT(i)],然后i= PARENT(i)。重復(fù)這個過程直到I = 1。

?????? 該算法與MAXHEAPIFY類似,只不過該算法是從下往上維護(hù)最大堆的性質(zhì)。該算法的時間復(fù)雜度為O(lg n)。代碼如下:

//from down to up to keep the property of max heap
void heap_increasekey(int *set, int index, int key, int size)
{
? ? ???int i, p;
? ? ???if(set[index] > key)
? ? ???{
? ? ???? ? ???printf("current is %d, key is %d, error\n", set[index], key);
? ? ???? ? ???return ;
? ? ???}
? ? ???set[index] = key;
? ? ???i = index;

? ? ???while(i > 0)
? ? ???{
? ? ???? ? ???p = PARENT(i);
? ? ???? ? ???if(key > set[p])
? ? ???? ? ???{
? ? ???? ? ???? ? ???set[i] = set[p];
? ? ???? ? ???? ? ???i = p;
? ? ???? ? ???}
? ? ???? ? ???else
? ? ???? ? ???{
? ? ???? ? ???? ? ???set[i] = key;
? ? ???? ? ???? ? ???break;
? ? ???? ? ???}
? ? ???}
}

?

? ? ???15:INSERT:向優(yōu)先隊列中插入元素。

?????? 該算法首先將heapsiize增加,然后置A[heapsize]為 。然后調(diào)用INCREASE-KEY(set, heapsize, key)即可,該算法的時間復(fù)雜度為O(lg n)。代碼如下:

//insert elements to max heap
void maxheapinsert(int *set, int key, int heapsize, int size)
{
? ? ???if(heapsize >= size)
? ? ???{
? ? ???? ? ???printf("heapsize larger than size, error\n");
? ? ???? ? ???return;
? ? ???}
? ? ???heapsize ++;
? ? ???set[heapsize - 1] = NEINFINITE;
? ? ???heap_increasekey(set, heapsize-1, key, heapsize);
}

?

? ? ???16:DELETE:從優(yōu)先隊列中刪除元素。

?????? 該算法將最后的元素A[heapsize]存儲到A[index]中,然后減少heapsize。然后比較當(dāng)前index元素的值與父母的值大小,如果A[index] < A[PARENT(index)],則從上往下維護(hù)堆的性質(zhì)(MAXHEAPIFY),否則,從下往上維護(hù)堆的性質(zhì)(INCREASE-KEY)。代碼如下:

//del elements from max heap,note: it should be up to down or down to up
void maxheapdel(int *set, int index, int size)
{
? ? ???int heapsize = size-1;
? ? ???int p = PARENT(index);
? ? ???int key = set[size-1];

? ? ???if(key < set[p])
? ? ???{//down
? ? ???? ? ???set[index] = set[size-1];
? ? ???? ? ???maxheapify(set, index, heapsize);
}
? ? ???else
? ? ???{//up
? ? ???? ? ???heap_increasekey(set,index,key,heapsize);
? ? ???}
}?


? ? ???17:設(shè)計一個復(fù)雜度為O(nlg k)的算法,將k個有序鏈表合并為一個有序鏈表,其中n為所有鏈表元素的總和。

?????? 首先將所有k個鏈表的第一個元素組成一個最小堆,然后EXTRACT-MIN得到綜合鏈表的第一個元素,然后將MIN所在鏈表的第二個元素INSERT到最小堆中,然后再次EXTRACT-MIN。如此重復(fù)下去,知道最小堆為空。該算法時間復(fù)雜度為O(nlg k)

?

18:一個m * n的YOUNG氏矩陣中,每一行的數(shù)據(jù)都是從左向右進(jìn)行排序的,每一列的元素都是從上到下排序的,如果矩陣中某個元素不存在,則記該元素為 比如包含元素{9,6,3,2,4,8,5,14,12}的4 x 4的Young氏矩陣如下:

2 3 4 5

6 8 9 12

14 ∞ ∞ ∞

∞ ∞ ∞ ∞

? ? ???a:給出一個O(m + n)的EXTRACT-MIN算法。

?????? 類似于堆的EXTRACT-MIN算法,首先將A[1][1]記錄下來以備返回,然后將矩陣的最后一個元素A[m][n]存儲到A[1][1]中,然后比較A[1][1]。A[1][2]和A[2][1]的值,將其中的最小值與A[1][1]進(jìn)行對換,然后再次調(diào)用該過程。每次調(diào)用都是比較A[i][j]、A[i][j+1]和A[i+1][j]的值,將最小值記錄到A[i][j]中,然后針對(I,j+1)或者(j+1, i)再次調(diào)用該過程(類似于MINHEAPIFY)。可見該過程的時間復(fù)雜度為O(m+n)。

?

? ? ???b:設(shè)計一個O(m + n)的算法,確定某個數(shù)是否在該矩陣中。

?????? 每次通過將X與矩陣中最右上角的元素進(jìn)行比較,如果X大,則說明X可能在剩下的(m-1) * n的矩陣中,如果X小,說明X有可能在剩下的m * (n-1)矩陣中。該算法的時間復(fù)雜度為O(m + n)。

?

轉(zhuǎn)載于:https://www.cnblogs.com/gqtcgq/p/7247241.html

總結(jié)

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

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