實現堆排序
實現堆排序
1. 堆排序的思想
堆是一棵完全二叉樹,任何一個節點的val不大於(最小堆)或者不小於(最大堆)其左右孩子節點的關鍵字。
以最大堆為例,堆排序的基本思想是:
1)將初始待排序關鍵字序列(R1,R2....Rn)構建成大頂堆,此堆為初始的無序區;
2)將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n];
3)由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,......Rn-1)調整為新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。
其實,堆排序最重要的兩部分就是:初始化堆和調整堆。
我們可以用下圖展示堆排序的過程:
給定一個整形陣列a[]={16,7,3,20,17,8},對其進行堆排序。
1) 構建最大堆;
這一步驟只需要構建一個完全二叉樹即可;
2)初始化最大堆;
這一步驟需要不斷調整,使得堆成為最大堆。
調整從最後一個非葉子節點開始。每次調整都是從父節點、左孩子節點、右孩子節點三者中選擇最大者跟父節點進行交換(交換之後可能造成被交換的孩子節點不滿足堆的性質,因此每次交換之後要重新對被交換的孩子節點進行調整)。
3)排序,繼續調整最大堆;
堆頂20和3交換:
堆頂17和3交換:
堆頂16和3交換:
堆頂8(7)和3交換:
總的來說,堆排序就是一個不斷調整堆的過程。
堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從R[1...n]中選擇最大記錄,需比較n-1次,然後從R[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。對於n個關鍵字序列,最壞情況下每個節點需比較log2(n)次,因此其最壞情況下時間複雜度為nlogn。
堆排序為不穩定排序,不適合記錄較少的排序。
2. 程式設計實現堆排序
#include<iostream>
#include<algorithm>
using namespace std;
// 調整堆函式
void HeapAdjust(int *a, int i, int size) // a:陣列;i:節點index;size:樹的規模
{
int lchild = 2 * i; // 節點的左孩子編號
int rchild = 2 * i + 1; // 節點的右孩子編號
int max = i; //節點編號備份
if(i <= size/2 - 1)
{
if(lchild <= size && a[lchild] > a[max]) // 左孩子比節點值要大
max = lchild;
if(rchild <= size && a[rchild] > a[max]) // 右孩子比節點值要大
max = rchild;
if(max != i) // 如果上面發生了交換,也就是如果上面有if成立了
{
swap(a[i], a[max]); // 首先要交換二者的真實值,因為上面只是index的交換
HeapAdjust(a, max, size); // 其次,需要判斷交換之後還需要重新調整嗎
}
}
}
//建立堆函式
void BuildHeap(int *a, int size)
{
int i;
for(i = size/2 - 1; i >= 0; i--) // 非葉子節點最大序號值為size/2,需要遍歷所有的節點
{
HeapAdjust(a, i, size); // 調整
}
}
// 堆排序函式
void HeapSort(int *a, int size)
{
int i;
BuildHeap(a, size);
for(i = size; i >= 0; i--)
{
swap(a[0], a[i]); // 交換堆頂和最後一個元素,每次將剩餘元素中的最大者放到最後面
HeapAdjust(a, 0, i-1); // 重新調整堆頂節點成為大頂堆,這個時候就要除出最後一個元素,範圍是1~n-1
}
}
int main()
{
int a[] = {100, 16, 20, 3, 11, 17, 8};
int size = 7;
HeapSort(a, size);
for(int i = 0; i < size; i++)
{
cout<<a[i]<<endl;
}
cout<<endl;
return 0;
}
參考連結:
http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
相關文章
- js 實現堆排序JS排序
- 堆排序(php實現)排序PHP
- 堆排序(實現c++)排序C++
- 使用 Swift 實現堆排序Swift排序
- 堆排序c++實現排序C++
- 【轉】堆排序Heap Sort——Java實現排序Java
- PHP 實現堆, 堆排序以及索引堆PHP排序索引
- 常見演算法 PHP 實現 -- 堆排序演算法PHP排序
- 大根堆和堆排序的原理與實現排序
- Java實現HEAPSORT堆排序演算法Java排序演算法
- MYSQL實現ORDER BY LIMIT的方法以及優先佇列(堆排序)MySqlMIT佇列排序
- 完全二叉樹實現優先佇列與堆排序二叉樹佇列排序
- 利用java實現插入排序、歸併排序、快排和堆排序Java排序
- 看懂堆排序——堆與堆排序(三)排序
- 堆排序排序
- 堆排序的Python實現(附詳細過程圖和講解)排序Python
- 排序演算法:堆排序的實現和時間複雜度分析排序演算法時間複雜度
- 【資料結構】堆排序和模擬實現優先順序佇列!!資料結構排序佇列
- js堆排序JS排序
- [JAVA]堆排序Java排序
- 【演算法】排序03——看著複雜其實就兩步的堆排序(含程式碼實現)演算法排序
- 夯實基礎:排序演算法之堆排序排序演算法
- 資料結構&演算法實踐—堆排序資料結構演算法排序
- 堆排序詳解排序
- python 堆排序Python排序
- 堆排序 Heap Sort排序
- 堆排序(C++)排序C++
- HeapSort 堆排序排序
- 【筆記】堆排序筆記排序
- 簡單堆排序排序
- 堆與堆排序(一)排序
- 堆排序演算法排序演算法
- 堆操作與堆排序排序
- 演算法-一步步教你如何用c語言實現堆排序(非遞迴)演算法C語言排序遞迴
- 排序演算法__堆排序排序演算法
- 順序表的堆排序排序
- 排序演算法-堆排序排序演算法
- 排序演算法 - 堆排序排序演算法