• 数据结构与算法之非比较排序【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、分析

    桶排序可用于最大最小值相差较大的数据情况,。
    但桶排序要求数据的分布必须均匀,否则可能导致数据都集中到一个桶中,导致桶排序失效。
  • 相关阅读:
    转:Web Service介绍
    CodeIgniter网页缓存
    CodeIgniter管理你的应用程序
    CodeIgniter自动装载资源
    python feedparser 使用
    HTC文件的使用
    动态执行javascript代码
    jQuery获取文本节点之text()/val()/html() 方法区别
    style,runtimeStyle与currentStyle的定义及用法
    File,FileStream,byte[]3者互相转换总结(转)
  • 原文地址:https://www.cnblogs.com/Demrystv/p/9022204.html
Copyright © 2020-2023  润新知