转载请注明原文地址: http://www.cnblogs.com/ygj0930/p/6639353.html 

比较和非比较排序

快速排序、归并排序、堆排序、冒泡排序等比较排序,每个数都必须和其他数进行比较,才能确定自己的位置。
冒泡排序之类的排序,问题规模为n,又因为需要比较n次,所以平均时间复杂度为O(n²)

归并排序、快速排序之类的排序,问题规模通过分治法削减为logN次,所以时间复杂度平均O(nlogn)
比较排序适用于各种规模的数据,也不在乎数据的分布,都能进行排序,适用于一切需要排序的情况

计数排序、基数排序、桶排序则属于非比较排序。非比较排序是通过求取每个元素前面应该有多少个元素来确定当前元素位置。针对数组arr,计算arr[i]之前有多少个元素,则唯一确定了arr[i]在排序后数组中的位置。
非比较排序只要确定每个元素之前的已有的元素个数即可,所以一次遍历即可解决。算法时间复杂度O(n)
非比较排序时间复杂度底,但由于非比较排序需要占用空间来确定唯一位置。所以对数据规模和数据分布有一定的要求

一:计数排序

作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数,并且必须是集中的数据;因为它借助一个辅助数组来排序,而辅助数组的大小是根据待排序数组的最大值来决定的。

算法思想如下:

1:首先,遍历待排序数组A[],得到A数组最大值Max,那么A数组的值必定处于0~Max之间;

2:创建辅助C[],大小为Max+1,即C数组下标范围为 0~Max,对应了待排数组的值的区间;

3:计数:统计A[]数组中每个元素出现了多少次。元素值对应C数组下标,次数对应C[A[i]]取值。

4:得出排序后A中元素值在结果数组中位置:C[]中存储了下标值对应的数据在A[]中出现的次数,那么C[i-1]+C[i]就等于A中值小于等于i的元素有多少个,也就是值为i的元素在排序后数组中的第几位。例如:A中小于等于5的数有3个,那么5就是结果数组中的第3位(因为等于啊!什么叫等于?小于等于自己的有n个,那么自己当然是等于自己的那个啊,也就是说,自己就是这n个当中的最后一个啊),由于数组下标从0开始,那么对应结果下标就是2.

代码实现如下:

  1. public class CountingSort {
  2. public int[] countingSort(int[] A, int n) {
  3. if(A==null||A.length<=0){
  4. return A;
  5. }
  6.  
  7. //找出待排序数组最大值
  8. int Max=A[0];
  9. for(int i=1;i<n;++i){
  10. Max=(Max>A[i])?Max:A[i];
  11. }
  12.  
  13. //由待排数据最大值,创建辅助数组
  14. int[] count=new int[Max+1];
  15.  
  16. //计数
  17. for(int i=0;i<n;++i){
  18. count[A[i]]++;
  19. }
  20.  
  21. //计算出值i在结果数组中的位置(第k位)
  22. for(int i=1;i<Max+1;++i){
  23. count[i]=count[i-1]+count[i];
  24. }
  25.  
  26. int[] res=new int[n];
  27. int val;
  28. int pos;
  29.  
  30. for(int i=0;i<n;++i){
  31. val=A[i];
  32.  
  33. //count[val]为val值在结果数组中的第count[val]位,由于数组下标从0开始,那么对应的下标就是count[val]-1
  34. pos=count[val]-1;
  35. //把val填到结果数组中自己的位置上
  36. res[pos]=val;
  37.  
  38. //值为val的数已经排好了一个,那么小于等于val的值就要减少一个了
  39. count[val]=count[val]-1;
  40. }
  41.  
  42. return res;
  43. }
  44. }

二:桶排序

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

算法思想如下:

1:遍历待排数组A,求出最大值Max和最小值Min,得出待排序数据区间Min~Max;

2:一个桶最大为A.length(极端情况下,数据十分集中,都进同一个桶),所以Min~Max的数据需要(Max—Min)/A.length+1(+1是为了上取整)个桶来存放;

3:遍历数组A,把A[i]放入桶中:桶是一个数据区间,区间大小为A.length,所以求A[i]属于第几个桶,只需(A[i]-min)/A.length即可。

4:A中数据全部入桶后,对每个桶(每个数据区间)进行小范围的排序

5:每个桶(区间)排好序后,从第一个桶到最后一个桶的数据排列顺序实际上就是A排好序后的结果。

代码实现如下:

  1. public class RadixSort {
  2. public int[] radixSort(int[] A, int n) {
  3. if(A==null||A.length<=0){
  4. return A;
  5. }
  6.  
  7. //求最大值最小值
  8. int Max=Integer.MIN_VALUE;
  9. int Min=Integer.MAX_VALUE;
  10. for(int i:A){
  11. if(i<Min){
  12. Min=i;
  13. }
  14. if(i>Max){
  15. Max=i;
  16. }
  17. }
  18.  
  19. //得到区间
  20. int range=Max-Min;
  21. //得到桶总数
  22. int total=range/n+1;
  23.  
  24. //创建桶数组,由于每个桶是动态添加数据的,所以使用ArrayList
  25. ArrayList<ArrayList<Integer>> buckets=new ArrayList<ArrayList<Integer>>(total);
  26. for(int i=0;i<total;++i){
  27. buckets.add(new ArrayList<Integer>());
  28. }
  29.  
  30. //遍历待排数组,计算出A[i]所处区间,然后入桶
  31. int pos;
  32. for(int i=0;i<n;++i){
  33. pos=A[i]/range;
  34. buckets.get(pos).add(A[i]);
  35. }
  36.  
  37. //对每个桶内数据进行小范围排序
  38. for(ArrayList arr:buckets){
  39. Collections.sort(arr);
  40. }
  41.  
  42. //从排序后桶数组中依次取出数据,即为排序后结果
  43. int[] res=new int[n];
  44. int index=0;
  45. for(ArrayList arr:buckets){
  46. for(Object i:arr){
  47. res[index]=(int)i;
  48. index++;
  49. }
  50. }
  51.  
  52. return res;
  53. }
  54. }

三:基数排序

基数排序已经不再是一种常规的排序方式,它更多地像一种排序方法的应用。 

基数排序的总体思路就是将待排序数据拆分成多个关键字进行排序:第1个排序关键字,第2个排序关键字,第3个排序关键字......然后,从低位到高位依据关键字对待排序数据进行排序。在前一位排序结果的基础上,依据当前位上数字进行排序......直到依据最高位进行排序,即可得到正确的拍完序结果。这里要注意,依据每一位上数字,对待排数组进行排序时,使用的是另一种排序方法,一般使用计数排序

  1. public class RadixSort {
  2. public int[] radixSort(int[] A, int n) {
  3. if(A==null||A.length<=0){
  4. return A;
  5. }
  6. //找出待排数组最大值,得到待排数据最高位
  7. Integer Max=Integer.MIN_VALUE;
  8. for(int i:A){
  9. if(i>Max){
  10. Max=i;
  11. }
  12. }
  13.  
  14. int maxindex=(Max.toString().length());
  15.  
  16. //创建一个临时数组,存放从低位到高位排序期间的临时结果
  17. int[] temp=new int[n];
  18.  
  19. //计数排序所用的计数数组
  20. int[] buckets=new int[10];
  21.  
  22. int rate=1;//从低位开始,倍数为1.后面为10,100...用于计算排序位是哪位
  23.  
  24. //从低位到高位,根据排序位值排序
  25. for(int index=1;index<=maxindex;++index)
  26. {
  27. //把上一次排序位排序后的A数组,赋值到临时数组中
  28. System.arraycopy(A,0,temp,0,n);
  29. //重置计数排序数组
  30. Arrays.fill(buckets, 0);
  31.  
  32. //遍历临时数组temp
  33. for(int j=0;j<n;++j){
  34. //计算出元素的当前排序位对应的值
  35. int subkey=(temp[j]/rate)%10;
  36. //计数
  37. buckets[subkey]++;
  38. }
  39.  
  40. //计数排序:计算排序位值小于等于l的有多少个,则buckets[l]为排序位值为l的待排数据在当前排序位排序结果中的位置(位置=下标+1)
  41. for(int l=1;l<10;++l){
  42. buckets[l]=buckets[l-1]+buckets[l];
  43. }
  44.  
  45. //进行排序位排序,遍历上一次排序结果
  46. for(int m=n-1;m>=0;--m){
  47. //计算当前元素的排序位值
  48. int subkey=(temp[m]/rate)%10;
  49. //由排序位值得到该元素在当前次排序结果中的下标
  50. int pos=buckets[subkey]-1;
  51. //根据下标,把当前元素填到合适位置
  52. A[pos]=temp[m];
  53. //因为取了一个出来,所以计数数组对应值减一
  54. buckets[subkey]--;
  55. }
  56. //每排完一位后,往更高一位进行排序
  57. rate*=10;
  58. }
  59. return A;
  60. }
  61. }

本次做题偶得:

1:数组越界问题,用IDE或者java命令运行程序,看异常提示,找到出错的行,然后在前面添加Sys.out.println()语句打印相关变量值,看是哪个数据造成的越界,为何越界。对症修改。

2:求一个数的长度,无需用位运算、循环除以10等,只需借助String对象的length()即可:

       Integer number;

       int maxindex=(number.toString().length());

 

排序基础之非比较的计数排序、桶排序、基数排序(Java实现)的更多相关文章

  1. java-数组排序--计数排序、桶排序、基数排序

    计数排序引入 不难发现不论是冒泡排序还是插入排序,其排序方法都是通过对每一个数进行两两比较进行排序的,这种方法称为比较排序,实际上对每个数的两两比较严重影响了其效率,理论上比较排序时间复杂度的最低下限 ...

  2. 计数排序与桶排序python实现

    计数排序与桶排序python实现 计数排序 计数排序原理: 找到给定序列的最小值与最大值 创建一个长度为最大值-最小值+1的数组,初始化都为0 然后遍历原序列,并为数组中索引为当前值-最小值的值+1 ...

  3. 计数排序、桶排序python实现

    计数排序在输入n个0到k之间的整数时,时间复杂度最好情况下为O(n+k),最坏情况下为O(n+k),平均情况为O(n+k),空间复杂度为O(n+k),计数排序是稳定的排序. 桶排序在输入N个数据有M个 ...

  4. go实现堆排序、快速排序、桶排序算法

    一. 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法.以大堆为例利用堆顶记录的是最大关键字这一特性,每一轮取堆顶元素放入有序区,就类似选择排序每一轮选择一个最大值放入有序区,可以把堆排序看成是 ...

  5. Java实现桶排序和基数排序

    桶排序代码: import java.util.Arrays; /** * 桶排序 * 工作的原理是将数组分到有限数量的桶里 * 每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序 ...

  6. 【算法】桶排序(Bucket Sort)(九)

    桶排序(Bucket Sort) 桶排序是计数排序的升级版.它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定.桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将 ...

  7. 线性时间的排序算法--桶排序(以leetcode164. Maximum Gap为例讲解)

    前言 在比较排序的算法中,快速排序的性能最佳,时间复杂度是O(N*logN).因此,在使用比较排序时,时间复杂度的下限就是O(N*logN).而桶排序的时间复杂度是O(N+C),因为它的实现并不是基于 ...

  8. Bucket Sort - leetcode [桶排序]

    桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里.每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序).桶排序是鸽巢排序 ...

  9. java,桶排序,冒泡排序,快速排序

    1.桶排序: 百度百科:桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里.每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排 ...

随机推荐

  1. JavaScript中 location.host 与 location.hostname 的区别

    JavaScript 中,大多数情况下,我们不会发现 location.host 与 location.hostname 的区别,因为大多数情况下,我们的网页用的是 80 端口. 他们的区别: loc ...

  2. Error:Program type already present: android.arch.lifecycle.LiveData

    Apparently, this is intended behavior: com.firebaseui:firebase-ui-firestore:3.1.0 depends on android ...

  3. 【电信我想问一下,网页上多出的隐藏广告】究竟谁在耍流氓,还要不要脸了??? 0817tt 植入广告

    最近总是有网页 莫名的有声音,是网页游戏的,一刷新就没了. 这次 我怒了! 我觉得不可能是这个网站的chinaunix的广告.左边是 有广告的,右侧标签 是无广告的. 有广告的 实际上 隐藏了一个页面 ...

  4. pchar,pwidechar,pansichar作为返回参数时内存访问错误

    function Test:pachr: var   str: string; begin   str := 'Test Char';   result:=pchar(str); end; 上面的Te ...

  5. ORM数据库框架 SQLite ORMLite MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. Neo4j 2.0 生产环境集群搭建

    一.在windows上搭建Neo4j ha cluster的配置方法: 例如:建立集群的三台机器的ip分别为:10.230.9.91,10.230.9.92,10.230.9.93. 10.230.9 ...

  7. 使用 CSS 接收用户的点击事情并对相关节点进行操作

    问题背景:使用纯 CSS 方案,实现导航栏tab切换 实现 Tab 切换的难点在于如何使用 CSS 接收到用户的点击事情并对相关的节点进行操作.即是: 如何接收点击事件 如何操作相关DOM 下面看看如 ...

  8. 【Spark】SparkStreaming-如何使用checkpoint

    SparkStreaming-如何使用checkpoint sparkstreaming checkpoint 默认_百度搜索 spark streaming中使用checkpoint - HarkL ...

  9. apache 错误:The system cannot find the file specified.

    在启动apache时出现了以下错误信息 Window日志里也记录了此错误信息   而出现此错误的原因是IIS占用了80端口 停止IIS再重新启动apache即可解决   参考: cannot find ...

  10. 【矩阵乘】【DP】【codevs 1305】Freda的道路

    1305 Freda的道路 时间限制: 1 s 空间限制: 128000 KB 题目等级: 大师 Master 题目描写叙述 Description Freda要到Rainbow的城堡去玩了. 我们能 ...