算法导论-排序(四)计数排序(线性时间排序)

目录

1、计数排序介绍

2、流程图

3、代码实现

4、性能分析

5、参考资料

内容

1、计数排序介绍

什么是计数排序?

计数排序是一种特殊的排序算法,之前介绍的排序算法需要对数进行两两比较,效率下界为θ(nlgn);   而计数排序不需要对数进行比较就可以进行排序;很神奇吧,只需要对待排序数组进行遍历就可以排序,效率为Θ(n)。。哈哈,那么神奇,下面开讲!!!!

限制:计数排序只能对非负整数(0,1,2,3...N)进行排序

排序思想:计数排序的基本思想就是对每一个输入元素 x,确定出小于 x 的元素个数。有了这一信息,就可以把 x 直接放到它在最终输出数组中的位置上。例如:有 10 个年龄不同的人,统计出有 8 个人的年龄比 A 小,那 A 的年龄就排在第 9 位,用这个方法可以得到其他每个人的位置,也就排好了序。

2、流程图

排序算法步骤:

1)统计数组中每个值为 X 的元素出现的次数,存入数组 C 的第X 项

2)累加元素出现次数(计算不超过 X包括X 的元素的个数)

3) 将元素X依次放入到适当的位置

排序伪码:

CountSort(A,n,k) //A-待排序数组;n-排序数组元素个数;k-大于等于待排序数组元素最大值的某个整数    步骤一流程图 1)统计数组中每个值为 X 的元素出现的次数,存入数组 C 的第X 项

  步骤二 流程图 2)累加元素出现次数(计算不超过 X包括X 的元素的个数)

步骤三流程图 3)将元素X依次放入到适当的位置

3、代码实现(c++)

 1 #include <iostream>
 2 #include <vector>
 3 #include <time.h>
 4 using namespace std;
 5
 6 #define  N 10   //排序数组大小
 7 #define  K 100   //排序数组范围0~K
 8
 9 void CountSort(vector<int> &A)
10 {
11     //找出待排序数组最大、最小值
12     int min,max;
13     min=max=A[0];
14     for (int i=1;i<A.size();i++)
15     {
16         if (A[i]<min) min=A[i];
17         else if (A[i]>max) max=A[i];
18     }
19     //定义数组B存放排好的数
20     vector<int> B(A.size());
21     //定义数组C,大小为(max-min+1),C[i]为A中值为i的个数
22     vector<int> C(max-min+1);
23     for (int i=0;i<max-min+1;i++) C[i]=0;//初始为0
24     for(int i=0;i<A.size();i++) C[A[i]-min]++;//计数
25     for (int i=1;i<max-min+1;i++) C[i]+=C[i-1];//累加
26     for (int i=A.size()-1;i>=0;i--)
27     {
28         B[C[A[i]-min]-1]=A[i];//A中值倒序取出放到B中合适位置,并在C计数中减1
29                                          //因数组下标从0开始,所以减1
30         C[A[i]-min]--;
31     }
32     A.assign(B.begin(),B.end());//B赋给A
33 }
34 ////打印数组
35 void print_element(vector<int> A)
36 {
37     int len=A.size();
38     for (int i=0;i<len;i++)
39     {
40         std::cout<<A[i]<<" ";
41     }
42     std::cout<<std::endl;
43 }
44 // 随机参数排序数组,产生数组范围0~k的整数
45 void Random(vector<int> &a,int n,int k)
46 {
47     int i=0;
48     srand( (unsigned)time( NULL ) );
49     while(i<n)
50     {
51         a[i++]=rand()%k;
52     }
53 }
54
55 int main()
56 {
57     vector<int > vec_int(N);
58     Random(vec_int,N,K);
59     cout<<"源数组: ";
60     print_element(vec_int);
61     CountSort(vec_int);
62     cout<<"以排序数组: ";
63     print_element(vec_int);
64
65     system("PAUSE");
66     return 0;
67 }

4、性能分析

分析性能好的快速排序和本节介绍的计数排序的效率【排序数组取值为0~100的整数,数组大小分别取100,1000,10000,100000测试】

数组大小N 快速排序(ms) 计数排序(ms)
100 0.153012 0.236982
1000 6.00759 4.61228
10000 58.4422 16.0187
100000 4176.58 169.768

分析:当数组元素个数较大时,计数排序效率相当高!

 注意:当排序数组元素个数较少时效率会降低,并且数组范围较大时内存消耗会相对增多。

         何时使用计数排序:

          结:  1)待排序数组为非负整数

                  2) and 数组范围小,元素个数较多

5、参考资料

【1】http://blog.csdn.net/xyd0512/article/details/8261816

【2】http://www.cnblogs.com/gaochundong/p/sorting_in_linear_time.html

【3】http://www.cnblogs.com/xiao-cheng/archive/2011/10/05/2199657.html

时间: 2024-10-06 04:07:49

算法导论-排序(四)计数排序(线性时间排序)的相关文章

算法导论笔记 第8章 线性时间排序

任何比较排序在最好情况下都要经过Ω(nlgn),即比较排序的下界为Ω(nlgn). 合并排序和堆排序都是渐进最优的. 要突破Ω(nlgn),就要进行非比较排序.计数排序.基数排序和桶排序都有非比较的一些操作来确定排序顺序,它们可以达到线性运行时间. 这三种排序都是以空间换时间.应用的不广,先不细看了. 原文地址:https://www.cnblogs.com/jackson-zhou/p/8419798.html

【算法导论-学习笔记】以线性时间增长的排序——计数排序

计数排序是一种能够达到运行时间能够线性时间θ(n)的排序算法.在排序算法里算是最快的算法之一,当然,他有很强烈的前提.下面开始介绍一下技术排序(Counting Sort). 算法思想 计数排序假设n个输入元素中的每一个都是介于0到k之间的整数,此处k为某个整数.这样可以用一个数组C[0..k]来记录待排序数组里元素的数量.当k=O(n)时,计数排序的运行时间为θ(n). 注:关于C[0..k],用键值对描述的话,待排序元素是键,相同元素的个数是值.例:待排序数组<2,3 , 6,4 , 1 ,

算法导论9.2以期望线性时间做选择

#include <stdint.h> #include <time.h> #include <iostream> #ifdef __linux #include <stdio.h> #include <stdlib.h> #endif void swap(int64_t* A, uint64_t i, uint64_t j) { int64_t tmp = A[i]; A[i] = A[j]; A[j] = tmp; } int64_t par

算法导论-- 线性时间排序(计数排序、基数排序、桶排序)

线性时间排序 前面介绍的几种排序,都是能够在复杂度nlg(n)时间内排序n个数的算法,这些算法都是通过比较来决定它们的顺序,这类算法叫做比较排序 .下面介绍的几种算法用运算去排序,且它们的复杂度是线性时间. -------------------------------------- 1.计数排序 计数排序采用的方法是:对每个元素x,去确定小于x的元素的个数,从而就可以知道元素x在输出数组中的哪个位置了. 计数排序的一个重要性质是它是稳定的,即对于相同的两个数,排序后,还会保持它们在输入数组中的

算法导论之六:线性时间排序之 决策树&amp;计数排序

本系列前五篇都是讲述的比较排序算法,从本文开始,将进入线性时间排序.什么是比较排序,简单的说,就是排序的过程依赖于数组中数据大小的比较,从而来确定数据在排好序输出时的位置. 比较排序法比较直观,但是也有它的不足,我们容易证明任何比较排序法,在最坏的情况下的时间复杂度的下限都是 nlgn.要证明这个问题,我们首先要搞清楚一个模型:决策树模型. 一.决策树模型 什么是决策树?决策树从形态上来讲,是一颗完全二叉树,它除叶子节点之外,其他层的节点都是满的.它的每一个叶子节点表示对输入数据组合的一种排序可

算法导论——lec 08 线性时间排序

之前我们介绍了几种O(nlgn)的排序算法:快速排序.合并排序和堆排序,本节我们介绍基于比较的排序算法的下界以及几个线性时间的排序算法--计数排序.基数排序.桶排序. 一. 比较排序算法的下界 1. 决策树模型:比较排序可以被抽象的视为决策树.一棵决策树是一棵满二叉树,表示某排序算法 作用于给定输入所做的所有比较. 排序算法的执行对应于遍历一条从树的根到叶结点的路径.在每个内节结点处要做比较. 要使排序算法能正确的工作,其必要条件是,n 个元素的n!种排列中的每一种都要作为决策树 的一个叶子而出

算法导论 第8章 线性时间排序

合并排序和堆排序的时间复杂度为O(nlgn),插入排序和冒泡排序的时间复杂度为O(n^2),快速排序的时间复杂度在平均情况下是O(nlgn),这些排序算法都是通过对元素进行相互比较从而确定顺序的,因此都叫比较排序. 比较排序可以看做是决策树(一个满二叉树),因为每一次比较都是一个分支.n个元素的序列,其排序的结果有 n! 种可能(n个元素的全排),所以这个决策树有 n! 个叶子结点,假设树的高度为h,则有:n! <= 2^h,所以h >= lg(n!) = Ω(nlgn).一次比较排序就是从决

算法导论第八章线性时间排序

一.线性时间排序算法历史概览 计数排序首先是由 Harold H. Seward 于1954年提出,而且他还提出将计数排序和基数排序进行结合的思想:基数排序是L.J.Comrie于1929年首次在一篇描述卡片穿孔机文档中提出的一种方法,它是从最低有效位开始,对一个有多位数组成的数进行排序的方法:而桶排序的基本思想则由E.J.Isaac和R.C.Singleton于1956年提出的,之后很多研究人员在这三种算法的基础上针对不同的应用场景又进一步改进,到了今天一个很成熟.很通用的地步. 二.O(nl

算法导论 第八章 线性时间排序(python)

比较排序:各元素的次序依赖于它们之间的比较{插入排序O(n**2) 归并排序O(nlgn) 堆排序O(nlgn)快速排序O(n**2)平均O(nlgn)} 本章主要介绍几个线性时间排序:(运算排序非比较排序)计数排序O(k+n)基数排序O() 第一节:用决策树分析比较排序的下界 决策树:倒数第二层满,第一层可能满的二叉树,它用来表示所有元素的比较操作{于此来分析下界},忽略控制,移动操作 1:2 #A[1]和A[2]比 <= 走左边 >走右边 <3,1,2> 最后的结果 下标对应排

排序算法(4)-线性时间排序

在前面三节排序算法中,我们分别分析了不同策略,思想用于排序,而这些算法都是基于数据间的比较来确定顺序的.假设我不用比较,换一种思路,那么就可以达到时间复杂度为O(n)的排序算法,当然是以付出额外的空间为代价的. 一.基本思想 线性时间排序的算法思想: (1):在计数排序中,利用比x小或等的元素个数和的来确定x位置.比如2 5 4 9 1 6.9比其余5个数都大,那就说明9 在排序后的第6个位置,这样我们只要得到比某个数大的元素个数就能得到元素在排序后数组中的位置了. (2):在桶排序中,是通过映