堆排序+代碼實現,堆排序代碼
堆排序
堆,heap,是二叉樹的一種。小根堆有這樣的性質——任意一個結點的值比它的左右孩子都要小。
排序思想
將待排元素看作是完全二叉樹,物理上用一維數組儲存。
實現堆排序需要解決兩個問題:
1.如何將雜亂的完全二叉樹初始化為一個堆?
答:從最後一個非葉結點起,將該節點當做根,自上而下進行調整,使之成為一個堆。然後依次對倒數第二個、倒數第三個、直至正數第一個結點進行此操作。
2.輸出堆頂元素後,如何將餘下的元素調整為一個堆?
答:將最後一個結點放在原根結點位置上,以它為根進行上述的調整。
複雜度分析。
二叉樹的層數計算方法,從上往下,1,2,3,4......
耗時的操作有構造初始堆和調整堆兩部分。
對深度為h的堆進行自上而下的調整,最多比較次數為2*(h-1)。
在初始化堆的過程中,完全二叉樹的高度為h,總的比較次數為
綜上,堆排序在複雜度最壞的情況下為O((1)式+(2)式)=O(n*logn)。
代碼
堆排序原始碼
演算法如下:
//hsort.c
//演算法來自《演算法導論》
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef unsigned long int ULong;
ULong heapSize = 0;
ULong Parent(ULong index) {
//因為C語言的數組起始下標為0
//所以和《演算法導論》中的代碼有點不同
//index >> 1 == i / 2;
return (index % 2) ? (index >> 1) : ((index >> 1) - 1);
}
ULong Left(ULong index) {
//index << 1 == index * 2;
return ((index << 1) + 1);
}
ULong Right(ULong index) {
return ((index << 1) + 2);
}
void swap(char * a, char * b) {
char tmp = *a;
*a = *b;
*b = tmp;
}
//array[index] 與其左右子樹進行遞迴對比
//用最大值替換array[index]
void maxHeapify(char * array, ULong index) {
ULong largest = 0;
ULong left = Left(index);
ULong right = Right(index);
if ((left <= heapSize) && (array[left] > array[index]))
largest = left;
else
largest = index;
if ((right <= heapSize) && (array[right] > array[largest]))
largest = right;
if (largest != index) {
swap(&array[index], &array[largest]);
maxHeapify(array, largest);
}
}
//初始化堆,將數組中的每一個元素置放到適當的位置
//完成之後,堆頂的元素為數組的最大值
void buildMaxHeap(char * array, ULong length) {
int i;
heapSize = length;
for (i = (length >> 1); i >= 0; i--)
maxHeapify(array, i);
}
int heapSort(char * array, ULong length) {
int i;
buildMa......餘下全文>>
【資料結構進】給個堆排序的執行個體(不要代碼)
假設是打算做從小到大的排序,所以是建大頂堆。
初始的時候堆就是整個序列(15,14,5,7,12,18)
所以整個堆的樣子是:
15
14 5
7 12 18
此時從最底部的三元組開始進行建堆
第一步: 第二步:
15 18
14 18 14 15
7 12 5 7 12 5
接著開始排序,此時先交換18 和 5,此時18就是最大的一個數位於最末位置,該數
不用繼續堆排序,因此對
5
14 15
7 12
進行建堆過程,結果為:
15
14 5
7 12
依次類推即可完成最終的堆排序。
第一次建堆和後續堆排序的過程差別在於,第一次堆序列都是亂的,所以
從最後的一個分支由下而上的建堆,而後面的堆排序過程,由於堆已經有
基本規律,除了頂部元素以外,其他都基本有序,所以從上向下進行建堆過程。