【筆記】堆排序
堆排序只需要記錄一個記錄大小的輔助空間,每個待排序的記錄僅佔有一個儲存空間。
**堆的定義:**n個元素的序列
或
(i = 1,2,3,…,
若將和此序列對應的一維陣列看成是一個完全二叉樹,則堆的含義表明,完全二叉樹中所有非終端節點的值均不大於其左、右孩子結點的值。由此,若序列
例如序列{96,83,27,38,11,09}和{12,36,24,85,47,30,53,91}對應的完全二叉樹為:
若在輸出堆頂的最小值之後,使得剩餘n-1個元素的序列重又建成一個堆,則得到n個元素中的次小值。如此反覆執行,便能得到一個有序序列,這個過程稱之為堆排序。
- 調整堆
如下圖所示,假設輸出堆頂元素之後,以堆中最後一個元素替代,此時根結點的左、右子樹均為堆,則僅需自上至下調整即可。首先以堆頂元素和其左、右子樹根結點的值進行比較,由於右子樹根結點的值相愛哦與左子樹結點的值,則將27和97交換,由於97的替代了27之後破壞了右子樹的堆,則需進行和上述相同的調整,直至葉子結點,此時堆頂為n-1個元素中的最小值。重複上述過程,將堆頂元素27和堆中最後一個元素97交換且調整,得到一個新的堆。我們稱這個自堆頂至葉子的調整過程為篩選。
- 建堆
從一個無序序列建堆的過程就是一個反覆篩選的過程。若將次序列看成是一個完全二叉樹,則最後一個非終端結點是第
例如下圖中的二叉樹表示一個有8個元素的無序序列{49,38,65,97,76,13,27,49},則篩選從第4個元素開始,由於97>49,則交換之。同理,在第3個元素65被篩選之後序列的狀態如圖所示。由於第2個元素38不大於其左、右子樹根的值,則篩選後的序列不變。
基本演算法思想:使記錄序列按關鍵字非遞減有序排列,則在堆排序的演算法中先建立一個最大堆,即先選得一個關鍵字為最大的記錄並與序列中最後一個記錄交換,然後對序列中前n-1記錄進行篩選,重新將它調整為一個最大堆,如此分那副直至排序結束。
- 型別定義
#include<stdio.h>
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
#define N 8
#define MAXSIZE 20 /* 一個用作示例的小順序表的最大長度 */
typedef int InfoType; /* 定義其它資料項的型別 */
typedef int KeyType; /* 定義關鍵字型別為整型 */
typedef struct
{
KeyType key; /* 關鍵字項 */
InfoType otherinfo; /* 其它資料項,具體型別在主程中定義 */
}RedType; /* 記錄型別 */
typedef struct
{
RedType r[MAXSIZE+1]; /* r[0]閒置或用作哨兵單元 */
int length; /* 順序表長度 */
}SqList; /* 順序表型別 */
typedef SqList HeapType; /* 堆採用順序表儲存表示 */
- 堆排序函式
void HeapAdjust(HeapType *H,int s,int m) /* 演算法10.10 */
{ /* 已知H.r[s..m]中記錄的關鍵字除H.r[s].key之外均滿足堆的定義,本函式 */
/* 調整H.r[s]的關鍵字,使H.r[s..m]成為一個大頂堆(對其中記錄的關鍵字而言) */
RedType rc;
int j;
rc=(*H).r[s];
for(j=2*s;j<=m;j*=2)
{ /* 沿key較大的孩子結點向下篩選 */
if(j<m&<((*H).r[j].key,(*H).r[j+1].key))
++j; /* j為key較大的記錄的下標 */
if(!LT(rc.key,(*H).r[j].key))
break; /* rc應插入在位置s上 */
(*H).r[s]=(*H).r[j];
s=j;
}
(*H).r[s]=rc; /* 插入 */
}
void HeapSort(HeapType *H)
{ /* 對順序表H進行堆排序。演算法10.11 */
RedType t;
int i;
for(i=(*H).length/2;i>0;--i) /* 把H.r[1..H.length]建成大頂堆 */
HeapAdjust(H,i,(*H).length);
for(i=(*H).length;i>1;--i)
{ /* 將堆頂記錄和當前未經排序子序列H.r[1..i]中最後一個記錄相互交換 */
t=(*H).r[1];
(*H).r[1]=(*H).r[i];
(*H).r[i]=t;
HeapAdjust(H,1,i-1); /* 將H.r[1..i-1]重新調整為大頂堆 */
}
}
- 主程式
void print(HeapType H)
{
int i;
for(i=1;i<=H.length;i++)
printf("(%d,%d)",H.r[i].key,H.r[i].otherinfo);
printf("\n");
}
void main()
{
RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
HeapType h;
int i;
for(i=0;i<N;i++)
h.r[i+1]=d[i];
h.length=N;
printf("排序前:\n");
print(h);
HeapSort(&h);
printf("排序後:\n");
print(h);
}
- 測試結果
相關文章
- 學習筆記--- 比較排序之堆排序筆記排序
- 《演算法筆記》4. 堆與堆排序、比較器詳解演算法筆記排序
- 看懂堆排序——堆與堆排序(三)排序
- 堆排序排序
- js堆排序JS排序
- [JAVA]堆排序Java排序
- 堆排序詳解排序
- python 堆排序Python排序
- 堆排序 Heap Sort排序
- 堆排序(C++)排序C++
- HeapSort 堆排序排序
- 實現堆排序排序
- 簡單堆排序排序
- js 實現堆排序JS排序
- 堆與堆排序(一)排序
- 堆排序(php實現)排序PHP
- 堆排序演算法排序演算法
- 堆操作與堆排序排序
- 印象筆記 --- 方法分享筆記筆記
- 堆排序(實現c++)排序C++
- 排序演算法__堆排序排序演算法
- 使用 Swift 實現堆排序Swift排序
- 順序表的堆排序排序
- 排序演算法-堆排序排序演算法
- 堆排序c++實現排序C++
- 排序演算法 - 堆排序排序演算法
- 每日一題(94) - 堆排序每日一題排序
- 【資料結構】堆排序資料結構排序
- 筆記筆記
- CUUG筆記 ORACLE索引學習筆記筆記Oracle索引
- 主動筆記與被動筆記筆記
- 優先佇列和堆排序佇列排序
- 堆排序就這麼簡單排序
- 堆的基本操作及堆排序排序
- 圖解堆排序演算法圖解排序演算法
- 二叉堆及堆排序排序
- rust-algorithms:8-堆排序RustGo排序
- C#堆排序演算法C#排序演算法