排序演算法 堆排序

2021-08-08 19:51:27 字數 1569 閱讀 9826

一.  堆排序

1.  堆:類似於完全二叉樹,有a1,a2,a3, ...  an,個元素,且第 2*i+1 和 2*i+2 位置的關鍵字都小於或大於第 i 位置的關鍵字。

2.  大根堆與小根堆

大根堆:堆中的所有元素都滿足第 2*i+1 和 2*i+2 位置的關鍵字都小於第 i 位置的關鍵字。

小根堆:堆中的所有元素都滿足第 2*i+1 和 2*i+2 位置的關鍵字都大於第 i 位置的關鍵字。

3.  堆排序:利用堆積樹(堆)這種資料結構所設計的一種排序演算法,它是選擇排序的一種。可以利用陣列的特點快速定位指定索引的元素。在陣列的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。

二.  原理

1.  用大根堆排序的基本思想

① 先將初始檔案r[1..n]建成乙個大根堆,此堆為初始的無序區

② 再將關鍵字最大的記錄r[1](即堆頂)和無序區的最後乙個記錄r[n]交換,由此得到新的無序區r[1..n-1]和有序區r[n],且滿足r[1..n-1].keys≤r[n].key

③由於交換後新的根r[1]可能違反堆性質,故應將當前無序區r[1..n-1]調整為堆。然後再次將r[1..n-1]中關鍵字最大的記錄r[1]和該區間的最後乙個記錄r[n-1]交換,由此得到新的無序區r[1..n-2]和有序區r[n-1..n],且仍滿足關係r[1..n-2].keys≤r[n-1..n].keys,同樣要將r[1..n-2]調整為堆。

……直到無序區只有乙個元素為止。

2.  例如:對資料進行排列如下圖:

三.  **實現 -- 大根堆排序

#include

using namespace std;

//一次堆調整 -- 大根堆

static heap(int* arr, int start, int end)

if(tmp < arr[i])

else

}arr[parent] = tmp;

}//堆排序 -- 大根堆

void heapsort(int* arr, int len)

//建立大根堆

for(int i=(len-1-1)/2; i>=0; i--)

//一次堆調整

for(int i=0; i

四.  時間複雜度和空間複雜度及穩定性

1.  時間複雜度

首先建立大根堆時,需要從(len-1-1)/2處不斷調整,整個是線性的過程時間複雜度為o(n),然後對len-1個資料進行一次堆調整,直至無序區只剩下乙個資料,這個過程的時間複雜度為o((n-1)*lgn),所以整個排序過程總的算下來為o(n*lgn)。

2.  空間複雜度

縱觀整個排序過程除了區域性臨時變數外,未借用其它額外的空間,所以空間複雜度為o(1)。

3.  穩定性

無論是**還是例圖我們都可以看出,堆排序過程中是2*i+1 或 2*i+2 位置的關鍵字與 i 處的進行交換,這種跳躍式的資料交換使得此排序不穩定。



排序演算法 堆排序

1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...

排序演算法 堆排序

花了一晚上時間研究堆排序,這個排序困擾了哥很久,終於搞清楚了。一 堆的定義 1.父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值 2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 二 已知結點 i 則它的子結點 為2 i 1 與 2 i 2 父節點為 i 1 2 三 堆排序...

排序演算法 堆排序

由於不經常使用,之前學習看過的演算法都給忘了。現在把他們寫下來,記錄下來,以方便以後查閱。本篇文章的 即為堆排序的 主函式中是對輸入檔案中的序列進行排序,並將結果輸出到乙個檔案中。這是一種形式類似於google codejam的測試方法。include include using namespace...