第三章:查詢與排序(下)----------- 3.16堆的概念及堆排序思路

Curtis_發表於2019-03-10

堆的概念及堆排序思路:

二叉堆是完全二叉樹,或者近似完全二叉樹。

二叉堆滿足兩個特性:

---1、父節點的鍵值總是大於或等於(小於或等於)任何一個節點的鍵值;

---2、每個節點的左子樹和右子樹都是一個二叉堆(都是最大堆或最小堆)。

任何節點的值都大於其子節點的值------大頂堆

任何節點的值都小於其子節點的值------小頂堆

 堆排序:

1、堆化,反向調整使得每個子樹都是大頂或者小頂堆;

2、按序輸出元素:把堆頂和堆末元素對調,然後調整堆頂元素。

虛擬碼: 

MakeMinHeap(A){
	n=A.length;
	for i from n/2-1 down to 0{
		MinHeapFixDown(A,i);
	}
}


/*
①、先看有沒有左右孩子; 
②、找到左右孩子中較小的那個; 
③、調整(交換或者不交換); 
④、遞迴地向下調整。 
*/

MinHeapFixDown(A,i,n){
	//找到左右孩子
	left=2*i+1;
	right=2*i+2; 
	//左孩子已經越界,i就是葉子節點	
	if(left>=n){
		return;
	}
	min=left;
	if(right>=n){
		min=left;
	}
	else{
		if(A[right]<A[left]){
			min=right;
		}
	}
	//min指向了左右孩子中較小的那個 
	
	//如果A[i] 比兩個孩子都要小,不用調整
	if(A[i]<=A[min]){
		return;
	} 
	
	//否則,找到兩個孩子中較小的,和i交換
	temp=A[i];
	A[i]=A[min];
	A[min]=temp;
	
	//小孩子那個位置的值發生了變化,i變更為小孩子那個位置,遞調整
	MinHeapFixDown(A,min,n);
}

 

//sort函式:
sort(A){
	//先對A進行堆化
	MakeMinHeap(A);
	for(int x=n-1;x>=0;x--)
		//把堆頂,0號元素和最後一個元素對調
		swap(A,0,x);
  		//縮小堆的範圍,對堆頂元素進行向下調整 
  		MinHeapFixDown(A,0,x-1);
} 

程式碼:

#include<iostream>
using namespace std;
/**
*思路:首先要知道大頂堆和小頂堆,陣列就是一個堆,每個i節點的左右孩子是2i+1和2i+2 
*      有了堆,將其堆化:從n/2-1個元素開始向下修復,將每個節點修復為小(大)頂堆 
*      修復完成後,陣列具有小(大)頂堆的性質 
*      按序輸出:小頂堆可以對陣列逆序排列,每次交換堆頂和末尾元素,對棧頂進行向下修復 
*
*時間複雜度:堆化:一半的元素修復,修復是單分支的,所以整體堆化為nlgn。(PS:常數因子較大)
*排序:n個元素都要取出,因此調整為n次,每次調整修復同上是lgn的,整體為nlgn 
*空間複雜度:不需要開闢輔助空間 
*原址排序 
* 穩定性:不穩定 
*/
void MinHeapFixDown(int A[],int i,int n); 

void makeMinHeap(int A[],int length){
	int n=length;
	for(int i=n/2-1;i>=0;i--){
		MinHeapFixDown(A,i,n);
	}
} 

//向下調整函式 
void MinHeapFixDown(int A[],int i,int n){
	//找到左右孩子
	int left=2*i+1;
	int right=2*i+2;
	//左孩子已經越界,i就是葉子節點
	if(left>=n){
		return;
	} 
	 int min=left;
	 if(right>=n){
	 	min=left;
	 }
	 else{
	 	if(A[right]<A[left]){
	 		min=right;
	 	}
	 }
	 //min指向了左右孩子中較小的那個
	 
	 //如果A[i]比兩個孩子都要小,不用調整
	 if(A[i]<A[min]){
	 	return;
	 } 
	 //否則,找到兩個孩子中較小的,和i交換
	 int temp=A[i];
	 A[i]=A[min];
	 A[min]=temp;
	 
	 //小孩子那個位置的值發生了變化,i變更為小孩子的那個位置,遞迴調整
	 MinHeapFixDown(A,min,n);	 
}

//排序函式
void sort(int A[],int length){
	//先對A進行堆化
	makeMinHeap(A,length);
	for(int x=length-1;x>=0;x--){
		//把堆頂,0號元素和最後一個元素對調		
		swap(A[0],A[x]);
		//縮小堆的範圍,對堆頂元素進行向下調整 
		MinHeapFixDown(A,0,x);
	}
} 

int main(){
	int arr[]={6,2,5,8,2,1,9,5,6};
	int len= 9;
	
	sort(arr,len);
	for(int i=0;i<len;i++){
		cout<<arr[i]<<" ";
	}
	return 0;
} 

結果:

相關文章