在计算机科学中,排序是一门基础的算法技术,许多算法都要以此作为基础,不同的排序算法有着不同的时间开销和空间开销。排序算法有非常多种,如我们最常用的快速排序和堆排序等算法,这些算法需要对序列中的数据进行比较,因为被称为基于比较的排序

基于比较的排序算法是不能突破O(NlogN)的。简单证明如下:

N个数有N!个可能的排列情况,也就是说基于比较的排序算法的判定树有N!个叶子结点,比较次数至少为log(N!)=O(NlogN)(斯特林公式)。

非基于比较的排序,如计数排序,桶排序,和在此基础上的基数排序,则可以突破O(NlogN)时间下限。但要注意的是,非基于比较的排序算法的使用都是有条件限制的,例如元素的大小限制,相反,基于比较的排序则没有这种限制(在一定范围内)。但并非因为有条件限制就会使非基于比较的排序算法变得无用,对于特定场合有着特殊的性质数据,非基于比较的排序算法则能够非常巧妙地解决。

基于非比较的排序算法有三种,计数排序,桶排序和基数排序。

-----------------------------我是分割线-------------------------------------------------------

1. 计数排序

计数排序(Counting sort)是一种稳定的线性时间排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。

 特征:

当输入的元素是n个0到k之间的整数时,它的运行时间是Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。

由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序算法中,能够更有效的排序数据范围很大的数组。

通俗地理解,例如有10个年龄不同的人,统计出有8个人的年龄比A小,那A的年龄就排在第9位,用这个方法可以得到其他每个人的位置,也就排好了序。当然,年龄有重复时需要特殊处理(保证稳定性),这就是为什么最后要反向填充目标数组,以及将每个数字的统计减去1的原因。算法的步骤如下:

  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组 C 的第 i 项
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

java 实现:

 1 public class CountingSort {
 2     public static void main(String[] argv) {
 3         int[] A = CountingSort.countingSort(new int[]{16, 4, 10, 14, 7, 9, 3, 2, 8, 1});
 4         Utils.print(A);
 5     }
 6 
 7     public static int[] countingSort(int[] A) {
 8         int[] B = new int[A.length];
 9         // 假设A中的数据a'有,0<=a' && a' < k并且k=100
10         int k = 100;
11         countingSort(A, B, k);
12         return B;
13     }
14 
15     private static void countingSort(int[] A, int[] B, int k) {
16         int[] C = new int[k];
17         // 计数
18         for (int j = 0; j < A.length; j++) {
19             int a = A[j];
20             C[a] += 1;
21         }
22         Utils.print(C);
23         // 求计数和
24         for (int i = 1; i < k; i++) {
25             C[i] = C[i] + C[i - 1];
26         }
27         Utils.print(C);
28         // 整理
29         for (int j = A.length - 1; j >= 0; j--) {
30             int a = A[j];
31             B[C[a] - 1] = a;
32             C[a] -= 1;
33         }
34     }
35 }
36 
37 
38 //针对c数组的大小,优化过的计数排序
39 public class CountSort{
40     public static void main(String []args){
41         //排序的数组
42         int a[] = {100, 93, 97, 92, 96, 99, 92, 89, 93, 97, 90, 94, 92, 95};
43         int b[] = countSort(a);
44         for(int i : b){
45             System.out.print(i + "  ");
46         }
47         System.out.println();
48     }
49     public static int[] countSort(int []a){
50         int b[] = new int[a.length];
51         int max = a[0], min = a[0];
52         for(int i : a){
53             if(i > max){
54                 max = i;
55             }
56             if(i < min){
57                 min = i;
58             }
59         }
60         //这里k的大小是要排序的数组中,元素大小的极值差+1
61         int k = max - min + 1;
62         int c[] = new int[k];
63         for(int i = 0; i < a.length; ++i){
64             c[a[i]-min] += 1;//优化过的地方,减小了数组c的大小
65         }
66         for(int i = 1; i < c.length; ++i){
67             c[i] = c[i] + c[i-1];
68         }
69         for(int i = a.length-1; i >= 0; --i){
70             b[--c[a[i]-min]] = a[i];//按存取的方式取出c的元素
71         }
72         return b;
73     }
74 }
count sort

相关文章:

  • 2022-01-04
  • 2021-07-05
  • 2022-12-23
  • 2021-08-12
  • 2021-04-03
猜你喜欢
  • 2021-07-19
  • 2021-07-07
  • 2021-09-09
  • 2021-05-17
相关资源
相似解决方案