堆排序

/*
 * 堆排序
時間複雜度:O(nlogn)
空間複雜度:O(1)
屬於不穩定排序算法。


  (1)用大根堆排序的基本思想
① 先將初始文件R[1..n]建成一個大根堆,此堆爲初始的無序區
② 再將關鍵字最大的記錄R[1](即堆頂)和無序區的最後一個記錄R[n]交換,
  由此得到新的無序區R[1..n-1]和有序區R[n],且滿足R[1..n-1].keys≤R[n].key
③ 由於交換後新的根R[1]可能違反堆性質,故應將當前無序區R[1..n-1]調整爲堆。
  然後再次將R[1..n-1]中關鍵字最大的記錄R[1]和該區間的最後一個記錄R[n-1]交換,
  由此得到新的無序區R[1..n-2]和有序區R[n-1..n],且仍滿足關係R[1..n- 2].keys≤R[n-1..n].keys,
  同樣要將R[1..n-2]調整爲堆。
  ……
  直到無序區只有一個元素爲止。
  
  (2)大根堆排序算法的基本操作:
① 初始化操作:將R[1..n]構造爲初始堆;
② 每一趟排序的基本操作:將當前無序區的堆頂記錄R[1]和該區間的最後一個記錄交換,然後將新的無序區調整爲堆(亦稱重建堆)。
注意:
①只需做n-1趟排序,選出較大的n-1個關鍵字即可以使得文件遞增有序。
②用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。
堆排序和直接選擇排序相反:在任何時刻,堆排序中無序區總是在有序區之前,
且有序區是在原向量的尾部由後往前逐步擴大至整個向量爲止。 
 */


/*
 * eg.數組{16, 7, 3, 20, 17, 8}
   16
  /    \
      7      3
     / \      /
   20 17 8


1.調整爲最大堆
20
       /    \
   17     8
    / \    /
  7  16  3


2.首元素[3]和尾元素[20]交換
3
 /   \
17    8    
/ \   /
  7  16 20
 將前5個元素(元素20除外)調整爲最大堆
  17
/    \
16     8    
  / \    /
 7  3  20
    
3.首元素[17]和倒數第2個元素[3]交換
3
 /   \
16     8    
  / \    /
 7  17  20
 將前4個元素(20和17除外)調整爲最大堆
16
 /    \
7      8    
/ \    /
  3  17  20


    4.首元素[16]和倒數第3個元素[3]交換
3
 /   \
7     8    
/ \    /
  16 17  20
    
5.首元素[3]和倒數第4個元素[8]交換
8
 /   \
7     3    
/ \    /
  16 17  20
  將前3個元素調整爲最大堆
3
 /   \
7     8    
/ \    /
 16 17  20


    6.首元素[3]和倒數第5個元素[7]交換
7
 /   \
3     8    
/ \    /
  16 17  20
 將前兩個元素調整爲最大堆
3
 /   \
7     8    
/ \    /
  16 17  20

 */


#include <iostream>
using namespace std;

/*
 *	調整爲最大堆
 */
void HeapAdjust(int *arr, int index, int len)
{
	while(2*index+1 < len){
		//左孩子索引
		int childIndex = 2*index+1;
		if(2*index+2 < len){
			if(arr[2*index+1] < arr[2*index+2]){
				//右孩子索引
				childIndex = 2*index + 2;
			}
		}
		if (arr[index] < arr[childIndex])
		{
			int tmp = arr[index];
			arr[index] = arr[childIndex];
			arr[childIndex] = tmp;
			index = childIndex;
		}
		else{
			break;
		}
	}
}

void HeapSort(int *arr, int len)
{
	int i;
	//將整個數組按最大堆排序
	for(i=len/2-1; i>=0; i--)
	{
		// len/2-1是最後一個非葉節點
		HeapAdjust(arr, i, len);
	}

	//將arr[0..i)按最大堆排序
	for (i = len-1; i>0; i--)
	{
		//arr[0]是最大的一個元素,將其與arr[i]交換,使大元素排到數組尾部
		int tmp = arr[0];
		arr[0] = arr[i];
		arr[i] = tmp;
		//交換後破壞了最大堆,arr[0..i)重新按最大堆排序
		HeapAdjust(arr, 0, i);
	}
}

int main()
{
	int array[] = {16, 7, 3, 20, 17, 8};
	HeapSort(array, 6);
	
	for(int i=0; i<6; i++)
		cout<<array[i]<<"  ";
	cout<<endl;
	return 0;
}


發佈了22 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章