数据结构--排序--基数排序(C语言代码实现)

基数排序

基数排序(Radix Sort)是一种非比较型整数排序算法,思想是将整数按位数切割成不同的数字,然后按每个位数分别比较。

  • 具体来说,基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集的过程。
  • 这个算法基于这样一个事实:对于两个数,如果它们的某个高位数字不同,那么无论它们的低位数字如何,这两个数都不会是相等的;但如果它们的高位数字相同,那么就需要比较它们的低位数字来确定它们的大小关系。

数据结构--排序--基数排序(C语言代码实现)_第1张图片

基数排序可以分为两种:
LSD(Least SignificantDigit,最低有效位)基数排序和MSD(Most Significant Digit,最高有效位)基数排序。

LSD基数排序LSD基数排序从整数的最低位开始,一次排序每个位。

它的基本步骤如下

  • 初始化‌:找到数组中的最大数,确定其位数(即最大数的长度或者说最大数的最位)。
  • 从最低位开始排序‌:对于每一位(从个位开始,然后是十位、百位等),使用计数排序或桶排序等稳定排序算法对数组进行排序。排序时,只考虑当前位的数字,忽略其他位。
  • 重复步骤2‌:对于每一位都重复上述排序过程,直到最高位也被排序。
  • 完成排序‌:经过上述步骤后,数组中的元素将按照从小到大的顺序排列。

MSD基数排序
MSD基数排序则从整数的最高位开始排序,这种方法的复杂度通常比LSD要高,因为它需要递归地处理子数组。

基本步骤如下:

  • 初始化‌:同样需要找到数组中的最大数,确定其位数。
  • 从最高位开始排序‌:根据最高位的数字将数组分成不同的桶(或子数组),每个桶包含所有最高位数字相同的元素。
  • 递归排序‌:对于每个桶(子数组),递归地应用MSD基数排序,但这次是基于次高位进行排序。
  • 合并桶‌:将所有桶中的元素合并成一个有序数组。
  • 完成排序‌:当所有位都被处理完毕后,数组即完成排序。

基数排序的特点
稳定性‌:基数排序是稳定的排序算法,因为每一位的排序都是基于稳定排序算法(如计数排序或桶排序)进行的。
时间复杂度‌:对于n个d位数(每位数的取值范围为0~k-1),LSD基数排序的时间复杂度为O(d*(n+k)),其中d是位数,n是待排序数组的大小,k是每位数的取值范围。MSD基数排序的时间复杂度则依赖于具体的实现和数据的分布情况。
‌空间复杂度‌:基数排序需要额外的空间来存储桶或计数数组,因此其空间复杂度通常较高。
‌适用性‌:基数排序特别适用于整数排序,尤其是当整数的位数较少且取值范围有限时。对于浮点数或字符串等其他类型的数据,基数排序需要进行适当的修改才能应用。

在基数排序的每一轮中,我们可以使用计数排序来对当前位进行排序。以下是一个用C语言实现的基数排序,其中包含了计数排序作为子过程。

代码的实例

#include
#include

//遍历数组
void  mm_ergodicArray(int* array, int array_size) {
    for (int i = 0; i < array_size; i++)
        printf("%d ", array[i]);
    printf("\n");
}

// 获取数组中的最大值
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 count[10] = { 0 }; // 计数数组,因为我们是十进制

    // 统计每个数字在当前位上的出现次数
    for (int i = 0; i < n; i++) {
        int index = (arr[i] / exp) % 10;
        count[index]++;  
    }

    // 计算每个数字的起始位置(即前缀和)
    for (int i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }

    // 根据计数数组将元素放到输出数组的正确位置
    for (int i = n - 1; i >= 0; i--) {
        int index = (arr[i] / exp) % 10;
        
        //count[index]表示前面有几个整数(包含index)
        output[count[index] - 1] = arr[i];  //数组下标从0开始,要-1.
        
        //count[index]个数减1,计算下次在来index,向前放
        count[index]--;
    }

    // 将排序后的数组复制回原数组
    for (int i = 0; i < n; i++) {
        arr[i] = output[i];
    }

    // 释放输出数组的内存
    free(output);
}

// 基数排序
void radixSort(int arr[], int n) {
    int max = getMax(arr, n); // 获取数组中的最大值

        // 对每一位(个,十,百)进行计数排序
    for (int exp = 1; max / exp > 0; exp *= 10) {
        countingSort(arr, n, exp);
    }
}

// 主函数
int main() {
    int array_radix[] = { 170, 45, 75, 90, 802, 24, 2, 66 };
    int array_rad_size = sizeof(array_radix) / sizeof(array_radix[0]);
    mm_ergodicArray(array_radix, array_rad_size);
    radixSort(array_radix, array_rad_size);
    printf("Sorted array: \n");
    mm_ergodicArray(array_radix, array_rad_size);
    return 0;
}

数据结构--排序--基数排序(C语言代码实现)_第2张图片

在这个C语言实现中:

  1. getMax 函数用于找到数组中的最大值,以确定需要排序的位数。
  2. countingSort 函数是基数排序中用于对当前位进行排序的计数排序实现。它接受一个额外的参数 exp,表示当前要排序的位(1表示个位,10表示十位,以此类推)。
  3. radixSort 函数是基数排序的主函数,它调用 countingSort 对每一位进行排序。
  4. mm_ergodicArray 函数用于打印数组。
  5. main 函数中,我们定义了一个示例数组,调用 radixSort 对其进行排序,并打印排序后的数组。

这个实现假设了数组中的元素都是非负整数,并且使用了十进制进行排序。如果数组中包含负数或者

你可能感兴趣的:(数据结构,c语言,开发语言)