堆排序
百度百科介紹:
堆排序(英語:Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。
堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱爲大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱爲小頂堆。如下圖
堆排序基本思想
將一個待排序序列構建成一個大頂堆,大頂堆的根節點就是此序列的最大值,然後將根節點最大值與末尾元素進行交換,此時末尾元素就是最大值;再然後將序列剩餘的n-1個序列重新構建成一個大頂堆,再把根節點值與n-1個序列末尾元素進行交換,此時就得到了n序列的第二大的值,依次反覆執行,就得到有序序列了。
基本步驟
1.將無序序列構建成一個堆,根據升序選擇大頂堆,降序選擇小頂堆
2.將堆頂元素與末尾元素進行交換 ,把最大值(最小值1)放在數組末尾
3.把剩餘的序列元素重新創建成堆結構,然後繼續交換堆頂與末尾元素,反覆執行建堆和交換,直到排序完畢
大頂堆法
#include <stdio.h>
#include <stdlib.h>
//數值交換函數
void swap(int *a,int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
//調整大頂堆
void adjustHeap1(int a[],int i,int length)
{
int temp = a[i]; //先取出當前元素i
for (int k = i*2+1 ; k < length ; k=k*2+1) //從i節點的左子節點開始,也就是2i+1處開始
{
if (k+1 < length && a[k] < a[k+1]) //如果左子節點小於右子節點,k指向右子節點
{
k++;
}
if (a[k] > temp) //如果子節點大於父節點,將子節點值賦給父節點(不用進行交換)
{
a[i] = a[k];
i = k;
}
else
{
break;
}
}
a[i]=temp; //將temp值放在最終的位置
}
//堆排序法【大頂堆法(有小到大排序)】
void Heap_Sort1(int a[],int n)
{
//構建大頂堆
for (int i = n/2-1 ; i >= 0 ; i--)
{ //從最後一個非葉子節點從左至右,從下到上調整結構
adjustHeap1(a,i,n);
}
//調整堆結構和交換堆頂元素與末尾元素
for (int j = n-1 ; j > 0 ; j--)
{
swap(&a[0],&a[j]);
adjustHeap1(a,0,j); //再次構建大頂堆
}
}
void main()
{
int a[]={12,13,46,56,16,49,79,45,15,59};
int n=sizeof(a)/sizeof(int); //計算數組元素
int i;
Heap_Sort1(a,n); //大頂堆法,由小到大
for ( i = 0; i < n; i++)
{
printf("%d ",a[i]);
}
system("pause"); //防止控制檯閃退
}
小頂堆法
//數值交換函數
void swap(int *a,int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
//調整小頂堆
void adjustHeap2(int a[],int i,int length)
{
int temp =a[i]; //先取出當前元素i
for (int k = 2*i+1 ; k < length; k=k*2+1)
{
if (k+1 < length && a[k] > a[k+1]) //如果左子節點大於右子節點,k指向右子節點
{
k++; //k爲關鍵字中較小的記錄的下標
}
if (a[k] < temp ) //如果子節點小於父節點,將子節點值賦給父節點(不用進行交換)
{
a[i] = a[k];
i = k;
}
else
{
break; //滿足小頂堆條件,直接跳出
}
}
a[i] = temp;
}
//堆排序法【小頂堆法(有大到小排序)】
void Heap_Sort2(int a[],int n)
{
//構建小頂堆
for (int i = n/2-1; i >= 0; i--)
{
//從最後一個非葉子節點從左至右,從下到上調整結構
adjustHeap2(a,i,n);
}
//將整個根節點節點最後一個子節點進行交換
for (int j = n-1; j > 0; j--)
{
swap(&a[0],&a[j]);
adjustHeap2(a,0,j);
}
}
void main()
{
int a[]={12,13,46,56,16,49,79,45,15,59};
int n=sizeof(a)/sizeof(int); //計算數組元素
int i;
Heap_Sort2(a,n); //小頂堆法,由大到小
for ( i = 0; i < n; i++)
{
printf("%d ",a[i]);
}
system("pause"); //防止控制檯閃退
}
參考文獻:
圖解排序算法(三)之堆排序
堆排序(最後一個非葉子節點的序號是n/2-1的推理)
有不對的地方請大家指教,在學習中。