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

}

基数排序结果:

  

 

posted @ 2019-01-17 18:32  |旧市拾荒|  阅读(1293)  评论(0编辑  收藏  举报