c语言排序算法之八(桶排序)

发布于:2024-05-09 ⋅ 阅读:(25) ⋅ 点赞:(0)

前言

以下内容是被验证可以有效理解桶排序,代码也较容易理解。如果你发现还有很多需要增加的,欢迎留言。

为什么要单独写排序算法这一系列,看过一些贴子普遍篇幅较长。看完依旧难以直观理解原理及整个过程。代码永远是基于理解的基础上才能实现。

执行过程能动画展示需方便清晰,最好具备单步演示,方便没理解的可以回看。

语言比较推荐c语言,高级语言库函数较多,人都有惰性思维,将自己置身于环境中训练也是至关重要。

问题与思考:

1.重复数据是否处理?见文末QA。

实现原理

桶排序(Bucket Sort)是一种排序算法,其工作原理是将数组分到有限数量的桶子中,每个桶子再个别进行排序。这个算法是鸽巢排序的一种归纳结果,当要被排序的数组内的数值是均匀分配的时候,桶排序可以使用线性时间(Θ(n))进行排序。

桶排序的步骤通常包括:

  1. 确定桶的数量和区间范围:根据待排序数据的大小范围和数量,确定需要多少个桶,并且确定每个桶所能存放的数据的大小范围。
  2. 将数据分配到对应的桶中:遍历待排序数据,根据数值与桶范围的对应关系,将数据分配到对应的桶中。
  3. 对每个桶进行排序:使用快排、归并等排序算法,对每个桶中的数据进行排序。
  4. 合并各个桶中的数据:将各个桶中的数据按照顺序依次取出,即为排序后的结果。

桶排序的优点是简单且易于实现,但是它并不是比较排序,因此不受O(n log n)下限的影响。然而,桶排序并不适用于所有情况,特别是当数据分布不均匀时,可能会导致某些桶中数据量过大或过小,影响排序效率。此外,桶排序的空间复杂度相对较高,因为需要额外的空间来存储桶。

在实际应用中,桶排序的效率取决于数据的分布和桶的数量。如果数据分布均匀,桶排序可以达到线性时间复杂度O(n)。但如果数据分布不均匀,可能会导致实际运行时间接近O(n log n)。

图解展示过程

图解步骤一:省略

图解步骤二:

图解步骤三:

图解步骤四:省略

具体代码实现

这个示例中,我们假设元素的范围为0-99,创建了10个桶来存放元素。在将元素分配到桶中时,我们通过将元素除以10的商来确定桶的索引。然后对每个桶中的元素使用插入排序进行排序,最后将排序后的元素依次放回原数组中,从而完成整个桶排序的过程。想实现任意数分桶排序还需优化。

#include <stdio.h>

// 桶排序的辅助函数,用于插入排序
void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

// 桶排序主函数
void bucketSort(int arr[], int n) {
    // 假设元素范围为0-99,创建10个桶
    const int num_buckets = 10;
    int buckets[num_buckets][n];
    int bucket_sizes[num_buckets];

    // 初始化每个桶的大小为0
    for (int i = 0; i < num_buckets; i++) {
        bucket_sizes[i] = 0;
    }

    // 将元素分配到桶中
    for (int i = 0; i < n; i++) {
        int bucket_index = arr[i] / 10;  // 桶的索引为元素除以10的商
        buckets[bucket_index][bucket_sizes[bucket_index]] = arr[i];
        bucket_sizes[bucket_index]++;
    }

    // 对每个桶中的元素进行插入排序
    for (int i = 0; i < num_buckets; i++) {
        insertionSort(buckets[i], bucket_sizes[i]);
    }

    // 将排序后的元素依次放回原数组
    int index = 0;
    for (int i = 0; i < num_buckets; i++) {
        for (int j = 0; j < bucket_sizes[i]; j++) {
            arr[index++] = buckets[i][j];
        }
    }
}

void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[] = {29, 25, 11, 49, 37, 21, 43};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("Original array: \n");
    printArray(arr, n);
    bucketSort(arr, n);
    printf("Sorted array: \n");
    printArray(arr, n);
    return 0;
}

Q1:重复数据处理?

A1:原始的数据在元素分配过程中尽数放入分桶中。后续分桶中的插入排序和放回原数组仍继续保留。