Java實現桶排序和基數排序


桶排序代碼:

import java.util.Arrays;

/**
 * 桶排序
 * 工作的原理是將數組分到有限數量的桶里
 * 每個桶再分別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排序)
 * 桶排序是鴿巢排序的一種歸納結果。當要被排序的數組內的數值是均勻分配的時候,桶排序使用線性時間O(N)
 * 但桶排序並不是比較排序,它不受到O(n log n) 下限的影響
 * 
 * 時間復雜度: O(N+C),其中C=N*(logN-logM)<br />
 * 空間復雜度:N+M,M為桶的個數<br />
 * 非原址排序<br />
 * 穩定性:穩定<br />
 *
 * 桶排序假設數據會均勻入桶,在這個前提下,桶排序很快!
 */
public class BucketSort {
	
	// 根據桶的個數來確定hash函數,這份代碼適合桶的個數等於數組長度
	static int hash(int element,int max,int length){
		return (element * length)/(max+1);
	}
	
	private static void sort(int[] arr) {
		int length = arr.length;
		LinkedNode[] bucket = new LinkedNode[length];  // 桶的個數等於length
		int max = arr[0];  // 求max
		for (int i = 1; i < arr.length; i++) {
			if (arr[i]>max) {
				max = arr[i];
			}
		}
		// 入桶
		for (int i = 0; i < length; i++) {
			int value = arr[i];  // 掃描每個元素
			int hash = hash(arr[i], max, length);  // 桶的下標
			if (bucket[hash]==null) {
				bucket[hash] = new LinkedNode(value);  // 初始化鏈表
			}else {
				insertInto(value,bucket[hash],bucket,hash);  // 插入鏈表
			}
		}
		int k = 0; // 記錄數組下標
		// 出桶,回填arr
		for(LinkedNode node:bucket){
			if (node!=null) {
				while(node!=null){
					arr[k++] = node.value;
					node = node.next;
				}
			}
		}
	}
	
	private static void insertInto(int value, LinkedNode head, LinkedNode[] bucket, int hash) {
		LinkedNode newNode = new LinkedNode(value); 
		// 小於頭節點,放在頭上
		if (value<=head.value) {
			newNode.next = head;
			// 替換頭節點
			bucket[hash] = newNode;
			return ;
		}
		// 往后找第一個比當前值大的節點,放在這個節點的前面
		LinkedNode p = head;
		LinkedNode pre = p;
		while(p!=null&&value>p.value){
			pre = p;
			p = p.next;
		}
		if (p == null) {  // 跑到末尾了
			pre.next = newNode;
		}else { 			// 插入pre和p之間
			pre.next = newNode;
			newNode.next = p;
		}
	}

	public static void main(String[] args) {
		int arr[] = new int[10];
		for(int i=0;i<10;i++){
			arr[i] = (int) ((Math.random()+1)*10);
		}
		System.out.println("排序前:"+Arrays.toString(arr));
		sort(arr);
		System.out.println("排序后:"+Arrays.toString(arr));
	}
}

/**
 * 簡單單向鏈表的節點
 *
 */
class LinkedNode {

	public int value;
	public LinkedNode next;
	
	public LinkedNode(int value) {
		this.value = value;
	}

}

桶排序結果:

  

基數排序代碼:

import java.util.ArrayList;
import java.util.Arrays;

/**
 * 思路:初始化0-9號十個桶,按個位數字,將關鍵字入桶,入完后,依次遍歷10個桶,按檢出順序回填到數組中
 * 		然后取十位數字將關鍵字入桶,入完后,依次遍歷10個桶,按檢出順序回填到數組中,假如數組中最大的數為三位數,
 * 		那么再將百位數字作關鍵字入桶,這樣就能實現基數排序了
 * 時間復雜度: 假設最大的數有k位,就要進行k次入桶和回填,每次入桶和回填是線性的,所以整體復雜度為kN,
 * 其中k為最大數的10進制位數
 * 空間復雜度:桶是10個,10個桶里面存n個元素,這些空間都是額外開辟的,所以額外的空間是N+k,k是進制
 * 非原址排序
 * 穩定性:假設有相等的元素,它們會次第入桶,次第回數組,不會交叉,所以是穩定的<br />
 */
public class RadixSort {
	// 10個桶,每個桶裝的數個數不定,適合用數組加ArrayList
	private static ArrayList[] bucket = new ArrayList[10];
	
	// 初始化桶
	static{
		for (int i = 0; i < bucket.length; i++) {
			bucket[i] = new ArrayList();
		}
	}
	
	/**
	 * 將數組arr,按d這個位來分配和收集
	 * 
	 * @param arr
	 * @param d
	 *            位數
	 */
	private static void sort(int[] arr, int d) {
		// 全部入桶
		for (int i = 0; i < arr.length; i++) {
			putInBucket(arr[i], getDigitOn(arr[i], d));
		}

		/*---每個桶中的元素依次壓入原數組---*/
		int k = 0;
		for (int j = 0; j < bucket.length; j++) {// 每個桶
			for (Object m : bucket[j]) {
				arr[k++] = (Integer) m;
			}
		}

		// 記得清空
		clearAll();
	}

	private static void putInBucket(int data, int digitOn) {
		switch (digitOn) {
		case 0:bucket[0].add(data);	break;
		case 1:bucket[1].add(data);	break;
		case 2:bucket[2].add(data);	break;
		case 3:bucket[3].add(data);	break;
		case 4:bucket[4].add(data);	break;
		case 5:bucket[5].add(data);	break;
		case 6:bucket[6].add(data);	break;
		case 7:bucket[7].add(data);	break;
		case 8:bucket[8].add(data);	break;
		default:bucket[9].add(data);break;
		}
	}

	private static void clearAll() {
		// 對每個桶調用clear方法進行情況
		for (ArrayList b : bucket) {
			b.clear();
		}
	}

	public static void sort(int[] arr) {
		int d = 1;// 入桶依據的位初始化為1
		int max = arr[0];
		for (int i = 1; i < arr.length; i++) {
			if (arr[i] > max) {
				max = arr[i];
			}
		} // 最大值

		int dNum = 1;// 最大數據的位數
		while (max / 10 != 0) {
			dNum++;
			max /= 10;
		}

		while (d <= dNum) {
			// 依據第二個參數入桶和出桶
			sort(arr, d++);
		}
	}

	public static int getDigitOn(int src, int d) {
		return src / (int) (Math.pow(10, d - 1)) % 10;
	}
	public static void main(String[] args) {
		int arr[] = new int[10];
		for(int i=0;i<10;i++){
			arr[i] = (int) ((Math.random()+1)*10);
		}
		System.out.println("排序前:"+Arrays.toString(arr));
		sort(arr);
		System.out.println("排序后:"+Arrays.toString(arr));
	}

}

基數排序結果:

  

 


免責聲明!

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



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