數據結構--基數排序(桶排序)

基數排序(桶排序)

1.定義:

基數排序(radix sort)屬於“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間複雜度爲O (nlog®m),其中r爲所採取的基數,而m爲堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法(截取自百度百科)。

2.原理

/**
	 * 基數排序的思想 
	 *  首先定義10個桶  ,然後對數組中的數據進行按個位、十位、百位、千位 來分配到相應的桶中
	 *  1.比如: arr這樣一個數組數據  那麼第一輪按照每位數據的個位數進行分桶
	 *  桶的位數    0    1   2   3    4    5    6  7  8  9
	 *   數據:          32   3   54        256
	 *   					    724      16
	 *    經過第一輪排序後位:  32,3,54,724,256,16
	 *  2.  第二輪按照十位來分
  	 *	 桶的位數       0    1   2   3    4    5    6  7  8  9
  	 *    數據:  3   16  724  32       54
  	 *    							 256
  	 *    進過第二輪排序後:  3,16,724,32,54,256
  	 *   3.第三輪按照百位來分
  	 *   桶的位數       0    1   2   3    4    5    6   7    8    9
  	 *     數據:  3       256                    724
  	 *			16
  	 *			32
  	 *			54
  	 *		進過第三輪排序後:  3,16,32,54,256,724
  	 *  說明: 
  	 *  1.排序的次數按照數組中最大位數來的
  	 *  2.當位數不足時,在位數前補0
  	 *  
  	 *  需注意:
  	 *    1.定義10個桶 剛好對應0-9這個10個數字  然後每個桶需要記錄桶裏面數據的個數

3.代碼實現

下面是每一步推導的過程,結合上面的算法思想去理解就會很容易了。

	public static void radixSort(int[] arr) {
   	
   	
   	//首先需要定義桶的數量
   	int [][] msg=new int[10][arr.length];
   	//用來記錄每個桶裝了幾個數據
   	int [] backElment=new int[10];
   	for(int j=0;j<arr.length;j++) {
   		//取出個位數據
   		int temp=arr[j]/1 % 10;
   		//放到對應的桶中
   		msg[temp][backElment[temp]]=arr[j];
   		backElment[temp]++;
   	}
   	//按照這個桶的順序(一維數組的下標一次取出數據,放入到原來的數組中)
   	int index=0;
   	//遍歷每一個桶,並將桶中的數據,放到原數組中
   	for(int i=0;i<backElment.length;i++) {
   		//如果桶中有數據,則將桶中數據循環放入原數組中
   		  if(backElment[i]!=0) {
   			  //循環該桶 即第I桶(即第i個一維數組) 放入
   			  for(int k=0;k<backElment[i];k++) {
   				   arr[index++]= msg[i][k];  
   			  }
   		  }
   		  //取出數組後將該桶置爲0
   		  backElment[i]=0;
   	}
   	
   	System.out.println("第一輪排序後的結果:===>"+Arrays.toString(arr));
   	
   	
   	for(int j=0;j<arr.length;j++) {
   		//取出個位數據
   		int temp=arr[j]/10 % 10;
   		//放到對應的桶中
   		msg[temp][backElment[temp]]=arr[j];
   		backElment[temp]++;
   	}
   	//按照這個桶的順序(一維數組的下標一次取出數據,放入到原來的數組中)
   	 index=0;
   	//遍歷每一個桶,並將桶中的數據,放到原數組中
   	for(int i=0;i<backElment.length;i++) {
   		//如果桶中有數據,則將桶中數據循環放入原數組中
   		  if(backElment[i]!=0) {
   			  //循環該桶 即第I桶(即第i個一維數組) 放入
   			  for(int k=0;k<backElment[i];k++) {
   				   arr[index++]= msg[i][k];  
   			  }
   		  }
   		  backElment[i]=0;
   	}
   	System.out.println("第二輪排序後的結果:===>"+Arrays.toString(arr));
   	
   	for(int j=0;j<arr.length;j++) {
   		//取出個位數據
   		int temp=arr[j]/100 % 10;
   		//放到對應的桶中
   		msg[temp][backElment[temp]]=arr[j];
   		backElment[temp]++;
   	}
   	//按照這個桶的順序(一維數組的下標一次取出數據,放入到原來的數組中)
   	 index=0;
   	//遍歷每一個桶,並將桶中的數據,放到原數組中
   	for(int i=0;i<backElment.length;i++) {
   		//如果桶中有數據,則將桶中數據循環放入原數組中
   		  if(backElment[i]!=0) {
   			  //循環該桶 即第I桶(即第i個一維數組) 放入
   			  for(int k=0;k<backElment[i];k++) {
   				   arr[index++]= msg[i][k];  
   			  }
   		  }
   	}
   	System.out.println("第三輪排序後的結果:===>"+Arrays.toString(arr));
   	
   } 	 
最終代碼
/**
	 * 優化後的桶排序算法
	 * @param arr
	 */
	public static void radixSort2(int[] arr) {
		// 桶排序的循環次數是根據數組中最大位數的來定義
		// 1 查找到數組中最大的數據 獲取位數 我們可以吧第一位定義爲最大的數字信息
		int maxValue = arr[0];
		for (int j = 1; j < arr.length; j++) {
			if (maxValue < arr[j]) {
				maxValue = arr[j];
			}
		}
		// 得到循環的次數
		int arrCount = (maxValue + "").length();
		// 首先需要定義桶的數量
		int[][] msg = new int[10][arr.length];
		// 用來記錄每個桶裝了幾個數據
		int[] backElment = new int[10];

		for (int i = 0, j = 1; i < arrCount; i++, j *= 10) {
			for (int k = 0; k < arr.length; k++) {
				// 取出個位數據
				int temp = arr[k] / j % 10;
				// 放到對應的桶中
				msg[temp][backElment[temp]] = arr[k];
				backElment[temp]++;
			}
			// 按照這個桶的順序(一維數組的下標一次取出數據,放入到原來的數組中)
			int index = 0;
			// 遍歷每一個桶,並將桶中的數據,放到原數組中
			for (int l = 0; l < backElment.length; l++) {
				// 如果桶中有數據,則將桶中數據循環放入原數組中
				if (backElment[l] != 0) {
					// 循環該桶 即第I桶(即第i個一維數組) 放入
					for (int k = 0; k < backElment[l]; k++) {
						arr[index++] = msg[l][k];
					}
				}
				// 取出數組後將該桶置爲0
				backElment[l] = 0;
			}
			//System.out.println("第"+(i+1)+"輪排序後的結果:===>"+Arrays.toString(arr));
		}

	}

4 測試性能

public static void main(String[] args) {
		int [] arr= {54,16,32,3,256,724,1024};
		
		radixSort(arr);
		System.out.println("--------------");
	
		
		//我們用數據來測試一下基數排序(桶排序)的性能
		int []data=new int[8000000];
		for(int i=0;i<8000000;i++) {
			data[i]=(int) (Math.random()*80000);
		}
		SimpleDateFormat format=new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
		Date str01=new Date();
		System.out.println("排序前--------------"+format.format(str01));
		radixSort2(data);
		Date str02=new Date();
		System.out.println("排序後--------------"+format.format(str02));
	}

由於筆記本性能較差 ,測試8000000條數據只需要1秒鐘即可完成。當然機器性能越好,測試數據條數也可更多。
以上如有不妥,歡迎指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章