经典算法之计数排序

本文转自:http://blog.csdn.net/SunnyYoona/article/details/24551123

一 引言

计数排序假设n个输入元素中的每一个都是介于0-k的整数,此处k为某个整数。当k等于O(n)时,计数排序的运行时间为Θ(n)。


二 基本思想

计数排序的基本思想就是对每一个输入元素x,确定小于x的元素个数。因此我们就可以直接把x放到最终输出数组中的相应位置上。

例如:

如果有17个元素小于x,则x就位于第18个输出的位置上。当然有几个元素相同时,这个方法就略微改进一下,因为不能将它们放在同一个位置上。


三 具体实现

假定输入数组为A[1..n],他们的值均位于0~k之间,输出排序之后的数组为B[1..n],以及临时存储数组C[0..k]。计数排序的伪代码如下:

上图显示出了计数排序的运行过程。

在第1~2行中的for循环初始化操作之后,在第3~4行检查输入的每一个元素。如果输入元素的值为i,即增加C[i]的值。C[i]记录了值为i的元素个数。

于是,在第4行之后C[i]中存放了等于i的元素的个数。在第6~7行中,通过数组C中记录计数和,可以确定对每一个i=0,1,2.....,k,有多少输入元素是小于等于i的。

最后,在第9~11行中的for循环部分,把每一个元素A[j]放在输出数组B中与其相应的最终位置上。如果每一个元素都不相同,则当第一次执行第9行时,对每一个A[j],值C[A[j]]即为A[j]在输出数组上的最终位置上,因为共有C[A[j]]个元素小于等于A[j]。

可是由于各个元素可能不一定是不同的,因此,每当将一个值A[j]放入数组B中时,都要减小C[A[j]]额值。这会使得下一个值等于A[j]的输入元素直接进入输出数组B中A[j]的前一个位置。


四 代码

/*********************************
*   日期:2014-04-26
*   作者:SJF0115
*   题目: 计数排序
**********************************/
#include <iostream>
#include <stdio.h>
using namespace std;

void COUNTINGSORT(int *A,int *B,int len,int k){
    if(A == NULL || k <= 0 || len <= 0){
        return;
    }
    int C[k+1],i;
    //初始化
    for(i = 0;i <= k;i++){
        C[i] = 0;
    }
    //统计值为A[i]的个数,C[i]是等于i的元素个数
    for(i = 0;i < len;i++){
        C[A[i]] ++;
    }
    //确定值A[i]在最终输出数组B中位置,C[i]是小于等于i的元素个数
    for(i = 1;i <= k;i++){
        C[i] += C[i-1];
    }
    //输出到数组B中
    for(i = len-1;i >= 0;i--){
        //index元素A[i]在数组B中的下标
        int index = C[A[i]];
        B[index] = A[i];
        //如果有相同值元素的情况
        C[A[i]] --;
    }
    //B下标从1开始
}

int main(){
    int A[8] = {2,5,3,0,2,3,0,3};
    int B[9];
    COUNTINGSORT(A,B,8,5);
    for(int i = 1;i <= 8;i++){
        printf("%d\n",B[i]);
    }
    return 0;
}

五 时间复杂度分析

时间复杂度是多少呢?

第1~2行for循环所花时间为Θ(k)。

第3~4行for循环所花时间为Θ(n)。

第6~7行for循环所花时间为Θ(k)。

第9~11行for循环所花时间为Θ(n)。

这样总的时间就是Θ(k+n)。在实践中,档k = O(n)时,我们常采用计数排序,这时运行时间为Θ(n)。


六 特点

1.  提前必须是已知待排序的关键字为整型且范围已知。

2.  时间复杂度为O(n+k),不是基于比较的排序算法,因此效率非常之高。

3.  稳定性好,这个是计数排序非常重要的特性,可以用在后面介绍的基数排序中。

4.  但需要一些辅助数组,如C[0..k],因此待排序的关键字范围0~k不宜过大。

时间: 2024-08-26 19:15:42

经典算法之计数排序的相关文章

排序算法之计数排序

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

Java中的经典算法之选择排序(SelectionSort)

Java中的经典算法之选择排序(SelectionSort) a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕.也就是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录.基于此思想的算法主要有简单选择排序.树型选择排序和堆排序.(这里只介绍常用的简单选择排序) b) 简单选择排序的基本思想:给定数组:int[] arr={里面n个数据}:第1趟排序,在待排序数据arr[1]~arr[n]中选出最小的数

【算法】计数排序、桶排序和基数排序详解

01.计数排序.桶排序与基数排序 并不是所有的排序 都是基于比较的,计数排序和基数排序就不是.基于比较排序的排序方法,其复杂度无法突破\(n\log{n}\) 的下限,但是 计数排序 桶排序 和基数排序是分布排序,他们是可以突破这个下限达到O(n)的的复杂度的. 1. 计数排序 概念 计数排序是一种稳定的线性时间排序算法.计数排序使用一个额外的数组C,使用 C[i] 来计算 i 出现的次数.然后根据数C来将原数组A中的元素排到正确的位置. 复杂度 计数排序的最坏时间复杂度.最好时间复杂度.平均时

三白话经典算法系列 Shell排序实现

山是包插入的精髓排序排序.这种方法,也被称为窄增量排序,因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序. 由于直接插入排序在元素基本有序的情况下(接近最好情况),效率是非常高的,因此希尔排序在时间效率上比前两种方法有较大提高. 以n=10的一个数组49, 38, 65, 97

算法导论--------------计数排序and基数排序

计数排序假设n个输入元素中的每一个都介于0和k之间的整数,k为n个数中最大的元素.当k=O(n)时,计数排序的运行时间为θ(n).计数排序的基本思想是:对n个输入元素中每一个元素x,统计出小于等于x的元素个数,根据x的个数可以确定x在输出数组中的最终位置.此过程需要引入两个辅助存放空间,存放结果的B[1...n],用于确定每个元素个数的数组C[0...k].算法的具体步骤如下: (1)根据输入数组A中元素的值确定k的值,并初始化C[1....k]= 0: (2)遍历输入数组A中的元素,确定每个元

算法导论 计数排序

计数排序的关键就在于如何处理每个元素的最终位置.在计数排序中,我们可以通过维护一个数组C[i]来记录键值为i的元素所属的位置.每次输入一个A[i],首先记录每个A[i]出现的次数C[i],然后从前向后C[i]=C[i-1]+C[i],这样可以得出值为i所在排序后新数组中的最后一个重复数的位置.计数排序的一个显然问题就是C[]数组的大小确定的问题.下面贴上我自己理解写出的代码. #include<iostream> using namespace std; int main() { int n,

常见排序算法之计数排序与基数排序

1.计数排序 顾名思义,是对待排序数组中的数据进行统计,然后根据统计的数据进行排序,例如: 待排序数组: a[] = { 100, 123, 112, 123, 201, 123, 112, 156, 156, 178, 185, 156, 123, 112 } 首先取出数组中最大值与最小值(这个不用说了吧) 最大值:201  最小值:100 因此该数组的数值范围为 201 - 100 + 1 = 102 开辟一个大小为102的数组 count[102] 并将所有元素初始化为0 再次遍历数组,以

腾讯算法岗一面算法题——计数排序

给定两个整数数组,对第一个数组进行排序,整数顺序由其在第二个数组中的位置决定.对于没有出现在第二个整数数组中的整数,应排在末尾,其之间的顺序无限制.这里整数的取值范围是[0, 2 ^ 32 - 1] 例: 第一个整数数组为 5 1 6 2 1 2 3, 第二个整数数组为2 1 3, 则排序结果为2 2 1 1 3 6 5或2 2 1 1 3 5 6 这道题很明显的第一个思路就是,先生成一个数到index下标的映射,然后建立一个compare函数,根据这个compare函数写一个快排. 相关代码如

经典算法学习——希尔排序

希尔排序的实质就是分组插入排序,该方法又称为缩小增量排序.基本思想为:先将整个带排元素序列分割成若干个子序列(由相隔某个增量的元素组成),分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的.因此希尔排序在时间效率上比前两种方法有较大提高.示例代码上传至:https://github.com/chenyufeng1991/ShellSort . 实现如下