內(nèi)部排序之堆排序的實現(xiàn)詳解
堆排序(Heap Sort)只需要一個記錄大小的輔助空間,每個待排序的記錄僅占有一個存儲空間。
(1)基本概念
a)堆:設有n個元素的序列:
{k1, k2, ..., kn}
對所有的i=1,2,...,(int)(n/2),當滿足下面關(guān)系:
ki≤k2i,ki≤k2i+1
或 ki≥k2i,ki≥k2i+1
這樣的序列稱為堆。
堆的兩種類型:
根結(jié)點最小的堆----小根堆。
根結(jié)點最大的堆----大根堆。
根結(jié)點稱為堆頂,即:在一棵完全二叉樹中,所有非葉結(jié)點的值均小于(或均大于)左、右孩子的值。
b)堆排序:是一種樹型選擇排序,特點是,在排序過程中,把R[1..n]看成是一個完全二叉樹的存儲結(jié)構(gòu),利用完全二叉樹雙親結(jié)點和孩子結(jié)點的內(nèi)在關(guān)系,在當前無序區(qū)中選擇關(guān)鍵字最大(最小)的記錄。
2)堆排序步驟:
1、從k-1層的最右非葉結(jié)點開始,使關(guān)鍵字值大(或小)的記錄逐步向二叉樹的上層移動,最大(或?。╆P(guān)鍵字記錄成為樹的根結(jié)點,使其成為堆。
2、逐步輸出根結(jié)點,令r[1]=r[i](i=n,,n-1,...,2),在將剩余結(jié)點調(diào)整成堆。直到輸出所有結(jié)點。我們稱這個自堆頂?shù)饺~子的調(diào)整過程為“篩選”。
(3)要解決的兩個問題:
1、如何由一個無序序列建成一個堆;
2、輸出一個根結(jié)點后,如何將剩余元素調(diào)整成一個堆。
將一個無序序列建成一個堆是一個反復“篩選”的過程。若將此序列看成是一個完全二叉樹,則最后一個非終端結(jié)點是第floor(n/2)個元素,由此“篩選”只需從第floor(n/2)個元素開始。
堆排序中需一個記錄大小的輔助空間,每個待排的記錄僅占有一個存儲空間。堆排序方法當記錄較少時,不值得提倡。當n很大時,效率很高。堆排序是不穩(wěn)定的。
堆排序的算法和篩選的算法如第二節(jié)所示。為使排序結(jié)果是非遞減有序排列,我們在排序算法中先建一個“大頂堆”,即先選得一個關(guān)鍵字為最大的記錄并與序列中最后一個記錄交換,然后對序列中前n-1個記錄進行篩選,重新將它調(diào)整為一個“大頂堆”,然后將選得的一個關(guān)鍵字為最大的記錄(也就是第一個元素)與當前最后一個記錄交換(全局看是第n-1個),如此往復,直到排序結(jié)束。由到,篩選應按關(guān)鍵字較大的孩子結(jié)點向下進行。
堆排序的算法描述如下:
用C語言代碼實現(xiàn)如下:
#include "iostream"
using namespace std;
#define MAXSIZE 20
typedef struct
{
int key;
//其他數(shù)據(jù)信息
}RedType;
typedef struct
{
RedType r[MAXSIZE+1];
int length;
}Sqlist;
typedef Sqlist HeapType; //堆采用順序表存儲表示
void HeapAdjust(HeapType &H,int s,int m) //已知H.r[s...m]中記錄的關(guān)鍵字出H.r[s].key之外均滿足堆的定義,本函數(shù)調(diào)整H.r[s]的關(guān)鍵字,使H.r[s...m]成為一個大頂堆(對其中記錄的關(guān)鍵字而言)
{
int j;
RedType rc;
rc=H.r[s];
for(j=2*s;j<=m;j*=2) //沿key較大的孩子結(jié)點向下篩選
{
if(j<m && (H.r[j].key<H.r[j+1].key)) //j為key較大的記錄的下標
++j;
if(rc.key>=H.r[j].key) //rc應插入在位置s上
break;
H.r[s]=H.r[j]; //將左、右孩子較大的結(jié)點與父節(jié)點進行交換,建成大頂堆
s=j;
}
H.r[s]=rc; //插入
}
void HeapSort(HeapType &H) //對順序表H進行堆排序
{
int i;
for(i=H.length/2;i>0;--i) //由一個無序序列建成一個大頂堆,將序列看成是一個完全二叉樹,則最后一個非終端節(jié)點是第n/2個元素
HeapAdjust(H,i,H.length);
for(i=H.length;i>1;--i)
{
H.r[0]=H.r[1]; //將堆頂記錄和當前未經(jīng)排序的子序列H.r[1...i]中最后一個記錄相互交換
H.r[1]=H.r[i];
H.r[i]=H.r[0];
HeapAdjust(H,1,i-1); //將H.r[1...i-1]重新調(diào)整為大頂堆
}
}//HeapSort
void InputL(Sqlist &L)
{
int i;
printf("Please input the length:");
scanf("%d",&L.length);
printf("Please input the data needed to sort:\n");
for(i=1;i<=L.length;i++) //從數(shù)組的第1個下標開始存儲,第0個下標作為一個用于交換的臨時變量
scanf("%d",&L.r[i].key);
}
void OutputL(Sqlist &L)
{
int i;
printf("The data after sorting is:\n");
for(i=1;i<=L.length;i++)
printf("%d ",L.r[i].key);
printf("\n");
}
int main(void)
{
Sqlist H;
InputL(H);
HeapSort(H);
OutputL(H);
system("pause");
return 0;
}
不使用上面的結(jié)構(gòu)體的另外一種方法如下:
/*
*堆排序
*/
#include "iostream"
using namespace std;
#define N 10
int array[N];
void man_input(int *array)
{
int i;
for(i=1;i<=N;i++)
{
printf("array[%d]=",i);
scanf("%d",&array[i]);
}
}
void mySwap(int *a,int *b)//交換
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
void heap_adjust(int *heap,int root,int len) //對堆進行調(diào)整,使下標從root到len的無序序列成為一個大頂堆
{
int i=2*root;
int t=heap[root];
while(i<=len)
{
if(i<len)
{
if(heap[i]<heap[i+1])
i++;
}
if(t>=heap[i])
break;
heap[i/2]=heap[i];
i=2*i;
}
heap[i/2]=t;
}
void heapSort(int *heap,int len) //堆排序
{
int i;
for(i=len/2;i>0;i--) //由一個無序序列建成一個大頂堆,將序列看成是一個完全二叉樹,則最后一個非終端節(jié)點是第len/2個元素
{
heap_adjust(heap,i,len);
}
for(i=len;i>=1;i--)
{
mySwap(heap+i,heap+1); //將堆頂記錄與最后一個記錄相互交換
heap_adjust(heap,1,i-1); //將下標為1~i-1的記錄重新調(diào)整為大頂堆
}
}
void print_array(int *array,int n)
{
int k;
for(k=1;k<n+1;k++)
{
printf("%d\t",array[k]);
}
}
int main(void)
{
man_input(array);
heapSort(array,N);
printf("\nAfter sorted by the heap_sort algorithm:\n");
print_array(array,N); //打印堆排序結(jié)果
system("pause");
return 0;
}
欄 目:C語言
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/4504.html
您可能感興趣的文章
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 01-10深入理解堆排序及其分析
- 01-10基于atoi()與itoa()函數(shù)的內(nèi)部實現(xiàn)方法詳解
- 01-10深入單鏈表的快速排序詳解
- 01-10用c語言實現(xiàn)冒泡排序,選擇排序,快速排序
- 01-10C++實現(xiàn)基數(shù)排序的方法詳解
- 01-10歸并排序的遞歸實現(xiàn)與非遞歸實現(xiàn)代碼
- 01-10如何使用VC庫函數(shù)中的快速排序函數(shù)
- 01-10STl中的排序算法詳細解析
- 01-10淺析stl序列容器(map和set)的仿函數(shù)排序


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