堆排序詳解

本文是轉載文章,文章的來源:csdn博客
博主:帶魚兄
文章:堆排序詳解
博文地址:https://blog.csdn.net/daiyudong2020/article/details/52529791

基本概念:

要了解堆排序,首先要了解什麼是

要了解堆,還要先了解什麼是完全二叉樹


一、什麼是完全二叉樹?

完全二叉樹(complete binary tree)有嚴格的形狀要求:從根節點起每一層從左到右填充。一棵高度爲d的完全二叉樹除了d-1層以外,每一層都是滿的。底層葉節點集中在左邊的若干位置上。完全二叉樹如下圖:



二、什麼是堆?

堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質:
a)任何一非葉節點的關鍵字不大於其左右孩子節點的關鍵字,稱之爲最小堆。
b)任何一非葉節點的關鍵字不小於其左右孩子節點的關鍵字,稱之爲最大堆。
由上述性質可知:
a)最大堆的堆頂的關鍵字是所有關鍵字中最大的。
b)最小堆的堆頂的關鍵字是所有關鍵字中最小的。

通常堆是通過一維數組來實現的,在起始位置爲0的情形中:
父節點i的左子節點在位置(2*i+1);
父節點i的右子節點在位置(2*i+2);
子節點i的父節點在位置floor((i-1)/2);

一個最大堆如圖:


三、完全二叉樹怎麼演變成一個堆?

給定一個整形數組a[]={7,4,2,9,8,5},首先將數組視爲一個完全二叉樹,對其進行轉換成一個堆,構造初始堆是對所有的非葉節點都進行調整,從最後一個非葉節點開始調整,使其滿足堆的特性。

第一步,將數組視爲一個完全二叉樹:


第二步,將完全二叉樹轉換成一個堆:



最後得到一個最大堆:



四、如何使用堆進行排序?

基於以上堆相關的操作,我們可以很容易的定義堆排序。例如,假設我們已經讀入一系列數據並創建了一個堆,一個最直觀的算法就是反覆的調用del_max()函數,因爲該函數總是能夠返回堆中最大的值,然後把它從堆中刪除,從而對這一系列返回值的輸出就得到了該序列的降序排列。所以,堆排序,最重要的兩個操作就是構造初始堆和調整堆

堆排序的過程是:
(1)建立一個堆H[0..n-1]。
(2)把堆首(最大值)和堆尾互換。
(3)把堆的尺寸縮小1,然後調整堆,目的構成新的堆。
(4)重複步驟2,直到堆的尺寸爲1。


平均時間複雜度O(nlogn)


動態圖:



下面展示如何將一個數組a[]={7,4,2,9,8,5}構建成堆進行排序:

第一步:構建初始堆:


第二步,開始排序,灰色表示被移除的堆尾(已排好序):



五、簡單例子

源碼:

#include <stdio.h>

/* 交換元素 */
void swap(int* a, int* b) {
    int temp = *b;
    *b = *a;
    *a = temp;
}

/* 調整堆 */
void max_heapify(int arr[], int start, int end) {
    //建立父節點下標和子節點下標
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子節點下標在範圍內才做比較
        if (son + 1 <= end && arr[son] < arr[son + 1]) //先比較兩個子節點大小,選擇最大的
            son++;
        if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數
            return;
        else { //否則交換父子內容再繼續子節點和孫節點比較
            swap(&arr[dad], &arr[son]);
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

/* 堆排序 */
void heap_sort(int arr[], int len) {
    int i;
    //初始化堆,i從最後一個父節點開始調整
    for (i = len / 2 - 1; i >= 0; i--)
        max_heapify(arr, i, len - 1);
    
    //先將第一個元素和已排好元素前一位做交換,再從新調整,直到排序完畢
    for (i = len - 1; i > 0; i--) {
        swap(&arr[0], &arr[i]);
        max_heapify(arr, 0, i - 1);
    }
}

int main() {
    int arr[] = {7, 4, 2, 9, 8, 5};
    int len = sizeof(arr) / sizeof(int);
    
    /* sort */
    heap_sort(arr, len);
    
    /* print */
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", arr[i]);
    printf("\n");

    return 0;
}


編譯運行:



原文出自:http://blog.csdn.net/daiyudong2020/article/details/52529791

End;

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