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++中深浅拷贝以及写时拷贝实现的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-08-08
  • C++之openFrameworks框架介绍

    C++之openFrameworks框架介绍

    本章我们将介绍一个非常好用的跨平台的 C++开源框架 openFrameworks。它是一个开源的跨平台的C++工具包,方便开发者创建出一个更简单和直观的框架,擅长开发图像和动画,感兴趣的同学可以参考一下
    2023-05-05
  • 基于C语言实现简易的扫雷游戏

    基于C语言实现简易的扫雷游戏

    这篇文章主要为大家详细介绍了基于C语言实现简易的扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C语言链表实现简单图书管理系统

    C语言链表实现简单图书管理系统

    这篇文章主要为大家详细介绍了C语言链表实现简单图书管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C++小知识:C/C++中不要按值传递数组

    C++小知识:C/C++中不要按值传递数组

    今天小编就为大家分享一篇关于C++小知识:C/C++中不要按值传递数组,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • C语言动态内存管理的实现

    C语言动态内存管理的实现

    本文主要介绍了C语言动态内存管理的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 详解Qt中的双缓冲机制与实例应用

    详解Qt中的双缓冲机制与实例应用

    所谓双缓冲机制,是指在绘制控件时,首先将要绘制的内容绘制在一个图片中,再将图片一次性地绘制到控件上。本文主要为大家介绍了Qt中的双缓冲机制与实例应用,希望对大家有所帮助
    2023-03-03
  • C++ 中将一维数组转成多维的三种方式示例详解

    C++ 中将一维数组转成多维的三种方式示例详解

    这篇文章主要介绍了C++ 中将一维数组转成多维的三种方式,每种方式结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • C语言函数的递归和调用实例分析

    C语言函数的递归和调用实例分析

    一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。C语言允许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层
    2013-07-07
  • C语言实现时间处理工具的示例代码

    C语言实现时间处理工具的示例代码

    这篇文章主要为大家详细介绍了利用C语言实现时间处理工具的相关资料,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2022-09-09

最新评论