基本思想
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。堆排序可以看作是對選擇排序的改進。
通常堆是通過一維數組來實現的。在起始數組爲0的情形中:
- 父節點i的左子節點在位置(2*i+1);
- 父節點i的右子節點在位置(2*i+2);
- 子節點i的父節點在位置floor((i-1)/2);
在堆的數據結構中,堆中的最大值總是位於根節點。堆中定義以下幾種操作:
- 最大堆調整(Max_Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點
- 創建最大堆(Build_Max_Heap):將堆所有數據重新排序
- 堆排序(HeapSort):移除位在第一個數據的根節點,並做最大堆調整的遞歸運算
時間複雜度分析
建立N個元素的二叉堆需要花費
代碼實現
最大堆調整有遞歸和非遞歸實現方式。
void Heap_adjust(int arr[], int index, int len)
{
while(true)
{
int iMax = index;
int iLeft = 2 * index + 1;
int iRight = 2 * index + 2;
if(iLeft < len && arr[index] < arr[iLeft])
iMax = iLeft;
if(iRight < len && arr[iMax] < arr[iRight])
iMax = iRight;
if(iMax != index)
{
swap(arr[index], arr[iMax]);
index = iMax;
}
else
break;
}
}
void Heap_adjust2(int arr[], int index, int len)
{
int iMax = index;
int iLeft = 2 * index + 1;
int iRight = 2 * index + 2;
if(iLeft < len && arr[index] < arr[iLeft])
iMax = iLeft;
if(iRight < len && arr[iMax] < arr[iRight])
iMax = iRight;
if(iMax != index)
{
swap(arr[index], arr[iMax]);
Heap_adjust2(arr, iMax, len);
}
}
void Build_maxheap(int arr[], int len)
{
for(int i = len / 2; i >= 0; i --)
{
Heap_adjust(arr, i , len);
}
}
void Heap_Sort(int arr[], int len)
{
Build_maxheap(arr, len);
for(int i = len - 1; i > 0; i --)
{
swap(arr[0], arr[i]);
Heap_adjust(arr, 0, i);
}
}
測試代碼
#include <iostream>
#include <cstring>
#include <ctime>
#include <cmath>
using namespace std;
#define ArraySize 100000
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
void Bubble_sort(int arr[], int len)
{
for(int i = 0; i < len; i ++)
{
for(int j = i + 1; j < len; j ++)
if(arr[i] > arr[j])
swap(arr[i], arr[j]);
}
}
void Bubble_sort1(int arr[], int len)
{
for(int i = 0; i < len; i ++)
{
for(int j = len - 1; j >= i; j --)
{
if(arr[i] > arr[j])
swap(arr[i], arr[j]);
}
}
}
void Bubble_sort2(int arr[], int len)
{
bool flag = true;
while(flag)
{
flag = false;
for(int i = 0; i < len; i ++)
for(int j = len - 1; j >= i; j --)
if(arr[i] > arr[j])
swap(arr[i], arr[j]);
}
}
void Slect_sort(int arr[], int len)
{
for(int i = 0; i < len; i ++)
{
int min_index = i ;
for(int j = i + 1; j < len; j ++)
{
if(arr[min_index] > arr[j])
min_index = j;
}
if(i != min_index)
swap(arr[i],arr[min_index]);
}
}
void Insert_sort(int arr[], int len)
{
for(int i= 1; i < len; i ++)
{
int key = arr[i];
int j = i;
while(j && arr[j - 1] > key)
{
arr[j] = arr[j - 1];
j --;
}
arr[j] = key;
}
}
void Shell_sort(int arr[], int len)
{
int increment = len / 2;
while(increment)
{
for(int i = increment; i < len; i ++)
{
int key = arr[i];
/*int j ;
for(j = i; j >= increment; j -= increment)
{
if(arr[j-increment] > key )
arr[j] = arr[j-increment];
else
break;
}*/
int j = i;
while(j >= increment && arr[j-increment] > key)
{
arr[j] = arr[j-increment];
j -= increment;
}
arr[j] = key;
}
increment /= 2;
}
}
void Shell_sort1(int arr[], int len)
{
int increment = 0;
for(increment = len/2; increment > 0; increment /=2)
{
for(int i = increment; i < len; i++)
{
int key = arr[i];
int j = 0;
for(j = i; j >= increment; j -=increment)
{
if(arr[j-increment] > key)
arr[j] = arr[j-increment];
else
break;
}
arr[j] = key;
}
}
}
void Shell_sort2(int arr[], int len)
{
int index = log( 2*len + 1) / log(3.0);
//cout << index << endl;
int increment = ( pow(3.0, index) - 1 ) / 2;
//cout << increment << endl;
while(increment)
{
for(int i = increment; i < len; i ++)
{
int key = arr[i];
/*int j ;
for(j = i; j >= increment; j -= increment)
{
if(arr[j-increment] > key )
arr[j] = arr[j-increment];
else
break;
}*/
int j = i;
while(j >= increment && arr[j-increment] > key)
{
arr[j] = arr[j-increment];
j -= increment;
}
arr[j] = key;
}
index -= 1;
increment = ( pow(3.0, index) - 1 ) / 2;
}
}
void Heap_adjust(int arr[], int index, int len)
{
while(true)
{
int iMax = index;
int iLeft = 2 * index + 1;
int iRight = 2 * index + 2;
if(iLeft < len && arr[index] < arr[iLeft])
iMax = iLeft;
if(iRight < len && arr[index] < arr[iRight])
iMax = iRight;
if(iMax != index)
{
swap(arr[index], arr[iMax]);
index = iMax;
}
else
break;
}
}
void Heap_adjust2(int arr[], int index, int len)
{
int iMax = index;
int iLeft = 2 * index + 1;
int iRight = 2 * index + 2;
if(iLeft < len && arr[index] < arr[iLeft])
iMax = iLeft;
if(iRight < len && arr[index] < arr[iRight])
iMax = iRight;
if(iMax != index)
{
swap(arr[index], arr[iMax]);
Heap_adjust2(arr, iMax, len);
}
}
void Build_maxheap(int arr[], int len)
{
for(int i = len / 2; i >= 0; i --)
{
Heap_adjust(arr, i , len);
}
}
void Heap_Sort(int arr[], int len)
{
Build_maxheap(arr, len);
for(int i = len - 1; i > 0; i --)
{
swap(arr[0], arr[i]);
Heap_adjust(arr, 0, i);
}
}
void Print_array(int arr[], int len)
{
for(int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main(int argc, char const *argv[])
{
/* code */
int Array[ArraySize];
int Array1[ArraySize];
int Array2[ArraySize];
time_t begin , end;
srand(time(NULL));
for(int i = 0; i < ArraySize; i ++)
{
Array[i] = rand()%ArraySize;
//cout << Array[i] << " ";
}
memcpy(Array1, Array, ArraySize * sizeof(Array1[0]));
memcpy(Array2, Array, ArraySize * sizeof(Array2[0]));
// Print_array(Array, ArraySize);
/* begin = clock();
Bubble_sort2(Array, ArraySize);
end = clock();
cout << "Bubble_sort runtime: " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;
begin = clock();
Slect_sort(Array1, ArraySize);
end = clock();
cout << "Slect_sort runtime: " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;
begin = clock();
Insert_sort(Array2, ArraySize);
end = clock();
cout << "Insert_sort runtime: " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;*/
begin = clock();
Shell_sort1(Array1, ArraySize);
end = clock();
cout << "Shell_sort1 runtime: " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;
begin = clock();
Shell_sort2(Array2, ArraySize);
end = clock();
cout << "Shell_sort2 runtime: " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;
begin = clock();
Heap_Sort(Array, ArraySize);
end = clock();
cout << "Heap_Sort runtime: " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;
//Print_array(Array2, ArraySize);
return 0;
}
運行結果如下:
Shell_sort1 runtime: 0.038s
Shell_sort2 runtime: 0.021s
Heap_Sort runtime: 0.026s
參考資料
堆排序 - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/%E5%A0%86%E6%8E%92%E5%BA%8F
常見排序算法 - 堆排序 (Heap Sort) | bubkoo
http://bubkoo.com/2014/01/14/sort-algorithm/heap-sort/