桶排序-基数排序-计数基数排序--Java

  前面已经讲述了很多排序算法,但是他们的排序算法都是基于两个值之间的比较,通过决策树的方法可以证明深度为d的二叉树则最多有2^{d}个树叶。具有L片树叶的二叉树的深度至少是logL向上取整。因为N个元素的排列组合为N!。所以至少需要logN!次比较。通过推导只要是比较的算法,至少需要的时间复杂度为O(NlogN)。

  一些好的排序算法是可以达到时间复杂度是线性的,桶排序就是其中一种。比如有N个数,但是这些数的最大数不超过M。这个时候就可以定义一个含有M个元素的数组(初始值为0),然后遍历N个数,在M的相应位置进行+1的操作。然后在遍历输出M中不为0的值的位置就可以了。

程序:

public class bucketSort {
	//假设数组中的数值是不超过50的。
	public void sort(int[] nums) {
		int[] temp = new int[50];
		for(int i = 0;i<nums.length;i++) {
			temp[nums[i]]++;
		}
		int j = 0;
		for(int i = 0;i<temp.length;i++) {
			while(temp[i]>0) {
				nums[j++] = i;
				temp[i]--;
			}
		}
	}
	public static void main(String[] args) {
		bucketSort sort = new bucketSort();
		int[] nums = {5,9,7,6,48,45,32,1,7};
		sort.sort(nums);
		for(int i = 0;i<nums.length;i++) {
			System.out.print(nums[i]+",");
		}
	}

}

基数排序

基数排序也叫卡片排序,当数组中的数字较大的时候,这个时候我们就不能用桶排序了,那样会浪费太多的存储空间。但是可以利用多次的桶排序,因为每个字符都是用ASCII编码的,范围是0-256。可以利用一个位置一个位置的进行循环排序,比如共三位数,那么第一次就进行个位上数字的排序,排序后得到个位上有序的数组,然后在此基础上进行十位上数字的排序,最后进行百位数字上的排序,则最后得到的结果就是整个数组有序的排列。这样的时间复杂度为O(p(N+b))p是躺数,N是待排序元素的个数,b是桶的个数。下面以字符排序(等长的字符)为例示范:

public void characterSort(String[] arr,int length) {
		//因为字符的共256个;
		final int BUCKETS = 256;
		//桶选择用ArrayList数组
		ArrayList<String>[] buckets = new ArrayList[BUCKETS];
		//对这些桶进行初始化
		for(int i = 0;i<buckets.length;i++) {
			buckets[i] = new ArrayList<>();
		}
		
		//进行每个字符的遍历
		for(int i = length-1;i>=0;i--) {
			//每个字符串上的该字符
			for(int j = 0;j<arr.length;j++) {
				//获取该位置上字符的ASCII的值
				buckets[arr[j].charAt(i)].add(arr[j]);
			}
			int index = 0;
			//要对排序好的数组进行重新赋值
			for(ArrayList<String> temp:buckets) {
				for(String s :temp) {
					arr[index++] = s;
				}
				
				//要对这个temp进行清空
				temp.clear();
			}
		}
		
		
	}

计数基数排序

计数基数排序是基数排序的另一种实现方法,该方法避免使用了ArrayList数组。采用了对比某个元素小的值有几个的计数方式进行排序。需要一个临时数组in[],进行排序过程中排序后的数组的记录,还需要个count数组进行数值的记录,比如count[K]的代表的就是严格比K小的元素的个数。然后根据这个个数对数据进行遍历的排序。一般的,计数基数排序要比基数排序的速度要快。代码:

public void countingBucketSort(String[] arr,int length) {
		
		//单位数字的ASCII的是有256个
		final int BUCKETS = 256;
		
		//初始化计数数组
		int[] count ;
		
		//每次排序后暂存数组的顺序
		String[] in = arr;
		
		
		//进行交换的时候先暂存,因为第一次in和arr是同一个,所以不能直接对arr进行修改、
		String[] out = new String[arr.length];
		
		//进行字符的遍历
		for(int i = length-1;i>=0;i--) {
			
			
			//遍历前要对count数组初始化
			count = new int[BUCKETS+1];
			
			//进行数组字符串的遍历
			for(int j = 0;j<arr.length;j++) {
				count[in[j].charAt(i)+1]++;
			}
			
			//进行计数的统计
			
			for(int j = 1;j<=BUCKETS;j++) {
				count[j] += count[j-1];
			}
			
			//统计后就得到了字符串在改位置的顺序,只需要根据count找到自己的位置就行
			for(int j = 0;j<arr.length;j++) {
				out[count[in[j].charAt(i)]] = in[j];
				//要对位置进行+1,因为可能有重复的数值
				count[in[j].charAt(i)]++;
			}
			
			//要进行数组的变换,
			String [] tmp = in;
			//in就保持上个排序后的字符串的顺序
			in = out;
			//out就代表将要进行的
			out = tmp;
		}
		
		//如果是偶数次比较,那么此时的out的引用就是arr。奇数次要进行替换
		
		if(length% 2 == 1) {
			for(int i = 0;i<arr.length;i++) {
				arr[i] = in[i];
			}
		}
	}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值