十大排序算法——堆排序(C語言)

堆排序

百度百科介紹:
堆排序(英語: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的推理)

有不對的地方請大家指教,在學習中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章