7.9 基数排序

基数排序

1.基数排序介绍

基数排序(Radix Sort)是桶排序的扩展,它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。 具体做法是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

2.基数排序图文说明

2.1基数排序图文说明

通过基数排序对数组{53, 3, 542, 748, 14, 214, 154, 63, 616},它的示意图如下:

img

在上图中,首先将所有待比较树脂统一为统一位数长度,接着从最低位开始,依次进行排序。

  1. 按照个位数进行排序。
  2. 按照十位数进行排序。
  3. 按照百位数进行排序。

排序后,数列就变成了一个有序序列。

2.2基数排序代码

  1. /*
  2. * 获取数组a中最大值
  3. *
  4. * 参数说明:
  5. * a -- 数组
  6. * n -- 数组长度
  7. */
  8. int get_max(int a[], int n)
  9. {
  10. int i, max;
  11. max = a[0];
  12. for (i = 1; i < n; i++)
  13. if (a[i] > max)
  14. max = a[i];
  15. return max;
  16. }
  17. /*
  18. * 对数组按照"某个位数"进行排序(桶排序)
  19. *
  20. * 参数说明:
  21. * a -- 数组
  22. * n -- 数组长度
  23. * exp -- 指数。对数组a按照该指数进行排序。
  24. *
  25. * 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
  26. * (01) 当exp=1表示按照"个位"对数组a进行排序
  27. * (02) 当exp=10表示按照"十位"对数组a进行排序
  28. * (03) 当exp=100表示按照"百位"对数组a进行排序
  29. * ...
  30. */
  31. void count_sort(int a[], int n, int exp)
  32. {
  33. int output[n]; // 存储"被排序数据"的临时数组
  34. int i, buckets[10] = {0};
  35. // 将数据出现的次数存储在buckets[]中
  36. for (i = 0; i < n; i++)
  37. buckets[ (a[i]/exp)%10 ]++;
  38. // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
  39. for (i = 1; i < 10; i++)
  40. buckets[i] += buckets[i - 1];
  41. // 将数据存储到临时数组output[]中
  42. for (i = n - 1; i >= 0; i--)
  43. {
  44. output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
  45. buckets[ (a[i]/exp)%10 ]--;
  46. }
  47. // 将排序好的数据赋值给a[]
  48. for (i = 0; i < n; i++)
  49. a[i] = output[i];
  50. }
  51. /*
  52. * 基数排序
  53. *
  54. * 参数说明:
  55. * a -- 数组
  56. * n -- 数组长度
  57. */
  58. void radix_sort(int a[], int n)
  59. {
  60. int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
  61. int max = get_max(a, n); // 数组a中的最大值
  62. // 从个位开始,对数组a按"指数"进行排序
  63. for (exp = 1; max/exp > 0; exp *= 10)
  64. count_sort(a, n, exp);
  65. }

radix_sort(a, n)的作用是对数组a进行排序。

  1. 首先通过get_max(a)获取数组a中的最大值。获取最大值的目的是计算出数组a的最大指数。

  2. 获取到数组a中的最大指数之后,再从指数1开始,根据位数对数组a中的元素进行排序。排序的时候采用了桶排序。

  3. count_sort(a, n, exp)的作用是对数组a按照指数exp进行排序。 下面简单介绍一下对数组{53, 3, 542, 748, 14, 214, 154, 63, 616}按个位数进行排序的流程。

    1. 个位的数值范围是[0,10)。因此,参见桶数组buckets[],将数组按照个位数值添加到桶中。

      img

    2. 接着是根据桶数组buckets[]来进行排序。假设将排序后的数组存在output[]中;找出output[]和buckets[]之间的联系就可以对数据进行排序了。

      img

3.基数排序实现

3.1基数排序C实现

实现代码(radix_sort.c)

  1. /**
  2. * 基数排序:C 语言
  3. *
  4. * @author skywang
  5. * @date 2014/03/15
  6. */
  7. #include <stdio.h>
  8. // 数组长度
  9. #define LENGTH(array) ( (sizeof(array)) / (sizeof(array[0])) )
  10. /*
  11. * 获取数组a中最大值
  12. *
  13. * 参数说明:
  14. * a -- 数组
  15. * n -- 数组长度
  16. */
  17. int get_max(int a[], int n)
  18. {
  19. int i, max;
  20. max = a[0];
  21. for (i = 1; i < n; i++)
  22. if (a[i] > max)
  23. max = a[i];
  24. return max;
  25. }
  26. /*
  27. * 对数组按照"某个位数"进行排序(桶排序)
  28. *
  29. * 参数说明:
  30. * a -- 数组
  31. * n -- 数组长度
  32. * exp -- 指数。对数组a按照该指数进行排序。
  33. *
  34. * 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
  35. * (01) 当exp=1表示按照"个位"对数组a进行排序
  36. * (02) 当exp=10表示按照"十位"对数组a进行排序
  37. * (03) 当exp=100表示按照"百位"对数组a进行排序
  38. * ...
  39. */
  40. void count_sort(int a[], int n, int exp)
  41. {
  42. int output[n]; // 存储"被排序数据"的临时数组
  43. int i, buckets[10] = {0};
  44. // 将数据出现的次数存储在buckets[]中
  45. for (i = 0; i < n; i++)
  46. buckets[ (a[i]/exp)%10 ]++;
  47. // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
  48. for (i = 1; i < 10; i++)
  49. buckets[i] += buckets[i - 1];
  50. // 将数据存储到临时数组output[]中
  51. for (i = n - 1; i >= 0; i--)
  52. {
  53. output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
  54. buckets[ (a[i]/exp)%10 ]--;
  55. }
  56. // 将排序好的数据赋值给a[]
  57. for (i = 0; i < n; i++)
  58. a[i] = output[i];
  59. }
  60. /*
  61. * 基数排序
  62. *
  63. * 参数说明:
  64. * a -- 数组
  65. * n -- 数组长度
  66. */
  67. void radix_sort(int a[], int n)
  68. {
  69. int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
  70. int max = get_max(a, n); // 数组a中的最大值
  71. // 从个位开始,对数组a按"指数"进行排序
  72. for (exp = 1; max/exp > 0; exp *= 10)
  73. count_sort(a, n, exp);
  74. }
  75. void main()
  76. {
  77. int i;
  78. int a[] = {53, 3, 542, 748, 14, 214, 154, 63, 616};
  79. int ilen = LENGTH(a);
  80. printf("before sort:");
  81. for (i=0; i<ilen; i++)
  82. printf("%d ", a[i]);
  83. printf("\n");
  84. radix_sort(a, ilen);
  85. printf("after sort:");
  86. for (i=0; i<ilen; i++)
  87. printf("%d ", a[i]);
  88. printf("\n");
  89. }

3.2基数排序C++实现

实现代码(RadixSort.cpp)

  1. /**
  2. * 基数排序:C++
  3. *
  4. * @author skywang
  5. * @date 2014/03/15
  6. */
  7. #include<iostream>
  8. using namespace std;
  9. /*
  10. * 获取数组a中最大值
  11. *
  12. * 参数说明:
  13. * a -- 数组
  14. * n -- 数组长度
  15. */
  16. int getMax(int a[], int n)
  17. {
  18. int i, max;
  19. max = a[0];
  20. for (i = 1; i < n; i++)
  21. if (a[i] > max)
  22. max = a[i];
  23. return max;
  24. }
  25. /*
  26. * 对数组按照"某个位数"进行排序(桶排序)
  27. *
  28. * 参数说明:
  29. * a -- 数组
  30. * n -- 数组长度
  31. * exp -- 指数。对数组a按照该指数进行排序。
  32. *
  33. * 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
  34. * (01) 当exp=1表示按照"个位"对数组a进行排序
  35. * (02) 当exp=10表示按照"十位"对数组a进行排序
  36. * (03) 当exp=100表示按照"百位"对数组a进行排序
  37. * ...
  38. */
  39. void countSort(int a[], int n, int exp)
  40. {
  41. int output[n]; // 存储"被排序数据"的临时数组
  42. int i, buckets[10] = {0};
  43. // 将数据出现的次数存储在buckets[]中
  44. for (i = 0; i < n; i++)
  45. buckets[ (a[i]/exp)%10 ]++;
  46. // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
  47. for (i = 1; i < 10; i++)
  48. buckets[i] += buckets[i - 1];
  49. // 将数据存储到临时数组output[]中
  50. for (i = n - 1; i >= 0; i--)
  51. {
  52. output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
  53. buckets[ (a[i]/exp)%10 ]--;
  54. }
  55. // 将排序好的数据赋值给a[]
  56. for (i = 0; i < n; i++)
  57. a[i] = output[i];
  58. }
  59. /*
  60. * 基数排序
  61. *
  62. * 参数说明:
  63. * a -- 数组
  64. * n -- 数组长度
  65. */
  66. void radixSort(int a[], int n)
  67. {
  68. int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
  69. int max = getMax(a, n); // 数组a中的最大值
  70. // 从个位开始,对数组a按"指数"进行排序
  71. for (exp = 1; max/exp > 0; exp *= 10)
  72. countSort(a, n, exp);
  73. }
  74. int main()
  75. {
  76. int i;
  77. int a[] = {53, 3, 542, 748, 14, 214, 154, 63, 616};
  78. int ilen = (sizeof(a)) / (sizeof(a[0]));
  79. cout << "before sort:";
  80. for (i=0; i<ilen; i++)
  81. cout << a[i] << " ";
  82. cout << endl;
  83. radixSort(a, ilen); // 基数排序
  84. cout << "after sort:";
  85. for (i=0; i<ilen; i++)
  86. cout << a[i] << " ";
  87. cout << endl;
  88. return 0;
  89. }

3.3基数排序Java实现

实现代码(RadixSort.java)

  1. /**
  2. * 基数排序:Java
  3. *
  4. * @author skywang
  5. * @date 2014/03/15
  6. */
  7. public class RadixSort {
  8. /*
  9. * 获取数组a中最大值
  10. *
  11. * 参数说明:
  12. * a -- 数组
  13. * n -- 数组长度
  14. */
  15. private static int getMax(int[] a) {
  16. int max;
  17. max = a[0];
  18. for (int i = 1; i < a.length; i++)
  19. if (a[i] > max)
  20. max = a[i];
  21. return max;
  22. }
  23. /*
  24. * 对数组按照"某个位数"进行排序(桶排序)
  25. *
  26. * 参数说明:
  27. * a -- 数组
  28. * exp -- 指数。对数组a按照该指数进行排序。
  29. *
  30. * 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
  31. * (01) 当exp=1表示按照"个位"对数组a进行排序
  32. * (02) 当exp=10表示按照"十位"对数组a进行排序
  33. * (03) 当exp=100表示按照"百位"对数组a进行排序
  34. * ...
  35. */
  36. private static void countSort(int[] a, int exp) {
  37. //int output[a.length]; // 存储"被排序数据"的临时数组
  38. int[] output = new int[a.length]; // 存储"被排序数据"的临时数组
  39. int[] buckets = new int[10];
  40. // 将数据出现的次数存储在buckets[]中
  41. for (int i = 0; i < a.length; i++)
  42. buckets[ (a[i]/exp)%10 ]++;
  43. // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
  44. for (int i = 1; i < 10; i++)
  45. buckets[i] += buckets[i - 1];
  46. // 将数据存储到临时数组output[]中
  47. for (int i = a.length - 1; i >= 0; i--) {
  48. output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
  49. buckets[ (a[i]/exp)%10 ]--;
  50. }
  51. // 将排序好的数据赋值给a[]
  52. for (int i = 0; i < a.length; i++)
  53. a[i] = output[i];
  54. output = null;
  55. buckets = null;
  56. }
  57. /*
  58. * 基数排序
  59. *
  60. * 参数说明:
  61. * a -- 数组
  62. */
  63. public static void radixSort(int[] a) {
  64. int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
  65. int max = getMax(a); // 数组a中的最大值
  66. // 从个位开始,对数组a按"指数"进行排序
  67. for (exp = 1; max/exp > 0; exp *= 10)
  68. countSort(a, exp);
  69. }
  70. public static void main(String[] args) {
  71. int i;
  72. int a[] = {53, 3, 542, 748, 14, 214, 154, 63, 616};
  73. System.out.printf("before sort:");
  74. for (i=0; i<a.length; i++)
  75. System.out.printf("%d ", a[i]);
  76. System.out.printf("\n");
  77. radixSort(a); // 基数排序
  78. System.out.printf("after sort:");
  79. for (i=0; i<a.length; i++)
  80. System.out.printf("%d ", a[i]);
  81. System.out.printf("\n");
  82. }
  83. }

上面3种实现的原理和输出结果都是一样的。下面是它们的输出结果:

  1. before sort:53 3 542 748 14 214 154 63 616
  2. after sort:3 14 53 63 154 214 542 616 748

原文链接