算法-计数排序及其变体
本文由@呆代待殆原创,转载请注明出处。
简介:用于整数排序,不同于比较排序,计数排序假设输入元素的大小在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 著;王刚,邹恒明,殷建平,王宏志等译