堆的基本概念
堆是將一個序列看成完全二叉樹,意思就是說將一個序列看成是二叉樹的順序結構,而且這個順序結構沒有空節點,常見的考法是判斷一個序列是否是一個堆(大根堆或小根堆),大根堆和小根堆的定義如下:
- 小根堆 : 所有的根節點小於所有子節點(如果子節點存在),即$K[i]\leq K[2i]$且$K[i]\leq K[2i+1]$
- 大根堆 : 所有的根節點大於所有子節點(如果子節點存在),即$K[i]\geq K[2i]$且$K[i]\geq K[2i+1]$
堆排序
調整算法
堆排序實際上是不斷將一個堆上的根結點彈出,因爲根節點總是最大的或者最小的,只要彈出後不斷建成新的堆即可,建堆時間利用的就是調整算法.調整算法有如下特點:
- 從第一個非葉子節點開始調整
- 如果調整的非葉子節點的子節點也是非葉子節點,那麼子樹還要調整,因爲調整後可能破環子樹的堆狀態.
代碼:
void sift(int *seq,int low,int high) {
int i = low;
int j = 2*i;
int temp = seq[i];
while(j<=high) {
if(j<high&&seq[j]<seq[j+1]) {
j = j+1;
}
if(temp<seq[j]) {
seq[i] = seq[j];
i = j;
j = 2*i;
} else {
break;
}
}
seq[i] = temp;
}
排序算法
堆排序算法示例:
#include <iostream>
using namespace std;
void sift(int *seq,int low,int high) {
int i = low;
int j = 2*i;
int temp = seq[i];
while(j<=high) {
if(j<high&&seq[j]<seq[j+1]) {
j = j+1;
}
if(temp<seq[j]) {
seq[i] = seq[j];
i = j;
j = 2*i;
} else {
break;
}
}
seq[i] = temp;
}
int main() {
int seq[10] = {6,8,7,9,0,1,3,2,4,5};
for(int i=4; i>=0; i--) {
sift(seq,i,9);
}
for(int i=0; i<10; i++) {
cout<<seq[i]<<" ";
}
cout<<"\n";
for(int i=0; i<10; i++) {
cout<<seq[0]<<" ";
seq[0] = seq[9-i];
sift(seq,0,9-i);
}
}