第三章:查詢與排序(下)----------- 3.25 知其然知其所以然:小頂堆與topK的具體程式碼實現

Curtis_發表於2019-03-11

小頂堆與topK的具體程式碼實現:

       求海量資料(正整數)按逆序排列的前k個數(TopK),因為數量太大,不能全部儲存在記憶體中,只能一個一個地從磁碟或者網路上讀取資料,請設計一個高效的演算法來解決這個問題。

       第一行:使用者輸入K,代表要求得topK。

       隨後的N(不限制)行,每一行是一個整數,代表使用者輸入的資料。

       使用者輸入-1代表輸入終止。

       請輸出topK,從小到大,空格分割。

       解決:大頂堆。

思路:

輸入N個資料時,若n<k,依次新增到陣列(堆)當中;當填入資料達到k時,立刻堆化

若n>k,比較要填入數與堆頂資料,若x>heap[0],將heap[0]賦值為x,並向下堆化。

ps:n:已填入資料的數量。

 程式碼:

#include<iostream>
using namespace std;

int* heap;  //全域性變數 ===> 陣列頭指標(陣列名) 
int size=0;
int k;  //輸出前k個數	

/*******/ 
void deal(int x);
void makeMinHeap(int A[],int length); 
void MinHeapFixDown(int A[],int i,int n);
void printRs();
/*******/

int main(){
	std::ios_base::sync_with_stdio(false);
 	
	cin>>k;
	
	heap=new int[k]; // 動態建立陣列 
	
	int x;  
	while((cin>>x)&&x!=-1){
		deal(x); //處理x 
	}	
	printRs();
			
	return 0;
}

/*
如果資料的數量小等於k,直接加入堆中
等於k的時候,進行堆化
*/ 
void deal(int x){
	if(size<k){
		heap[size++]=x;
		
		if(size==k){
			//堆化
		 	makeMinHeap(heap,k);
		}
	}
	else{
		//x和堆頂進行比較,如果x大於堆頂,x將堆頂擠掉,並向下調整 
		if(heap[0]<x){
			heap[0]=x;
			MinHeapFixDown(heap,0,k);
			printRs();
		}	
	}
	
} 

void printRs(){
	for(int i=0;i<k;i++){
		cout<<heap[i]<<" ";
	}
	cout<<endl;
}


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);	 
}

 結果:

相關文章