1. 程式人生 > >排序系列演算法——堆排序

排序系列演算法——堆排序

堆:大根堆與小根堆

      堆排序是建立在堆基礎上的排序方法,首先了解一下什麼是堆。

      常用的堆一般有兩種,大根堆和小根堆。堆可以看做是一棵二叉樹,其父節點的值總是大於(大根堆)或者小於(小根堆)子節點的值。舉一個例子:

 

                         圖1 不滿足堆的條件                 圖2大根堆                             圖3 小根堆

      圖1不是堆,因為不滿足父節點的值大於或者小於子節點的值;

      圖2是大根堆,根節點是最大值,父節點都大於或等於子節點的值;

      圖3是小根堆,根節點是最小值,父節點都小於或等於子節點的值。

堆排序

      下面以大根堆為例講解堆排序:

      大根堆有一個很好的性質,根節點的數值總是大於其他所有節點的數值,利用這個性質,可以實現排序的工作。堆排序的步驟可以描述如下:

      1.構建大根堆。首先我們的原始陣列一般情況下是不滿足堆的條件,既然我們要可用大根段的性質進行排序,第一步當然是對原始陣列進行處理,構建大根堆。

      2.根節點資料處理以及大根堆重構。構建了大根堆之後,根節點的資料是最大值,將該數值取出,對剩下的元素重構大根堆,這時根節點是剩下元素的最大值,取出。只要不斷重複上述的操作,不斷取出未排序元素的最大值,直到未排序的元素只剩一個,就完成了排序工作。

      說得有點抽象,直接用一個實際的例子說明堆排序的工作步驟:

      對一個無序的序列A={5,4,17,13,15,12,10 }按從小到大進行排序,序列的下標分別為{1,2,3,4,5,6,7},A[i]表示下標為i的元素。

      第一步:對無序的陣列構造大根堆

 

大根堆的根節點是整個序列的最大值。

       第二步

       將A[1]與A[7]互換,此時A[7]為序列的最大值,A[7]已經排序完畢,剩餘的元素A[1]~A[6]形成新的未排序序列,由於此時序列不是大根堆,需要重構大根堆。


       第三步

       將A[1]與A[6]互換,此時A[6]為序列的最大值,A[6]已經排序完畢,剩餘的元素A[1]~A[5]形成新的未排序序列,由於此時序列不是大根堆,需要重構大根堆。

      第四步

      將A[1]與A[5]互換,此時A[5]為序列的最大值,A[5]已經排序完畢,剩餘的元素A[1]~A[4]形成新的未排序序列,由於此時序列不是大根堆,需要重構大根堆。

      第五步

      將A[1]與A[4]互換,此時A[4]為序列的最大值,A[4]已經排序完畢,剩餘的元素A[1]~A[3]形成新的未排序序列,由於此時序列不是大根堆,需要重構大根堆。

      第六步

      將A[1]與A[3]互換,此時A[3]為序列的最大值,A[3]已經排序完畢,由於此時未排序的序列只剩下兩個元素,而且A[0]>A[1],將A[0]與A[1]互換即可得到最終的已排序序列。

 

C++程式實現

從上述的排序過程可知,堆排序主要有兩個過程,大根堆的構建與重構:

1、大根堆的重構

  如何實現大根堆的重構?如果一個原有的陣列滿足大根堆的性質,而只有其中一個元素改變從而破壞了大根堆的性質,那麼可以從該元素出發,不斷”逐級下降“,讓子節點小於等於父子節點,滿足大根堆的性質。以一個例項說明重構的過程:

  堆排序的過程中,每一次改變的只有根節點的元素,因此只需要從根節點出發,進行如上圖的操作即可實現大根堆的重構。C++程式碼如下:

 1 void ReBuildMaxHeap(int *array,int arraylength,int startIndex){
 2     int index=0;
 3     //int j=0;
 4     int max=0;
 5     while((2*startIndex+1)<arraylength){
 6         index = startIndex;
 7         max = array[index];
 8         if(max<(array[2*startIndex+1])){
 9             max=array[2*startIndex+1];
10             index=2*startIndex+1;
11         }
12         if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){
13             max=array[2*startIndex+2];
14             index=2*startIndex+2;
15         }
16         if(index==startIndex){
17             break;
18         }
19         swap(array,index,startIndex);
20         startIndex = index;
21     }
22 }

1、  構建大根堆。

  要構建大根堆,只需要遍歷所有非葉子節點元素,使其所有的葉子節點均不大於足該節點元素即可。構建大根堆自低向上對陣列進行遍歷,如果發現父節點的值小於子節點的值,則將父節點的值與子節點的最大值進行交換,保證父節點的資料總是大於子節點的資料。如果發生了資料的交換,有可能令子節點不滿足大根堆條件,需要進行會輸重構大根堆。以一個實際的例子說明構建大根堆的過程:

C++程式碼如下:

 1 void createHeap(int *array,int length){
 2     int max=0;
 3     int index=0;
 4     for(int i=floor(length/2)-1;i>=0;i--){
 5         index = i;
 6         max = array[i];
 7         if(max<array[2*i+1]){
 8             index=2*i+1;
 9             max = array[2*i+1];
10         }
11         if(2*i+2<length&&max<array[2*i+2]){
12             index = 2*i+2;
13             max = array[2*i+2];
14         }
15         if(index!=i){
16             swap(array,index,i);
17             ReBuildMaxValue(array,length,index);
18         }
19     }
20 }

全部原始碼:

 1 #include "stdafx.h"
 2 #include <iostream>
 3 using namespace std;
 4 
 5 //兩個文位置的資料交換
 6 void swap(int *array,int num1,int num2){
 7     int temp = *(array+num1);
 8     *(array+num1) = *(array+num2);
 9     *(array+num2) = temp;
10 }
11 
12 //重構大根堆
13 void ReBuildMaxValue(int *array,int arraylength,int startIndex){
14     int index=0;
15     //int j=0;
16     int max=0;
17     while((2*startIndex+1)<arraylength){
18         index = startIndex;
19         max = array[index];
20         if(max<(array[2*startIndex+1])){
21             max=array[2*startIndex+1];
22             index=2*startIndex+1;
23         }
24         if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){
25             max=array[2*startIndex+2];
26             index=2*startIndex+2;
27         }
28         if(index==startIndex){
29             break;
30         }
31         swap(array,index,startIndex);
32         startIndex = index;
33     }
34 }
35 
36 //構建大根堆
37 void createHeap(int *array,int length){
38     int max=0;
39     int index=0;
40     for(int i=floor(length/2)-1;i>=0;i--){
41         index = i;
42         max = array[i];
43         if(max<array[2*i+1]){
44             index=2*i+1;
45             max = array[2*i+1];
46         }
47         if(2*i+2<length&&max<array[2*i+2]){
48             index = 2*i+2;
49             max = array[2*i+2];
50         }
51         if(index!=i){
52             swap(array,index,i);
53             ReBuildMaxValue(array,length,index);
54         }
55     }
56 }
57 
58 //堆排序
59 void heapSort(int *array,int arraylength){
60     createHeap(array,10);
61     for(int i=arraylength-1;i>0;i--){
62         swap(array,i,0);
63         ReBuildMaxValue(array,i,0);
64     }
65 }
66 
67 int main(int argc, _TCHAR* argv[])
68 {
69     int values[10]={5,4,17,13,15,12,10,7,11,9};
70     heapSort(values,10);
71     for(int i=0;i<10;i++){
72         cout<<*(values+i)<<endl;
73     }
74     return 0;
75 }

相關推薦

排序系列演算法——排序

堆:大根堆與小根堆       堆排序是建立在堆基礎上的排序方法,首先了解一下什麼是堆。       常用的堆一般有兩種,大根堆和小根堆。堆可以看做是一棵二叉樹,其父節點的值總是大於(大根堆)或者小於(小根堆)子節點的值。舉一個例子:                            圖1 不滿足

排序系列演算法——歸併排序

      歸併排序是採用分治策略進行排序的一種演算法,其基本原理是將未排序的陣列劃分為兩個子陣列,分別對兩個子陣列盡心排序,然後將有序的子數組合並。歸併排序分為兩個過程:一是陣列劃分為兩個子陣列並分別進行排序,二是將兩個已排序的子陣列進行合併。 將陣列劃分為兩個子陣列並進行排序       將陣列一

經典排序演算法 - 排序Heap sort

經典排序演算法 - 堆排序Heap sort 堆排序有點小複雜,分成三塊 第一塊,什麼是堆,什麼是最大堆 第二塊,怎麼將堆調整為最大堆,這部分是重點 第三塊,堆排序介紹 第一塊,什麼是堆,什麼是最大堆 什麼是堆 這裡的堆(二叉堆),指得不是堆疊的那

排序演算法排序(關鍵詞:資料結構/演算法/排序演算法/排序

假定:有 1 個亂序的數列 nums ,其中有 n 個數。 要求:排好序之後是 從小到大 的順序。 堆排序演算法 原理 先將原始的堆,調整為最大堆: 從倒數第 1 個有子結點的結點(下標為 index = n//2 - 1)開始,將以結點 index 為根結點的子堆

排序演算法-排序

#include<iostream> using namespace std; void swap(int a[],int i,int j) { int temp = a[i]; a[

圖解排序演算法---排序

預備知識 堆排序   堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序,它的最壞,最好,平均時間複雜度均為O(nlogn),它也是不穩定排序。首先簡單瞭解下堆結構。 堆   堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值

程式設計師必須掌握的十種演算法---排序演算法

堆排序,就是利用完全二叉樹的某些特性對陣列進行排序。 #include<stdio.h> int h[101];//用來存放堆的陣列 int n;//用來儲存堆中元素的個數,也就是堆的

排序系列演算法——希爾排序

希爾排序可以說是插入排序的加強版,通過對原始資料進行分組再排序,更高效地完成對資料的排序工作。 1.從插入排序到希爾排序 回顧插入排序的基本知識,插入排序通過不斷將無序的元素插入到已排序的序列中,直到所有的元素都已經插入位置。 插入排序一個很明顯的缺點是插入元素時需要與已經排序的元素進行對比,對比的

排序演算法——排序(大頂、小頂

堆排序的思想這裡就先不講了,以後有時間再補上,下面是分別採用大頂堆和小頂堆實現的堆排序。 注意:下面例子中排序的數字是{1,2,5,3,6,4,9,7,8}。 大頂堆方式 #include &

【圖解演算法排序演算法——排序

簡介 關於堆排序(HeapSort),堆這種資料結構比這種排序演算法更為有價值。 堆排序(Heapsort)是指利用堆積樹(堆)這種資料結構所設計的一種排序演算法,它是選擇排序的一種。可以利用陣列的特點快速定位指定索引的元素。堆分為大根堆和小根堆,是完

排序演算法-排序

堆排序,顧名思義,就是把待排序的資料按照一定的規則放到一個堆裡面去。不過,這裡這個堆不同於其他堆,這裡的堆是一顆完全二叉樹。那什麼是完全二叉樹呢,就是葉節點只能在最後一層或者倒數第二層,並且最後一層的結點都集中在該層最左邊的若干位置的二叉樹。 堆排序的基本思想

java排序演算法 排序

利用二叉堆排序其實就是迴圈移除頂部元素到陣列末尾,然後利用Sink重建堆的操作。 實現程式碼如下: public static void headSort(int[] data) { int n = data.length; for(int i = 0; i &

Java排序演算法 [排序]

package cn.com.dom4j.sort; import java.util.Arrays; public class Test2 { /** * 堆排序 */ public static <AnyType exten

java排序演算法 排序

堆排序就是利用堆(假設利用大頂堆)進行排序的方法。它的基本思想是,將待排序的序列構造成一個大頂堆。此時,整個序列的最大值就是堆頂的根節點。將它移走(其實就是將其與堆陣列的末尾元素交換,此時末尾元素就是最大值),然後將剩餘的n-1 個序列重新構造成一個堆,這樣就會得到 n

實驗六:排序演算法應用 1.錄入學生基本資訊 2、直接插入排序 3、氣泡排序 4、快速排序 5、簡單選擇排序 6、排序

/*實驗六:排序演算法應用 內容: 給出n個學生的考試成績表,每條記錄由學號、姓名和分數和名次組成,設計演算法完成下列操作: (1)設計一個顯示對學生資訊操作的選單函式如下所示: *************************1、錄入學生基本資訊2、直接插入排序3、氣泡

資料結構與演算法---排序(Heap sort)

堆排序基本介紹 1、堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序,它的最壞,最好,平均時間複雜度均為O(nlogn),它也是不穩定排序。 2、堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆, 注意 : 沒有要求結點的左孩子的值和右孩子的值的大

排序演算法——排序

1、堆排序思想     1. 建立二叉樹模型,依據陣列下標獲取節點關係:對於一個數組,我們可以將其看做是一

經典排序算法——排序

microsoft gin wap amp 又一 根節點 sort img tracking 對於一個int數組。請編寫一個堆排序算法。對數組元素排序。 給定一個int數組A及數組的大小n,請返回排序後的數組。 測試例子: [1,2,3,5,2,3],6 [1,

排序算法——排序

調整 wap nbsp 開始 eap code 代碼實現 模擬 while 堆排序   ①了解二叉堆的定義   ②一般用數組表示堆 註意邏輯存儲結構和實際存儲結構   ③i節點的     父節點(i-1)/2 子節點 左2*i+1 右2*i+2   ④註意每種操作的思想  

排序算法-排序

threading true task main 整體 頁面 read 時間 pos 部分內容轉自: 作者: dreamcatcher-cx 出處: <http://www.cnblogs.com/chengxiao/> 本文版權歸作者和博客園共有,歡迎轉載,但