C语言基数排序:原理、实现与优化
简介
基数排序(Radix Sort)是一种非比较排序算法,它的独特之处在于不通过元素间的比较来确定顺序,而是利用数字的每一位来进行排序操作。这种排序算法在处理整数序列,特别是位数固定的整数序列时,展现出很高的效率。在C语言中,实现基数排序可以让我们在合适的场景下快速地对数据进行排序,本文将详细介绍其概念、使用方法、常见实践及最佳实践。
目录
- 基数排序基础概念
- C语言中基数排序的使用方法
- 常见实践案例
- 最佳实践建议
- 小结
基数排序基础概念
基数排序基于“分配”和“收集”的过程。它按照数字的每一位(个位、十位、百位等)依次进行排序。具体来说,它从最低位开始,将所有元素按照该位的值分配到不同的“桶”中,然后再按照桶的顺序依次收集元素,这样经过一次分配和收集后,序列就会在该位上有序。接着对次低位重复这个过程,直到处理完所有的位。
例如,对于序列 [329, 457, 657, 839, 436, 720, 355]
,首先按个位进行分配:
- 个位为0的桶:
[720]
- 个位为5的桶:
[355]
- 个位为6的桶:
[436]
- 个位为7的桶:
[457, 657]
- 个位为9的桶:
[329, 839]
然后按桶的顺序收集:[720, 355, 436, 457, 657, 329, 839]
。接着对十位、百位重复上述过程,最终得到有序序列。
C语言中基数排序的使用方法
下面是一个简单的C语言实现基数排序的代码示例:
#include <stdio.h>
#include <stdlib.h>
// 获取最大数
int getMax(int arr[], int n) {
int max = arr[0];
for (int i = 1; i < n; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
// 计数排序的辅助函数,用于按指定数位排序
void countingSort(int arr[], int n, int exp) {
int *output = (int *)malloc(n * sizeof(int));
int i, count[10] = {0};
// 统计每个数位出现的次数
for (i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;
// 计算每个数位的最终位置
for (i = 1; i < 10; i++)
count[i] += count[i - 1];
// 构建输出数组
for (i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;
}
// 复制回原数组
for (i = 0; i < n; i++)
arr[i] = output[i];
free(output);
}
// 基数排序主函数
void radixSort(int arr[], int n) {
int m = getMax(arr, n);
// 对每一位进行计数排序
for (int exp = 1; m / exp > 0; exp *= 10)
countingSort(arr, n, exp);
}
// 打印数组
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main() {
int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Original array: ");
printArray(arr, n);
radixSort(arr, n);
printf("Sorted array: ");
printArray(arr, n);
return 0;
}
代码说明
getMax
函数用于找到数组中的最大值,这是为了确定需要处理的最大数位。countingSort
函数是基数排序中的核心辅助函数,它根据指定的数位exp
对数组进行排序。radixSort
函数驱动整个基数排序过程,通过循环调用countingSort
对每一位进行排序。printArray
函数用于打印数组内容,方便调试和查看排序结果。
常见实践案例
对学生成绩进行排序
假设有一个学生成绩数组,每个成绩都是三位数(000 - 999),可以使用基数排序快速对成绩进行排序。
#include <stdio.h>
#include <stdlib.h>
// 前面的getMax、countingSort、radixSort函数定义省略
int main() {
int scores[] = {345, 231, 567, 123, 789, 456};
int n = sizeof(scores) / sizeof(scores[0]);
printf("Original scores: ");
for (int i = 0; i < n; i++)
printf("%d ", scores[i]);
printf("\n");
radixSort(scores, n);
printf("Sorted scores: ");
for (int i = 0; i < n; i++)
printf("%d ", scores[i]);
printf("\n");
return 0;
}
对电话号码进行排序
如果有一组电话号码,每个号码都是固定长度(例如11位),也可以使用基数排序。
#include <stdio.h>
#include <stdlib.h>
// 假设电话号码是11位数字的整数表示
void radixSortForPhone(long long arr[], int n) {
long long m = 0;
for (int i = 0; i < n; i++)
if (arr[i] > m)
m = arr[i];
for (long long exp = 1; m / exp > 0; exp *= 10)
// 这里需要修改countingSort函数以适应long long类型
// 例如修改数组类型和计算方式
countingSortForPhone(arr, n, exp);
}
// 打印电话号码数组
void printPhoneArray(long long arr[], int n) {
for (int i = 0; i < n; i++)
printf("%lld ", arr[i]);
printf("\n");
}
int main() {
long long phones[] = {13800138000, 13900139000, 13600136000};
int n = sizeof(phones) / sizeof(phones[0]);
printf("Original phones: ");
printPhoneArray(phones, n);
radixSortForPhone(phones, n);
printf("Sorted phones: ");
printPhoneArray(phones, n);
return 0;
}
最佳实践建议
- 数据类型适配:确保基数排序的实现能够适应不同的数据类型和范围。如果处理大整数或负数,需要对算法进行适当的调整。
- 空间优化:在使用辅助数组时,尽量减少不必要的内存分配和释放。可以考虑复用已有的内存空间。
- 稳定性维护:基数排序是稳定排序算法,在实现过程中要注意保持其稳定性,以满足特定的应用需求。
- 性能测试:在实际应用中,对基数排序进行性能测试,与其他排序算法(如快速排序、归并排序)进行比较,确保在特定场景下选择最优的排序算法。
小结
基数排序是一种高效的非比较排序算法,在C语言中实现基数排序可以为处理整数序列提供快速的排序解决方案。通过理解其基础概念、掌握使用方法、进行常见实践并遵循最佳实践建议,开发者能够在合适的场景下灵活运用基数排序,提高程序的性能和效率。希望本文能帮助读者深入理解并高效使用C语言基数排序。