计数排序实现基数排序

分手后的思念是犯贱 2022-07-28 11:41 329阅读 0赞

基数排序

简介

基数排序(英语:Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

效率

基数排序的时间复杂度是O(k⋅n),其中n是排序元素个数,k是数字位数。注意这不是说这个时间复杂度一定优于O(n⋅log(n)),k的大小取决于数字位的选择(比如比特位数),和待排序数据所属数据类型的全集的大小;k决定了进行多少轮处理,而n是每轮处理的操作数目。


















数据结构 数组
最差时间复杂度 O(kN)
最差空间复杂度 O(kN)

以上内容整理自维基百科


实现

上述提到基数排序的原理是按位排序(必须是稳定的排序算法),对于位数不足的正整数要在高位补0,根据此,得出伪代码:

  1. RADIX-SORT(A,d)
  2. for i: 1 to d
  3. do use a stable sort to sort array A on digit i

这里的稳定排序可以是计数排序和桶排序(中文维基上给的示例是桶排序),这里我用计数排序来实现它。
由于基数排序适用于正整数、字符串、特定格式的浮点数排序,这里不方便写成模板的方式(或者是我能力还不够LOL),我就写了正整数的排序版本。

代码

  1. #ifndef MYSORT_H_
  2. #define MYSORT_H_
  3. #include <iostream>
  4. #include <limits>
  5. namespace MySort{
  6. template <typename T>
  7. void Counting_Sort(T *data,T*A, T*B, int k, size_t n)//修改的计数排序
  8. {
  9. //n= length(A)
  10. T *C = new T[k + 1];
  11. for (int i = 0; i <= k; i++)
  12. {
  13. *(C + i) = 0;
  14. }//初始化辅助空间C
  15. for (int i = 0; i < n; i++)
  16. {
  17. *(C + *(A + i)) = *(C + *(A + i)) + 1;
  18. }//计数
  19. for (int i = 1; i <= k; i++)
  20. {
  21. *(C + i) = *(C + i) + *(C + i - 1);
  22. }
  23. for (int i = n - 1; i >= 0; i--)
  24. {
  25. *(B + *(C + *(A + i)) - 1) = *(data + i);//把data[i]放在其前面数总和的下一个位置
  26. *(C + *(A + i)) = *(C + *(A + i)) - 1;//排除存在相同元素的情况
  27. }
  28. delete[]C;
  29. }
  30. int max_bits(int a[],int n)//求最大位数
  31. {
  32. int maxNum=a[0];
  33. for (int i = 0; i < n; i++)
  34. {
  35. if (maxNum < a[i])
  36. {
  37. maxNum = a[i];
  38. }
  39. }
  40. int bit = 0;
  41. while (maxNum)
  42. {
  43. maxNum /= 10;
  44. bit++;
  45. }
  46. return bit;
  47. }
  48. int genBit(int value, int i)
  49. {
  50. return (value / (int)pow(10, i - 1)) % 10;
  51. }
  52. void Radix_Sort(int a[], int n,int k)
  53. {
  54. int *src = new int[n];
  55. //a[]表示待比较的数
  56. //n表示待比较元素的个数
  57. //k表示待比较元素中长度最长的长度
  58. //int k = max_bits(a, n);
  59. for (int i = 1; i <= k; i++)
  60. {
  61. int* dest = new int[n];
  62. for (int j = 0; j < n; j++)
  63. {
  64. src[j] = genBit(a[j], i);//tmp成为计数排序中待比较的值
  65. }
  66. Counting_Sort<int>(a,src, dest, 10, n);//重载版本
  67. for (int k = 0; k < n; k++)
  68. {
  69. a[k] = dest[k];
  70. }
  71. delete[]dest;
  72. }
  73. delete[] src;
  74. }
  75. }//namespace MySort
  76. #endif

测试代码

  1. #include <iostream>
  2. #include "MySort.h"
  3. using namespace std;
  4. int main()
  5. {
  6. int a[] = { 234, 114, 5, 44, 3231, 98 };
  7. int aSize = sizeof(a) / sizeof(int);
  8. int maxBits = MySort::max_bits(a, aSize);
  9. MySort::Radix_Sort(a, aSize, maxBits);
  10. for (int i = 0; i < aSize; i++)
  11. {
  12. cout << a[i] << endl;
  13. }
  14. system("PAUSE");
  15. return 0;
  16. }

发表评论

表情:
评论列表 (有 0 条评论,329人围观)

还没有评论,来说两句吧...

相关阅读

    相关 彻底计数排序基数排序

    随机化快速排序、堆排序、归并排序、插入排序都是比较模型的排序,最好的情况下时间复杂度是O(nlgn),那有没有比nlgn更快的呢?答案是有的,利用空间换时间,那就是计数排序和基