大數據量的排序算法 -最小堆排序算法


  今天有人推薦了一個排序算法:最小堆排序算法。號稱能處理10億數據的排序問題.

  正好將要面臨2.5億數據的查詢計算比對問題,從沒面對過如此大的數據量,之前處理過最大的表不過3000萬,心里正有些惴惴不安。正好把這個算法拿來學習揣摩一番。

  剛開始隨手寫了個遞歸排序,本以為想法是比對一下2種算法的,后來發現結果大跌眼鏡。

   下表中,表頭是隨機數量,內容單位為毫秒。

  1000 10000 20000 100000 1000000 5000000 10000000 15000000 20000000
最小堆排序算法 0 16 16 32 327 2137 4804 7675 10701
遞歸排序 16 172 718  -  -  -  -  -  -

       自己寫的遞歸算法只能給20000個隨機數排序,超過就會引發java.lang.StackOverflowError異常,查了一下是jvm的堆棧溢出了,看來遞歸也不能隨便用。。。。。。。

   回到最關注的時間問題上,最小堆排序算法相當穩定,如果看折線圖的話基本是條略上揚的斜線,1億的隨機數列也沒問題,時間大概是70159毫秒,再多的數量考慮時間就沒一一測試。

      確實是個很好的算法,給將來的問題留了一條解決之路。

  以下是代碼

  

package algorithm;

import java.util.Random;

/******************************8
 * 有十億條數字,要從中選出最大的1000條,用什么算法最好?
 * 需要考慮空間復雜度和時間復雜度
 * 其中10億要表達的意思是,內存不能一次裝下
 * 
 * 這個算法是“計算機科學中最重要的32個算法”之一
 * 
 * @author Administrator
 *
 */
public class 最小堆排序算法 {

	/*
	* 將數組調整為小根堆,即由小到大排序
	*/
	public static int[] heap = new int[] { 1,3,7,3,5,2,8,4,6,10,9,11,54,23,13};
	
	public static void initData(int n){
		Random ran = new Random();
		heap = new int[n];
		for(int i=0;i<n;i++){
			heap[i] = ran.nextInt(n*2);
		}
	}
	
	public static void main(String[] args) {
		initData(1*10000);
		long start = System.currentTimeMillis();
		algorithm();
		//custom(heap.length);
		long end = System.currentTimeMillis();
		System.out.println("cost:"+(end-start));
		show();
	}
	
	/**
	 * 展示排序結果
	 */
	public static void show(){
		StringBuffer sb = new StringBuffer();
		for (int j = 0; j < heap.length; j++) {
			//System.out.print(heap[j] + " ");
			//sb.append(heap[j]+" ");
		}
		//System.out.println(sb.length()+","+sb.toString());		
	}
	
	/**
	 * 自己定義的排序算法,主要用來比較時間
	 */
	public static void custom(int end){
		for(int i=0;i<end-1;i++){
			if(heap[i]>heap[i+1]){
				int temp = heap[i];
				heap[i] = heap[i+1];
				heap[i+1] = temp;
			}
		}
		if(end>1){
			custom(end-1);
		}
	}
	
	/***
	 * 最小堆排序算法
	 */
	public static void algorithm(){
		int temp;
		/*
		* 創建堆(對該堆進行簡單的排序)
		*/
		CreateHeap();
		for (int i = heap.length - 1; 0 < i; i--) {
			temp = heap[0];
			heap[0] = heap[i];
			heap[i] = temp;
			/*
			//展示每次排序后的結果
			for (int j = 0; j < heap.length; j++) {
				System.out.print(heap[j] + " ");
			}
			*/
			//System.out.println(i);//換行
			//從堆頂進行調整,使未排序堆中最大關鍵字到堆頂
			AdjustHeap(0,i);
		}
	}
	/*
	* 調整堆使其堆頂為未排序堆中最大關鍵字
	*/
	public static void AdjustHeap(int location,int unSortlength) {
		int temp;
		int tempLoc;
		//確保左右節點存在
		if ((tempLoc = (location + 1) * 2) < unSortlength) {
			//判斷左右節點大小
			if (heap[tempLoc] >= heap[tempLoc - 1]) {
				//判斷父節點與子節點的大小,若父節點小,則與大的子節點換位
				if (heap[location] < heap[tempLoc]) {
				temp = heap[location];
				heap[location] = heap[tempLoc];
				heap[tempLoc] = temp;
				//遞歸法對換位后的子節點及其子節點進行調整
				AdjustHeap(tempLoc,unSortlength);
				}
			} else {
				//左節點大於右節點
				if (heap[location] < heap[tempLoc - 1]) {
					temp = heap[location];
					heap[location] = heap[tempLoc - 1];
					heap[tempLoc - 1] = temp;
					//遞歸法對換位后的子節點及其子節點進行調整
					AdjustHeap(tempLoc - 1,unSortlength);
				}
			}
		}
		//確保左節點存在
		else if ((tempLoc = (location + 1) * 2 - 1) < unSortlength) {
			//與左節點進行比較
			if (heap[location] < heap[tempLoc]) {
				//左子節點大於父節點,將兩者進行換位
				temp = heap[location];
				heap[location] = heap[tempLoc];
				heap[tempLoc] = temp;
				AdjustHeap(tempLoc,unSortlength);
			}
		}
	}
	
	/*
	* 創建堆(對該堆進行簡單的排序)
	*/
	public static void CreateHeap() {
		for (int i = heap.length - 1; i >= 0; i--) {
			AdjustHeap(i,heap.length);
		}
	}


}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM