在此之前,算法导论中讲到的排序都是比较排序——通过元素之间的比较来确定某个元素的位置。书中先是证明了比较排序的下限运行时间是O(nlgn),接下来,介绍了几个不通过比较来排序的算法:计数排序,基数排序,桶排序。当然在这些算法的实现中,有的还是用到了比较排序作为中间过程的。
计数排序:计数排序的思想是,对于一个数组中的元素,排序之后,它的位置应该与数组中小于或等于它的元素的个数相关。因此,对于每一个元素,算法先是计算出数组中小于或等于它的元素个数count,并用一个数组将这个count保存起来。然后再根据这些信息确定每个元素的最终位置。这样,数组就完成了排序。
大致的过程就是这样,很简单,当然,怎么计算这个count,可能也有很多不同的方法,下面给出一种实现。
package com.zy.sortalgorithms; public class CountingSort implements SortAlgorithm{ private int[] destArray; //将排序后的数据存储在这个数组中,然后再复制到a。 private int[] tempArray; //临时数组,用来保存 数组a中 元素的值小于等于下标i 的元素的个数 @Override public void sort(int[] a) { // TODO Auto-generated method stub countintSort(a); } //执行计数排序 private void countintSort(int[] a) { initArrays(a); //初始化两个辅助用的数组 for(int i=0; i<tempArray.length; i++) { tempArray[i] = 0; } //首先,让tempArray[i]中存放 数组a中 元素的值等于下标i 的元素的个数。 for(int i=0; i<a.length; i++) { int x = a[i]; tempArray[x]++; } //再次,让tempArray[i]中存放 数组a中 元素的值小于等于下标i 的元素的个数 for(int i=1; i<tempArray.length; i++) { tempArray[i] = tempArray[i]+tempArray[i-1]; } //对于数组a中的每个元素a[i],排序后它所在的位置下标 应该等于 a中小于等于它 的元素的个数count, //而这个个数count就存放在tempArray[a[i]]中。 for(int i=a.length-1; i>=0; i--) { int x = a[i]; int count = tempArray[x]; destArray[count-1] = x; tempArray[x]--; } for(int i=0; i<a.length; i++) { a[i] = destArray[i]; } } //初始化两个辅助用的数组destArray和tempArray private void initArrays(int[] a) { // TODO Auto-generated method stub int len = a.length; destArray = new int[len]; //取得待排序数组中元素的最大值。 int max = a[0]; for(int i=1; i<len; i++) { if(max<a[i]) { max = a[i]; } } //创建暂存数据用的临时数组,其元素个数为前面求得的max tempArray = new int[max+1]; } }
书中之后讲解了基数排序和桶排序,都比较简单,但是实现起来还是比较麻烦的,所以就没有去试。