這次想寫一下堆排序,之前遇到過好多次有關堆排序的問題,無論是編程還是選擇題。但是對這個堆排序一直是稀裏糊塗,一個原因網上好多博客寫的爛,衆說紛紜,各執一詞,還有一個原因是自己沒有真正想要搞懂一個問題,真正搞透問題。
好了廢話不多說開始講解這次的主角堆排序。
堆排序步驟
堆排序的步驟主要是三個:
- 將序列構建成堆,然後整理這個堆,如果最終需要得到升序->大頂堆,降序->小頂堆
- 將堆頂元素和末尾元素互換,將最大元素放到堆的最後
- 然後調整這個堆,將除了最後一個元素之外的其他元素按照堆的順序進行整理,然後再將堆頂元素和最後一個元素(除了剛剛已經被放在最後一個的元素)進行互換位置。
這個地方有很多地方都是坑:
一個就是:
首先必須按照最後的排序要求構建大頂堆還是小頂堆!!!
首先必須按照最後的排序要求構建大頂堆還是小頂堆!!!
首先必須按照最後的排序要求構建大頂堆還是小頂堆!!!
第二個就是:
(這個步驟非常重要)構建大頂堆,小頂堆的方法:從最後一個非葉子節點(這個節點的位置非常有意思:如果節點數爲奇數:n/2-1; 如果節點數是偶數:n/2)開始調整,將這個節點和自己的兩個子節點進行比較,將這三個節點中最大或者最小的放在根節點處,從右向左,從下向上,依次整理過去。
第三個就是:
互換堆頂和末尾節點之後,末尾節點就不考慮了(排除在後續操作之外了)
複雜度
堆排序的平均時間複雜度、最好情況時間複雜度、最差情況時間複雜度都是
空間複雜度:
堆排序是一種不穩定的排序。
C++實現代碼
//調用heap_sort,其中data爲待排序的數組,heapsize爲數組長度
void heapsort(int data[],int heapsize){
//堆排序算法實現主體:先用build_max_heap將輸入數組構造成大頂堆
//將data[0]和堆的最後一個元素交換
//繼續進行調整
build_max_heap(data,heapsize);
for(int i=heapsize-1;i>0;i--){
int t=data[0];
data[0]=data[i];
data[i]=t;
max_heapify(data,0,i);
}
}
void build_max_heap(int data[],int heapsize){
//建堆的過程,通過自底向上地調用max_heapify來將一個數組data[1...n]變成一個大頂堆
//只對除了葉子節點之外的節點進行調整
for(int i=heapsize/2-1;i>=0;i--)
max_heapify(data,i,heapsize);
}
void max_heapify(int data[],int i,int heapsize){
//以某個節點爲根節點的子樹進行調整,調整爲大頂堆
int l=2*i+1;
int r=2*i+2;
int largest =i;
if(l<heapsize && data[l]>data[i]){
largest =l;
}
if(r<heapsize && data[r]>data[largest]){
largest =r;
}
if(largest!=r){
int temp=data[largest];
data[largest]=data[i];
data[i]=temp;
max_heapify(data,largest,heapsize);
}
}