通用算法 -[排序算法] - 堆排序

1、算法思想

先回顧以下堆的概念
堆分爲兩種:最大堆和最小堆,兩者的差別在於節點的排序方式。
在最大堆中,父節點的值比每一個子節點的值都要大。在最小堆中,父節點的值比每一個子節點的值都要小。這就是所謂的“堆屬性”,並且這個屬性對堆中的每一個節點都成立。
例子:
在這裏插入圖片描述
這是一個最大堆,因爲每一個父節點的值都比其子節點要大。10 比 7 和 2 都大。7 比 5 和 1都大。
堆的實際存儲結構是一個數組,i表示根節點的索引,i2+1和i2+2分別表示根節點i的左右子節點。
上圖所示的堆實際存儲爲
[10,7,2,5,1]

堆排序就是先將數組中元素構建成一個最大堆,然後把堆頂的元素與最後一個元素交換,交換之後破壞了堆的特性,我們再把堆中剩餘的元素再次構成一個大頂堆,然後再把堆頂元素與最後第二個元素交換….如此往復下去,等到剩餘的元素只有一個的時候,此時的數組就是有序的了。
爲方便理解我還準備了動圖:
在這裏插入圖片描述

2、實現代碼

 // 堆排序
void headSort(int* arr int length) {
    
        //構建大頂堆
        for (int parent = (length - 2) / 2; parent >= 0; parent--) 			   	
        { 
            downAdjust(arr, parent, length - 1);
        }
        
        //進行堆排序
        for (int i = length - 1; i >= 1; i--) {
            // 把堆頂元素與最後一個元素交換
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            // 把打亂的堆進行調整,恢復堆的特性
            downAdjust(arr, 0, i - 1);
        }
    }


        //下沉操作
 void downAdjust(int*  arr, int parent, int length) {
        //臨時保存要下沉的元素
        int temp = arr[parent];
        //定位左孩子節點的位置
        int child = 2 * parent + 1;
        //開始下沉
        while (child <= length) {
            // 如果右孩子節點比左孩子大,則定位到右孩子
            if(child + 1 <= length && arr[child] < arr[child + 1])
                child++;
            // 如果孩子節點小於或等於父節點,則下沉結束
            if (arr[child] <= temp ) break;
            // 父節點進行下沉
            arr[parent] = arr[child];
            parent = child;
            child = 2 * parent + 1;
        }
        arr[parent] = temp;
    }
}

3、算法分析

  • 時間複雜度:O(nlogn)
  • 空間複雜度:O(1)
  • 非穩定排序
  • 原地排序
發佈了155 篇原創文章 · 獲贊 16 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章