美文网首页程序员
灵光一闪的排序算法与靠谱的计数排序

灵光一闪的排序算法与靠谱的计数排序

作者: 扈扈哈嘿 | 来源:发表于2017-01-11 17:27 被阅读147次

自己闲来没事乱写的排序算法

假设我们有正要待排序的数组A,它的区间是[0,k],0~k均是有限大小的整数。接下来我们初始化一个k+1长度的数据B,并把它所有的值都初始化为-1(只因为它是负数,可以用来区别将要进行排序的数据,因为要排序的数据都>=0)。
那我们现在就有两个数组了。假设A数组的值是{5,0,2,3,1}:

1.最开始初始化
原谅我自己手画的,工作时间挤出来,见谅见谅。

因为A数组中最大的为5,那B数组中数组长度为(5+1),为6,初始化之后B数组的初始值为-1。
接下来就是给B数组赋值了。我们把A数组中的值对应B数组的下标,把A数组中的下标对应B数组的值,比如:A[0]=5->B[5]=0,A[1]=0->B[0]=1;这样我们就可根据B数组知道:A中的5存储在下标为0,也就是第一个位置上,A中的0保存在下标为1也就是第二个位置上。这样操作了之后如下图:

经过上诉操作之后B数组的值

从B数组我们也就知道了A数组中的信息。第三步,我们需要一个新的数组C,用来保存A数组中的信息。
如下:

C数组与A数组保存数据一致

这个C数组会在接下来说明。接下来我们我们将一个一个的从B数组中取出数据用来当C数组的下标取出重新赋值给A数组。按前面的我们知道,从B数组我们知道,A数组中最小的是下标为1的位置。接下来是下标为4的位置,最大的数据在下标为0 的位置。处理之后,A数组就变成了:

最终结果

java实现代码:

public void sort(int[] aDatas) { 
   //根据A数组中的最大值得到B数组中长度 
 int bDataLength = getMaxNum(aDatas)+1; 
   //得到A与C数组的长度   
 int cLength = aDatas.length;   
 //接下来初始化C数组  
 int[] cDatas = new int[cLength];  
 for (int i = 0; i < cLength; i++) {   
     cDatas[i] = aDatas[i];   
 }  
  //接下来处理B数组中的值  
 int[] bDatas = new int[bDataLength];   
 for (int i = 0; i < bDataLength; i++) {     
   bDatas[i] = -1;   
 }  
  //根据A数组赋值给B数组  
 for (int i = 0; i < cLength; i++) {    
    bDatas[aDatas[i]] = i;    }    
//用于记录A数组中的有效位置   
 int numberLeng = 0;   
 //进行大小位置正确放置  
  for (int i = 0; i < bDataLength; i++) {  
  if (bDatas[i] != -1) {     
  int index = bDatas[i];    
  int temp = cDatas[index];   
 aDatas[numberLeng] = temp;        
 numberLeng++;  
     }   
 }
}


public int getMaxNum(int[] datas) { 
   int max = 0;   
 int length = datas.length;  
  for (int i = 0; i < length; i++) {   
     if (datas[i] > max) {     
       max = datas[i];    
    } 
   }    
return max ;
}
public static void main(String[] args) {  
  int[] datas = new int[]{5,0,2,3,1};  
  new BucketSort().sort(datas);  
  for (int i = 0; i < datas.length; i++) {  
      System.out.println(datas[i]); 
   }}

来看看结果

0
1
2
3
5

然后觉得不对,我这样写如果有重复的元素,肯定排序就不正确。当然可以再用一个数组D来记录下重复的元素。可是这样就太麻烦了,太复杂了,并且要排序的数据不要太大,要不然B数组太大,效率也不高。后来回家翻了下算法导论发现计数排序和我这个非常相似。书是好东西,得经常翻翻。


计数排序

现在可以进入正题了。
应该都知道冒泡排序,快速排序,选择排序等等都是通过比较两个数据大小来进行排序的。而它们的时间复杂度以及稳定性如下 :


计数排序是时间效率为O(n)的计数排序所谓排序算法,无非就是把正确的元素放到正确的位置,计数排序就是计算相同key的元素各有多少个,然后根据出现的次数累加而获得最终的位置信息。但是计数排序有两个限制条件,那就是存在一个正整数K,使得数组里面的所有元素的key值都不大于N,且key值都是非负整数。
计数排序算法步骤大概有三个步骤:
  • 建一个长度为K+1的的数组B,里面的每一个元素初始都置为0(Java里面默认就是0)。我自己写的是将B数组初始化为一个固定负数,如-1
  • 遍历待排序的数组,计算其中的每一个元素出现的次数,比如一个key为i的元素出现了3次,那么C[i]=3。这里是记录元素出现的次数,我只是记录下标,所以我不能处理重复数据,而计数法可以
  • 累加B数组,获得元素的排位,从0开始遍历B, B[i+1]=B[i]+B[i-1]
  • 建一个临时数组C,长度与待排序数组一样。从数组末尾遍历待排序数组,把元素都安排到C里面,直接从B里面就可以得到元素的具体位置, 不过记得每处理过一个元素之后都要把B里面对应位置的计数减1。为什么要从末尾开始遍历呢,是为保证排序算法的稳定性。
    现在又用的我手工图给大家讲解一下:

1.假设A数组内容为{5,0,2,3,2}这里我故意加了个重复元素

A与B初始化

2.在A的值对应B的下标加1

对B进行赋值

上图B数组中表示A中0有一个,1有0个,2有两个,3有一个,4有零个,5有一个。

  1. B[i]=B[i]+B[i-1]
B数组最终的样子

4.新建一个数组C与A有相同的值,从数组末尾遍历A数组,直接从B里面就可以得到元素的具体位置, 不过记得每处理过一个元素之后都要把B里面对应位置的计数减1。
这里图显示一下前两次循环的结果:

前两次循环排序结果

下面是java的实现代码:

public static void countSort(int[] aDatas) throws Exception { 
   if (aDatas.length <= 1) { 
       return; 
   }   
 int range = getMaxNum(aDatas);
int[] bDatas = new int[range + 1];  
  for (int i = 0; i < aDatas.length; i++) {   
   int value = aDatas[i];     
   bDatas[value] += 1;  
  }   
 for (int i = 1; i < bDatas.length; i++) {     
  bDatas[i] += bDatas[i - 1];  
  }   
 int[] cDatas = new int[aDatas.length];   
 for (int i = aDatas.length - 1; i >= 0; i--) {    
 int value = aDatas[i];    
  int position = bDatas[value] - 1;      
  cDatas[position] = value;      
  bDatas[value] -= 1; 
   }    
for (int i = 0; i < aDatas.length; i++) {  
      aDatas[i] = cDatas[i]; 
   }
}
public static int getMaxNum(int[] datas) { 
   int max = 0; 
   int length = datas.length; 
   for (int i = 0; i < length; i++) {   
     if (datas[i] > max) {    
        max = datas[i];   
     }   
 }   
 return max;}
public static void main(String[] args) throws Exception {
 int[] array = {5, 0, 2, 3, 2};   
countSort(array);   
 for (int i = 0; i < array.length; i++) {     
   System.out.println(array[i]); 
   }}
0
2
2
3
5

有种在以前上学时打草稿的感觉。

相关文章

  • 灵光一闪的排序算法与靠谱的计数排序

    自己闲来没事乱写的排序算法 假设我们有正要待排序的数组A,它的区间是[0,k],0~k均是有限大小的整数。接下来我...

  • (转)排序算法

    排序算法点这里 数据结构与算法——计数排序、桶排序、基数排序

  • 线性排序

    桶排序、计数排序、基数排序 一、线性排序算法介绍 1.线性排序算法包括桶排序、计数排序、基数排序。2.线性排序算法...

  • 排序算法-8---计数排序

    # 排序算法-8---计数排序 概念 计数排序(Counting sort)是一种稳定的线性时间排序算法。该算法于...

  • 算法and数据结构

    算法 冒泡排序 选择排序 计数排序

  • 数据结构与算法——计数排序、桶排序、基数排序

    数据结构与算法——计数排序、桶排序、基数排序 计数排序 计数排序有如下四个步骤。 首先会对每个输入进行频率统计,得...

  • 排序算法

    常见排序算法 本文涉及的算法有:冒泡排序选择排序计数排序 冒泡排序 伪代码 流程图 选择排序 伪代码 流程图 计数...

  • 08-计数排序(Counting Sort)

    计数排序(Counting Sort) 本节内容,继续介绍排序算法,在本节内容之前,介绍过7种排序算法,那计数排序...

  • LeetCode大全

    1.常见排序算法: 常见的排序算法:冒泡排序、选择排序、插入排序、归并排序、快速排序、希尔排序、堆排序、计数排序、...

  • Python实现计数排序

    计数排序 计数排序是一个非基于比较的排序算法,优势在于在对一定范围内的整数排序时,快于基于比较的排序算法。 算法思...

网友评论

    本文标题:灵光一闪的排序算法与靠谱的计数排序

    本文链接:https://www.haomeiwen.com/subject/extrbttx.html