堆排序是一種利用二叉堆的性質來進行排序的算法,二叉堆本身可以使用一個數組來表示,若我們有一個無序數組,我們可以先將其通過一系列方法變成一個二叉堆,然後再進行出堆操作,實際上就是將其目前最大值或最小值輸出,這樣我們的輸出順序其實就是按照從小到大或者從大到小一個順序,也就間接完成了我們的排序工作。
首先,二叉堆是什麼呢?
第一,二叉堆首先是一顆完全二叉樹,也就是一顆除了最底層其他層節點全部都是滿的且最底層節點從左到右是滿的,右邊可以空缺這樣一顆樹。
第二,二叉堆與完全二叉樹不同點在於二叉堆的根節點總是大於等於或小於等於其子節點的值。
知道了二叉堆的概念,那麼我們接下來要了解一下爲什麼二叉堆是使用數組來存儲的,這是因爲假如使用鏈式存儲的方式來存儲的話,一是佔用空間,二是實現複雜,由於完全二叉樹的節點之間是沒有空隔的,所以我們完全可以使用數組來存儲它,這樣並不浪費空間,而且對二叉堆的操作也轉換成了對數組的操作,這樣的操作也簡便,所以使用數組來存儲是非常合適的。
假如我們有一個二叉堆數組,那怎麼才能將其元素們進行排序呢?對於二叉堆我們有一個方法來將最大或者最小元素進行輸出,就是出堆操作,將堆頂元素進行出堆,這時二叉堆堆頂是空,我們這時將二叉堆最後一個元素放到堆頂,再通過一系列辦法將這個堆重新變成二叉堆,再次出堆堆頂元素,以此往復,這樣就能保證出堆元素一直是當前堆的最大元素或最小元素,這樣我們就實現了排序的過程。
以下是C語言代碼實現:
//交換數組中兩個元素的位置,i,j爲兩個元素的index
void swap(int tree[], int i, int j)
{
int temp = tree[i];
tree[i] = tree[j];
tree[j] = temp;
}
//n爲數組中元素個數 i爲進行heapify算法的節點,同時也是堆的下沉操作
void heapify(int tree[], int n, int i)
{
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int max = i;
if (tree[c1] > tree[max] && c1<n)
{
max = c1;
}
if (tree[c2] > tree[max] && c2<n)
{
max = c2;
}
if (max != i)
{
swap(tree, max, i);
heapify(tree, n, max);
}
}
//void Upheapify(int tree[], int n, int i)
//{
// int p = (i - 1) / 2;
// if (tree[p] < tree[i] && p>=0)
// {
// swap(tree, p, i);
// Upheapify(tree, n, p);
// }
//}
//使數組完全變成一個堆,n爲元素個數
void build_heap(int tree[], int n)
{
int last_node = n - 1;
int parent = (last_node - 1) / 2;
for (int i = parent;i >= 0;i--)
{
heapify(tree,n,i);
}
}
//排序輸出
void heap_Sort(int tree[],int n)
{
build_heap(tree, n);
int i;
for (i = n - 1;i >= 0;i--)
{
printf("%d\n", tree[0]);
swap(tree, i, 0);
heapify(tree, i, 0);
}
}
int main()
{
int tree[8] = { 12,1,22,34,15,33,45,35 };
heap_Sort(tree, 8);
}
以上代碼我已經測試過可以直接使用
堆排序時間複雜度O (nlgn)