十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序(二)

简介: 十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序

2-计数排序


算法思想:

计数排序最核心的思想就是计数序列中每个元素出现的次数,我们将每个元素的数量都记录下来之后.我们就可以通过按


了解完计数排序的基本思想之后,我们就来看看看这个算法的实现步骤又是怎么样的呢?主要就是下面这几个步骤:


1.第一次遍历序列,找出序列中的最大值以及最小值,然后根据最大值MAX与最小值MIN创建一个MAX-MIN+1长度的数组.为什么创建这样长度的数组呢,因为只有创建了这样长度的数组,MIN-MAX区间内的每个元素才有对应的位置进行存放,如下图所示:


20210202110104902.png


2.第二次遍历序列,我们每次遍历一个元素都将该元素所对应的区间数组对应的位置进行+1操作,这个步骤其实就是我们计数排序的核心----计数了.遍历结束之后,区间数组中的元素值就代表相应元素出现的次数,如下图所示:


20210202110150421.png


3.最后一步就只需要按照区间数组中的次数一次将该元素打印出来即可.如下图所示:


20210202110652919.png


计数排序的基本思想基本就是这样,按照惯例,还是通过下面的图来帮助大家更好的理解计数排序的基本思想:

20210202110831365.png

20210202110850630.png


20210202110928914.png

20210202110956130.png


了解完计数排序的基本思想之后,我们还是按照惯例分析一下计数排序算法的一些特点:


-计数排序是稳定的 ,这个大家应该能很明显的看出来,因为计数排序本身并不是基于比较的算法.


-计数排序需要的额外空间比较大,这个大家很明显的看出来,并且空间浪费的情况也会比较严重,因为一旦序列中MAX与MIN的差距过大,那么需要的内存空间就会非常大.并且假如序列中的元素都是散布在一个特定的区间内,那么内存空间浪费的情况也会非常明显.


算法图解:


20210119161954380.gif


示例代码:

public static void main(String[] args) {
    int []num ={7,4,9,3,2,1,8,6,5,10};
    long startTime=System.currentTimeMillis();  
    int min=Integer.MAX_VALUE;
    int max=Integer.MIN_VALUE;
    //先找出数组中的最大值与最小值
    for(int i=0;i<num.length;i++) {
      if(num[i]<min)
        min=num[i];
      if(num[i]>max)
        max=num[i];
    }
    //创建一个长度为max-min+1长度的数组来进行计数
    int []figure=new int [max-min+1];
    for(int i=0;i<num.length;i++) {
      //计算每个数据出现的次数
      figure[num[i]-min]++;
    }
    int begin=0;
    //创建一个新的数组来存储已经排序完成的结果
    int []num1=new int [num.length];
    for(int i=0;i<figure.length;i++) {
      //循环将数据pop出来
      if(figure[i]!=0) {
        for(int j=0;j<figure[i];j++) {
          num1[begin++]=min+i;
        }
      }
    }
    System.out.println("数据范围:"+min+"~"+max);
    System.out.println("计数结果:  ");
    for(int i=0;i<num.length;i++)
      System.out.println("         "+num[i]+"出现"+figure[num[i]-min]+"次");
    System.out.print("排序结果:  ");
    for(int i=0;i<num1.length;i++)
      System.out.print(num1[i]+"   ");
    System.out.println();
    long endTime=System.currentTimeMillis(); 
    System.out.println("程序运行时间: "+(endTime-startTime)+"ms"); 
  }

20210126110413648.png

复杂度分析:


理解完计数排序的基本思想之后,我们就需要来分析一下他的时间复杂度,空间复杂度.


时间复杂度


计数排序很明显是一种通过空间来换时间的算法,因为我们可以很明显的看到计数排序需要三次遍历,两次遍历我们的原序列,第三次是遍历我们的区间数组.那么很明显时间复杂度一定是线性级别的但是因为第三次遍历的并不是我们的原序列,而是我们的区间数组,所以时间复杂度并不是我们的平常的O(n),而是应该加上我们遍历区间数组的时间,假设我们的区间数组长度为k的话,那么我们的时间复杂度就是O(n+k)


空间复杂度


上面我们已经说过了,计数排序本身就是一个通过空间来换取时间的算法,所以很明显他的空间复杂度就会很高.并且这个空间复杂度主要就取决于我们区间数组的长度,所以假设我们的区间数组长度为k的话,那么我们的空间复杂度就为O(k)


相关文章
|
2月前
|
算法 搜索推荐
数据结构与算法学习十八:堆排序
这篇文章介绍了堆排序是一种通过构建堆数据结构来实现的高效排序算法,具有平均和最坏时间复杂度为O(nlogn)的特点。
74 0
数据结构与算法学习十八:堆排序
|
2月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
28 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
2月前
|
搜索推荐 Java Go
深入了解计数排序算法
深入了解计数排序算法
35 4
|
2月前
|
算法 搜索推荐
算法之堆排序
本文介绍了堆排序算法的原理和实现,通过构建最大堆或最小堆,利用堆的性质进行高效的排序,并提供了具体的编程实现细节和示例。
24 0
算法之堆排序
|
2月前
|
搜索推荐 Java Go
深入了解基数排序算法
深入了解基数排序算法
31 3
|
2月前
|
搜索推荐 Java Go
探究桶排序算法
探究桶排序算法
24 1
|
2月前
|
算法 Java Go
深入了解堆排序算法
深入了解堆排序算法
28 1
|
2月前
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
17 0
|
4月前
|
存储 搜索推荐 算法
Python中的桶排序算法
总结而言,桶排序是一个非常高效的排序算法,尤其适用于数据分布均匀的情况。正确实现和使用桶排序可以在特定情况下获得极高的排序速度。
22 0
|
5月前
|
算法 搜索推荐 C#