数据结构与算法之非比较排序【Java】

比较排序与非比较排序的对比

  常见的快速排序、归并排序、堆排序、冒泡排序等属于比较排序。在排序的最终结果里,元素之间的次序依赖于它们之间的比较。每个数都必须和其他数进行比较,才能确定自己的位置。在冒泡排序之类的排序中,问题规模为n,又因为需要比较n次,所以平均时间复杂度为O(n²)。在归并排序、快速排序之类的排序中,问题规模通过分治法消减为logN次,所以时间复杂度平均O(nlogn)。比较排序的优势是,适用于各种规模的数据,也不在乎数据的分布,都能进行排序。可以说,比较排序适用于一切需要排序的情况。

计数排序、基数排序、桶排序则属于非比较排序。非比较排序是通过确定每个元素之前,应该有多少个元素来排序。针对数组arr,计算arr[i]之前有多少个元素,则唯一确定了arr[i]在排序后数组中的位置。

  非比较排序只要确定每个元素之前的已有的元素个数即可,所有一次遍历即可解决。算法时间复杂度O(n)。非比较排序时间复杂度底,但由于非比较排序需要占用空间来确定唯一位置。所以对数据规模和数据分布有一定的要求。

 

非比较排序

常见的比较排序主要有以下几种:基数排序、计数排序、桶排序。

基数排序

1、基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

2、算法实现

 1 package com.allSorts;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 /**
 7  * Created by Demrystv.
 8  */
 9 public class Ji1Shu {
10     public static void main(String[] args) {
11         int[] a = {23,45,67,88,90,21,42,52,73,61};
12         System.out.println("排序前:");
13         for(int i=0;i<a.length;i++){
14             System.out.print(a[i]+" ");
15         }
16 
17         //基数排序
18         sort(a);
19 
20         System.out.println("");
21         System.out.println("排序后:");
22         for(int i=0;i<a.length;i++){
23             System.out.print(a[i]+" ");
24         }
25     }
26 
27     private static void sort(int[] a){
28 
29         //找到最大值,看最大值有几位,从而确定要比较几次,个十百千万。。。
30         int max = 0;
31         for(int i=0;i<a.length;i++){
32             if(max<a[i]){
33                 max = a[i];
34             }
35         }
36 
37         //找到最大值后,确定要比较几次
38         int times = 0;
39         while (max>0){
40             max = max/10;
41             times++;
42         }
43 
44         //建立从0到9十个队列
45         List<ArrayList> list1 = new ArrayList<>();
46         for(int i=0;i<10;i++){
47             ArrayList list2 = new ArrayList();
48             list1.add(list2);
49         }
50 
51         //进行times次分配和收集,不断的重复即可。
52         for(int i=0;i<times;i++){
53 
54             //分配,按照比较的所在的位的大小将其放入list1 中,类似于数组链表中的链表
55             for(int j=0;j<a.length;j++){
56                 int x = a[j] % (int)Math.pow(10,i+1) / (int)Math.pow(10,i);
57                 ArrayList list3 = list1.get(x);
58                 list3.add(a[j]);
59                 list1.set(x,list3);
60             }
61 
62             //收集,然后以此从数组的从左到右,链表的从上到下进行收集,将其重新放进一个新的数组中
63             int count = 0 ;
64             for(int j=0;j<10;j++){
65                 while (list1.get(j).size()>0){
66                     ArrayList<Integer> list4 = list1.get(j);
67                     a[count] = list4.get(0);
68                     list4.remove(0);
69                     count++;
70                 }
71             }
72         }
73 
74 
75     }
76 }

3、分析

  基数排序是稳定的排序算法。

  基数排序的时间复杂度为O(k*n),空间复杂度为O(m),k为数组中数值的最大位数,m为桶的的个数。

计数排序

1、基本思想是:对每一个输入的元素arr[i],确定小于 arr[i] 的元素个数,可以直接把 arr[i] 放到它输出数组中的位置上。假设有x个数小于 arr[i],所以 arr[i] 应该放在数组的第(x+1)个位置上。
2、算法实现
 1 package com.allSorts;
 2 
 3 /**
 4  * Created by Demrystv.
 5  */
 6 public class Ji4Shu {
 7     public static void main(String[] args) {
 8         int[] a = {23,42,53,64,63,32,13,52,97,94,26};
 9         System.out.println("排序前:");
10         for(int i=0;i<a.length;i++){
11             System.out.print(a[i]+" ");
12         }
13 
14         //计数排序
15         sort(a);
16 
17         System.out.println("");
18         System.out.println("排序后:");
19         for(int i=0;i<a.length;i++){
20             System.out.print(a[i]+" ");
21         }
22     }
23 
24     private static void sort(int[] a){
25 
26         if(a==null || a.length==0){
27             return;
28         }
29 
30         int max=0,min=0;
31         for(int i=0;i<a.length;i++){
32             max = Math.max(max,a[i]);
33             min = Math.min(min,a[i]);
34         }
35 
36         int[] help = new int[max-min+1];
37         int pos;
38 
39         for(int i=0;i<a.length;i++){
40             pos = a[i]-min;
41             help[pos]++;
42         }
43 
44         int index=0;
45         for(int i=0;i<help.length;i++){
46             while (help[i]>0){
47                 a[index] = i + min;
48                 index++;
49                 help[i]--;
50             }
51         }
52     }
53 }

3、分析

  计数排序是稳定的排序算法。

  计数排序的时间复杂度为O(k+n),空间复杂度为O(m),k为数组中最大数与最小数差值,m为桶的的个数。

桶排序

1、基本思想是把数组 arr 划分为n个大小相同子区间(桶),每个子区间各自排序,最后合并。计数排序是桶排序的一种特殊情况,可以把计数排序当成每个桶里只有一个元素的情况。
2、算法实现
 1 package com.allSorts;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collections;
 5 
 6 /**
 7  * Created by Demrystv.
 8  */
 9 public class Tong {
10     public static void main(String[] args) {
11         int[] a = {32,45,42,51,53,86,95,53,93,55,59};
12         System.out.println("排序前:");
13         for(int i=0;i<a.length;i++){
14             System.out.print(a[i]+" ");
15         }
16 
17         //桶排序
18         sort(a);
19 
20         System.out.println("");
21         System.out.println("排序后:");
22         for(int i=0;i<a.length;i++){
23             System.out.print(a[i]+" ");
24         }
25     }
26 
27     private static void sort(int[] a){
28 
29         if(a==null || a.length==0){
30             return;
31         }
32 
33         int max=0,min=0;
34         for(int i=0;i<a.length;i++){
35             max = Math.max(max,a[i]);
36             min = Math.min(min,a[i]);
37         }
38 
39         //确定桶数,并且建立一系列的桶
40         int bucketNum = (max-min)/a.length+1;
41         ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
42         for (int i=0;i<bucketNum;i++){
43             bucketArr.add(new ArrayList<Integer>());
44         }
45 
46         //将每个元素放入桶
47         for(int i=0;i<a.length;i++){
48             int num = (a[i]-min)/a.length;
49             bucketArr.get(num).add(a[i]);
50         }
51 
52         //对每个桶进行排序
53         for(int i=0;i<bucketArr.size();i++){
54             Collections.sort(bucketArr.get(i));
55         }
56 
57         int index = 0;
58         for(int i=0;i<bucketArr.size();i++){
59             while (bucketArr.get(i).size()>0){
60                 a[index++] = bucketArr.get(i).get(0);
61                 bucketArr.get(i).remove(0);
62             }
63         }
64     }
65 }

3、分析

桶排序可用于最大最小值相差较大的数据情况,。
但桶排序要求数据的分布必须均匀,否则可能导致数据都集中到一个桶中,导致桶排序失效。

猜你喜欢

转载自www.cnblogs.com/Demrystv/p/9022204.html