C语言排序算法之桶排序解析

 更新时间:2023年10月30日 10:23:21   作者:有人_295  
这篇文章主要介绍了C语言排序算法之桶排序解析,桶排序Bucket sort或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里,每个桶再分别排序,大部分是在分桶时,即插入时就排序了,需要的朋友可以参考下

1. 算法思想

桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里,每个桶再分别排序(大部分是在分桶时,即插入时就排序了)。

个人理解,适合数据比较集中排序,桶的数量适当设置。

2. 实现原理

桶排序以下列程序进行:

  • 设置一个定量的数组当作空桶子。
  • 寻访序列,并且把项目一个一个放到对应的桶子去。
  • 对每个不是空的桶子进行排序。
  • 从不是空的桶子里把项目再放回原来的序列中。

3. 动态演示

在这里插入图片描述

(1)数据分桶

在这里插入图片描述

(2)桶内数据排序(大部分是在分桶时,即插入时就排序了)

在这里插入图片描述

(3)然后连接就好了

4. 完整代码

主要函数

插入函数:void insert(BN* list, int value)
排序函数:void bucket_sort(int* array, int size, int num)
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h> // rand() srand()
#include <time.h>   // time()

typedef struct BucketNode
{
    int                data;
    struct BucketNode* next;
} BN;

void displayL(BN* L);               // 输出链表
void display(int* array, int size); // 输出数组
int  check(int* array, int size);   // 检查函数

/***************************************************************************
 * @date    2020/12/03
 * @brief   合并链表
 * @param   head    头指针
 * @param   list    顺序数据链表
 ***************************************************************************/
BN* merge(BN* head, BN* list)
{
    BN* last   = head;
    last->next = list->next;
    while (last->next) {
        last = last->next;
    }
    return last;
}

/***************************************************************************
 * @date    2020/12/03
 * @brief   顺序插入节点
 * @param   list    代表第几个桶的链表
 * @param   value   数据
 ***************************************************************************/
void insert(BN* list, int value)
{
    BN* prev   = list;
    BN* curr   = list->next;
    BN* node   = (BN*)malloc(sizeof(BN));

    node->data = value;
    node->next = NULL;
    if (curr == NULL) {
        prev->next = node;
    } else {
        while (curr != NULL && curr->data < value) {
            prev = curr;
            curr = curr->next;
        }
        prev->next = node;
        node->next = curr;
    }
}

/***************************************************************************
 * @date    2020/12/03
 * @brief   桶排序主程序
 * @param   array   数组
 * @param   size    数组大小
 * @param   num     几个桶
 ***************************************************************************/
void bucket_sort(int* array, int size, int num)
{
    // 申请内存,二级指针,初始化,可以理解头指针没数据,从下一个开始存数数据
    BN** buckets = (BN**)malloc(sizeof(BN*) * num);
    for (int i = 0; i < num; i++) {
        *(buckets + i)         = (BN*)malloc(sizeof(BN));
        (*(buckets + i))->next = NULL;
    }

    // 1. 找到最大值和最小值求间隔(桶的大小)
    int max = array[0];
    int min = array[0];
    for (int i = 0; i < size; i++) {
        if (array[i] > max) {
            max = array[i];
        }
        if (array[i] < min) {
            min = array[i];
        }
    }
    int space = ((max - min) / num) + 1;

    // 2. 一个一个分桶排序
    for (int i = 0; i < size; i++) {
        int n = (array[i] - min) / space;
        insert(*(buckets + n), array[i]);
    }
    for (int i = 0; i < num; i++) {
        printf("第 %d 个桶数据: ", i);
        displayL((*(buckets + i))->next);
    }

    // // 3. 合并链表
    // BN* head   = (BN*)malloc(sizeof(BN));
    // head->next = NULL;
    // BN* last   = merge(head, *(buckets + 0));
    // for (int i = 1; i < num; i++) {
    //     if ((*(buckets + i))->next) {
    //         last = merge(last, *(buckets + i));
    //     }
    // }
    // head = head->next;

    // // 4. 把链表值返回数组
    // for (int i = 0; i < size; i++) {
    //     array[i] = head->data;
    //     head     = head->next;
    // }

    // 3+4. 当然也可以不合并链表,直接把数据返回数组
    int index = 0;
    for (int i = 0; i < num; i++) {
        if ((*(buckets + i))->next != NULL) {
            BN* temp = (*(buckets + i))->next;
            while (temp != NULL) {
                array[index++] = temp->data;
                temp           = temp->next;
            }
        }
    }
}

int main()
{
    // 测试用例
    // int array[]    = {49, 38, 65, 97, 76, 13, 27, 49, 10};
    // int array_size = sizeof(array) / sizeof(array[0]);
    // int bucket_num = 5;
    // printf("%d \n", array_size);
    // printf("排序前数组:");
    // display(array, array_size);
    // bucket_sort(array, array_size, bucket_num);
    // printf("排序后数组:");
    // display(array, array_size);

    // 随机测试
    int bucket_num = 5;              // 桶的个数
    int array_num  = 20;             // 数组数量
    int array_size = 20;             // 数组大小
    int array[array_size];           // 数组初始化
    srand((unsigned int)time(NULL)); // 随机数种子,保证每次不一样
    for (int i = 0; i < array_num; i++) {
        for (int j = 0; j < array_size; j++) {
            array[j] = rand() % 1000; // 随机生成数大小 0~999
        }
        printf("原来的数组:");
        display(array, array_size);
        bucket_sort(array, array_size, bucket_num);
        printf("排序后数组:");
        display(array, array_size);
        // 检测排序结果
        if (check(array, array_size) != 0) {
            exit(-1);
        }
        printf("\n");
    }

    return 0;
}

/***************************************************************************
 * @date    2020/12/03
 * @brief   输出线性表
 * @param   L   首节点
 ***************************************************************************/
void displayL(BN* L)
{
    BN* p = L;                  // p 指向首结点
    while (p != NULL) {         // 不为空,依次遍历
        printf("%d ", p->data); // 打印
        p = p->next;            // p 移向下一个节点
    }
    printf("\n");
}

/***************************************************************************
 * @date    2020/12/03
 * @brief   输出数组
 * @param   array   数组
 * @param   size    数组大小
 ***************************************************************************/
void display(int* array, int size)
{
    for (int i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
}

/**
 * @brief 检查函数,从小到大
 *
 * @param array        数组首指针
 * @param size         数组大小
 */
int check(int* array, int size)
{
    for (int i = 0; i < size - 1; i++) {
        if (array[i] > array[i + 1]) {
            printf("sort array fail...\n");
            return -1;
        }
    }
    printf("sort array success...\n");
    return 0;
}

5. 结果展示

在这里插入图片描述

6. 算法分析

时间复杂度:

  • 最好: O ( n ) O(n) O(n)
  • 最坏: O ( n 2 ) O(n^{2}) O(n2)
  • 平均: O ( n + k ) O(n+k) O(n+k)

空间复杂度: O ( n ∗ k ) O(n*k) O(n∗k)

稳定性:稳定(也有说根据桶内排序决定稳定性)

到此这篇关于C语言排序算法之桶排序解析的文章就介绍到这了,更多相关C语言桶排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++实现的求解多元一次方程示例

    C++实现的求解多元一次方程示例

    这篇文章主要介绍了C++实现的求解多元一次方程,涉及C++矩阵运算相关操作技巧,需要的朋友可以参考下
    2018-01-01
  • C语言中的pause()函数和alarm()函数以及sleep()函数

    C语言中的pause()函数和alarm()函数以及sleep()函数

    这篇文章主要介绍了C语言中的pause()函数和alarm()函数以及sleep()函数,是C语言入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • VScode中添加头文件和源文件(C/C++)的方法

    VScode中添加头文件和源文件(C/C++)的方法

    使用VSCode编译C/C++时,会存在找不到头文件的情况,下面这篇文章主要给大家介绍了关于VScode中添加头文件和源文件(C/C++)的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • C++中的头文件与Extern(外部函数调用)方式

    C++中的头文件与Extern(外部函数调用)方式

    这篇文章主要介绍了C++中的头文件与Extern(外部函数调用)方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C语言修炼之路初识指针阴阳窍 地址还归大道真上篇

    C语言修炼之路初识指针阴阳窍 地址还归大道真上篇

    指针是指向另一个变量的变量。意思是一个指针保存的是另一个变量的内存地址。换句话说,指针保存的并不是普通意义上的数值,而是另一个变量的地址值。一个指针保存了另一个变量的地址值,就说这个指针“指向”了那个变量
    2022-02-02
  • C++实现LeetCode(31.下一个排列)

    C++实现LeetCode(31.下一个排列)

    这篇文章主要介绍了C++实现LeetCode(31.下一个排列),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 深入HRESULT与Windows Error Codes的区别详解

    深入HRESULT与Windows Error Codes的区别详解

    本篇文章是对HRESULT与Windows Error Codes的区别进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言实现变色进度条

    C语言实现变色进度条

    这篇文章主要为大家详细介绍了C语言实现一个变色的进度条,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • Linux系统下C语言中的标准IO总结

    Linux系统下C语言中的标准IO总结

    最近用到了C语言的标准IO库,由于对其中的一些细节不是非常清楚,导致了许多Bug,花了好长时间来调试,所以在此做个笔记,这篇文章主要给大家介绍了关于Linux系统下C语言中标准IO的相关资料,需要的朋友可以参考下
    2024-01-01
  • C++超详细分析函数重载的使用

    C++超详细分析函数重载的使用

    C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,一个函数名可以有多种用途
    2022-04-04

最新评论