算法-计数排序及其变体

本文由@呆代待殆原创,转载请注明出处。

简介:用于整数排序,不同于比较排序,计数排序假设输入元素的大小在0到k之间,通过计算比 i 小的数的个数而确定 i 的位置。

思路:计算所排序的数组中,比元素 i 小的数的个数 n,如果n=5,那么 i 就应该排列在第6个位置上,通过计算每一个元素的 n 值,我们就能知道每一个元素的位置,因为元素有可能重复,所以我们还有记录重复的数的个数以免把重复的数都重复放置到同一个位置上(当然如果你想去掉重复的数时,可以省略这一步)。

算法分析

时间复杂度:Θ(n+k)

空间复杂度:Θ(2n+k)

稳定性:稳定算法

是否是原址排序:否

代码实现

普通版:这个版本假设输入的数据在[0,k]之间,需要给方法输入k的值,会保留重复的数据。

 1 #include<iostream>
 2 #include<vector>
 3 using std::cout;
 4 using std::endl;
 5 using std::vector;
 6 vector<int> counter_sort(vector<int> v,int k){//k是v中最大的数,不是v中元素的个数
 7     vector<int> count, out;
 8     count.resize(k+1,0);//最大的数是9,加上0所以一共要10个空间
 9     out.resize(v.size(),0);//out用来装排好序的v所以和v一样大
10     for (int n : v)//记录相同的元素的个数。
11         ++count[n];
12     for (int i=1; i < count.size(); ++i)//计算小于等于n的数,同时它把自己也算了进去
13         count[i] = count[i] + count[i - 1];
14     for (int n : v){//把每一个元素摆到正确的位置,因为比n小的数的个数已经存到count里了,所以可以直接用
15         out[count[n]-1] = n;//减一的原因是因为count记录的是小于等于元素 n 的数,其中包括 n 自己,所以要剪掉一位
16         --count[n];
17     }
18     return out;
19 }
20 int main(){
21     for (int n : counter_sort({ 1, 4, 2, 1, 9, 4, 8, 7, 9, 0 }, 9))
22         cout << n << " ";
23     cout << endl;
24     vector<int> a = { 0 };
25     a.resize(10, 1);
26     print(a);
27     return 0;
28 }

去重复数据版:这个版本假设输入的数据在[0,k]之间,需要给方法输入k的值,并且会自动去掉重复的数据。

 1 vector<int> counter_sort(vector<int> v, int k){
 2     vector<int> count, out;
 3     count.resize(k + 1);
 4     //out.resize(v.size());
 5     for (int n : v)
 6         count[n] = 1;//++count[n];
 7     for (int i = 1; i < count.size(); ++i)
 8         count[i] = count[i] + count[i - 1];
 9     out.resize(count[count.size() - 1]);//计算去除重复后新数字的长度
10     for (int n : v){
11         out[count[n] - 1] = n;
12         //--count[n];
13     }
14     return out;
15 }

范围扩大版:这个版本假设输入的数据在[-∞,k]之间,需要给方法输入k的值,会保留重复的数据。

 1 vector<int> counter_sort(vector<int> v, int a, int k){
 2     if (0 != a){
 3         for (int& n : v)
 4             n -= a;
 5         k -= a;
 6     }//将[-∞,k]转换到[0,k2]的域里,再用普通的版本去执行
 7
 8     vector<int> count, out;
 9     count.resize(k + 1, 0);
10     out.resize(v.size(), 0);
11     for (int n : v)
12         ++count[n];
13     for (int i = 1; i < count.size(); ++i)
14         count[i] = count[i] + count[i - 1];
15     for (int n : v){
16         out[count[n] - 1] = n;
17         --count[n];
18     }
19     if (0 != a)
20         for (int& n : out){
21             n += a;
22             k += a;
23         }
24     return out;
25 }

自动确定k值版:这个版本会自动确定排序范围,会保留重复的数据。

 1 vector<int> counter_sort(vector<int> v){
 2     if (v.size() < 2)
 3         return v;
 4     int a, k;//自己计算a和k值
 5     if (v[0]<=v[1])
 6         a=v[0], k=v[1];
 7     else a = v[1], k = v[0];
 8     for (int i = 2; i < v.size(); ++i){
 9         if (v[i] < a)
10             a = v[i];
11         else if (v[i] > k)
12             k = v[i];
13     }
14     if (0 != a){
15         for (int& n : v)
16             n -= a;
17         k -= a;
18     }
19
20     vector<int> count, out;
21     count.resize(k + 1, 0);
22     out.resize(v.size(), 0);
23     for (int n : v)
24         ++count[n];
25     for (int i = 1; i < count.size(); ++i)
26         count[i] = count[i] + count[i - 1];
27     for (int n : v){
28         out[count[n] - 1] = n;
29         --count[n];
30     }
31     if (0 != a)
32         for (int& n : out){
33             n += a;
34             k += a;
35         }
36     return out;
37 }

参考资料:《算法导论 中文版》(英文版第三版)(美)ThomasH.Cormen,CharlesE.Leiserson,RonaldL.Rivest,CliffordStein 著;王刚,邹恒明,殷建平,王宏志等译

时间: 2024-10-06 01:14:49

算法-计数排序及其变体的相关文章

经典排序算法 - 计数排序Counting sort

经典排序算法 - 计数排序Counting sort 注意与基数排序区分,这是两个不同的排序 计数排序的过程类似小学选班干部的过程,如某某人10票,作者9票,那某某人是班长,作者是副班长 大体分两部分,第一部分是拉选票和投票,第二部分是根据你的票数入桶 看下具体的过程,一共需要三个数组,分别是待排数组,票箱数组,和桶数组 var unsorted = new int[] { 6, 2, 4, 1, 5, 9 };  //待排数组 var ballot = new int[unsorted.Len

6.算法-计数排序

//算法-计数排序var cc=cc||consolefunction counting_sort(A,B,k){    var C=[]    for(var i=0;i<k;i++){        C[i]=0    }    for(var j=0;i< A.length;j++){        C[A[j]]=C[A[j]]+1    }    for(var i=0;i<k;i++){        C[i]=C[i]+C[i-1]    }    for(var j= A

算法 计数排序

参考博客:常用排序算法总结(二) 计数排序 counting sort 1.计数排序是一种非常快捷的稳定性强的排序方法,时间复杂度O(n+k),其中n为要排序的数的个数,k为要排序的数的组大值.计数排序对一定量的整数排序时候的速度非常快,一般快于其他排序算法.但计数排序局限性比较大,只限于对整数进行排序.计数排序是消耗空间发杂度来获取快捷的排序方法,其空间发展度为O(K)同理K为要排序的最大值. 2.计数排序的基本思想为一组数在排序之前先统计这组数中其他数小于这个数的个数,则可以确定这个数的位置

[经典算法]计数排序

概述: 计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出.它的优势在于在对一定范围内的集合排序时,它的复杂度为Ο(n+k)(其中k是元素的范围),快于任何比较排序算法. 计数排序本质上是通过计算无序集合中元素出现的次数来决定集合应该如何排序的. 例如一个数组{1, 4, 1, 2, 7, 5, 2},进行计数排序过程 1.使用Count数组记录元素次数 Index: 0 1 2 3 4 5 6 7 8 9 Count: 0 2 2 0 1 1 0

【vlfeat】O(n)排序算法——计数排序

今天想在网上找一个实现好的er算法来着,没啥具体的资料,无奈只能看vlfeat的mser源码,看能不能修修补补实现个er. 于是,看到某一段感觉很神奇,于是放下写代码,跑来写博客,也就是这段 1 /* ----------------------------------------------------------------- 2 * Sort pixels by intensity 3 * --------------------------------------------------

算法——计数排序与快速排序

计数排序是一种算法复杂度 O(n) 的排序方法,适合于小范围集合的排序.比如100万学生参加高考,我们想对这100万学生的数学成绩(假设分数为0到100)做个排序.我们如何设计一个 最高效的排序算法.本文不光给出计数排序算法的传统写法,还将一步步深入讨论算法的优化,直到时间复杂度和空间复杂度最优. 先看看计数排序的定义 Counting sort (sometimes referred to as ultra sort or math sort[1]) is a sorting algorith

线性排序算法---- 计数排序, 基数排序, 桶排序

排序算法里,除了比较排序算法(堆排序,归并排序,快速排序),还有一类经典的排序算法-------线性时间排序算法.听名字就让人兴奋! 线性时间排序,顾名思义,算法复杂度为线性时间O(n) , 非常快,比快速排序还要快的存在,简直逆天.下面我们来仔细看看三种逆天的线性排序算法, 计数排序,基数排序和桶排序. 1计数排序  counting Sort 计数排序 假设 n个 输入元素中的每一个都是在 0 到 k 区间内的一个整数,当 k= O(N) 时,排序运行的时间为 O(N). 计数排序的基本思想

排序算法 - 计数排序

基本思想 计数排序是一种线性排序算法,它利用了一个数组,因为数组下标的增长是线性的,所以它就把自己的元素转换成新开辟数组的下标.可是下标都是非负数啊?数组当中的值有正有负啊.做一个简单的转化就行了:找到数组中最小元素,用元素值减去,这样一来,所有元素对应的下标就求出来了.(实际上感觉像是个映射函数?)下图中保存的是待排序数组:[-1,-5,-6,-2,1,2,8,2,1,8] 然后跟哈希排序的思路一样:这里.直接开辟一个对应的哈希数组,然后统计每个元素出现的次数.橙色标注出来的表示待排序数组中没

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

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