图解并用 C 语言实现非比较排序(计数排序、桶排序和基数排序)

news2024/12/26 11:42:05

目录

一、计数排序

二、桶排序

三、基数排序



一、计数排序

算法步骤

  1. 找出待排序数组 arr 中的最小值和最大值(分别用 min 和 max 表示)。

  2. 创建一个长度为 max - min + 1、元素初始值全为 0 的计数器数组 count

  3. 扫描一遍原始数组,将 arr[i] - min 作为下标,并将该下标的计数器增 1。

  4. 扫描一遍计数器数组,按顺序把值收集起来。

void CountSort(int* arr, int n)
{
    // 找出待排序数组中的最小值和最大值
    int min = arr[0];
    int max = arr[0];
    for (int i = 1; i < n; ++i)
    {
        if (arr[i] < min)
        {
            min = arr[i];
        }
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }
    // 创建一个长度为 max - min + 1,元素初始值全为 0 的计数器数组
    int* count = (int*)calloc(max - min + 1, sizeof(int));
    if (NULL == count)
    {
        perror("malloc failed!");
        return;
    }
    // 扫描原始数组
    for (int i = 0; i < n; ++i)
    {
        count[arr[i] - min]++;
    }
    // 扫描计数器数组
    int k = 0;
    for (int i = 0; i < max - min + 1; ++i)
    {
        for (int j = 0; j < count[i]; ++j)
        {
            arr[k++] = i + min;
        }
    }
}

计数排序适合范围集中,且范围不大的整型数组


二、桶排序

桶排序(Bucket Sort)或所谓的箱排序,其工作原理是:假设输入数据服从均匀分布,将数据分到有限数量的桶里,然后对每个桶分别排序,最后把桶的数据合并。

桶排序的时间复杂度,取决于各个桶之间数据进行排序的时间复杂度,因为其他部分的时间复杂度都为 O(n)。很显然,桶划分地越小,各个桶之间的数据越少,排序所用的时间也会越少,但相应的空间消耗会增加。

void BucketSort(int* arr, int n)
{
    int bucket[5][5] = { 0 };  // 分配 5 个桶,每个桶最多放 5 个元素
    int bucketCount[5] = { 0 };  // 这 5 个桶的计数器的计数器
    // 将数据放入桶中
    for (int i = 0; i < n; ++i)
    {
        bucket[arr[i] / 10][bucketCount[arr[i] / 10]++] = arr[i];
    }
    // 对每个桶进行排序
    for (int i = 0; i < 5; ++i)
    {
        QuickSort(bucket[i], bucketCount[i]);
    }
    // 把每个桶中的数据填充到数组中
    int k = 0;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < bucketCount[i]; ++j)
        {
            arr[k++] = bucket[i][j];
        }
    }
}

在现实世界中,大部分的数据分布是均匀的,或者在设计的时候可以让它均匀分布,或者说可以转换为均匀地分布。当数据均匀地分布,桶排序的效率就能发挥出来。

理解桶思想可以设计出高效的算法。


三、基数排序

基数排序(Radix Sort)是一种借助多关键排序的思想对单逻辑关键字进行排序的方法。

void DistrAndCollect(int* arr, int n, int exp)
{
    Queue q[10];
    for (int i = 0; i < 10; ++i)
    {
        QueueInit(&q[i]);
    }
    // 分配
    for (int i = 0; i < n; ++i)
    {
        int j = (arr[i] / exp) % 10;
        QueuePush(&q[j], arr[i]);  // 将 arr[i] 分配到下标为 j 的队列(桶)中
    }
    // 收集
    int j = 0;
    for (int i = 0; i < 10; ++i)
    {
        while (!QueueEmpty(&q[i]))
        {
            arr[j++] = QueueFront(&q[i]);
            QueuePop(&q[i]);
        }
    }
}
​
void RadixSort(int* arr, int n)
{
    // 找出待排序数组中的最大值
    int max = arr[0];
    for (int i = 1; i < n; ++i)
    {
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }
    // 分配和收集
    for (int exp = 1; max / exp > 0; exp *= 10)
    {
        // exp 表示排序指数,
        // 当 exp 为 1 时,表示按个位分配,
        // 当 exp 为 10 时,表示按十位分配,依次类推。
        DistrAndCollect(arr, n, exp);
    }
}

 

void DistrAndCollect(int* arr, int n, int exp)
{
    int bucket[10] = { 0 };  // 初始化 10 个桶
    int* result = (int*)malloc(sizeof(int) * n);
    if (NULL == result)
    {
        perror("malloc failed!");
        return;
    }
    // 分配
    for (int i = 0; i < n; ++i)
    {
        bucket[(arr[i] / exp) % 10]++;
    }
    for (int i = 1; i < 10; ++i)
    {
        bucket[i] = bucket[i] + bucket[i - 1];
    }
    // 收集
    for (int i = n - 1; i >= 0; --i)  // 从后向前遍历数组 arr
    {
        int j = (arr[i] / exp) % 10;
        result[bucket[j] - 1] = arr[i];
        bucket[j]--;
    }
    memmove(arr, result, sizeof(int) * n);
}
​
void RadixSort(int* arr, int n)
{
    // 找出待排序数组中的最大值
    int max = arr[0];
    for (int i = 1; i < n; ++i)
    {
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }
    // 分配和收集
    for (int exp = 1; max / exp > 0; exp *= 10)
    {
        // exp 表示分配指数,
        // 当 exp 为 1 时,表示按个位分配,
        // 当 exp 为 10 时,表示按十位分配,依次类推。
        DistrAndCollect(arr, n, exp);
    }
}

基数排序的其他应用,例如超女选秀活动,如果要把超女的出生日期排序:

  1. 年:1990 ~ 2005(15 个桶)

  2. 月:1 ~ 12(12 个桶)

  3. 日:1 ~ 31(31 个桶)

创作不易,可以点点赞,然后关注一下博主~ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nacos客户端实例注册源码分析-篇一

Nacos客户端实例注册源码分析-篇一 版本 nacos 服务器端 nacos 2.0.3 实例客户端注册入口 注册案例 回到之前搭建的服务提供者项目 9002 &#xff0c;在真实的生产环境下&#xff0c;如果需要让某一个服务注册到 Nacos 的服务当中&#xff0c;我们引入对应的 nacos 发现依赖&…

4月Google Play政策更新,游戏上架需要注意这几点

3月21日&#xff0c;据路透社报道&#xff0c;由于发现国内某知名电商应用存在恶意软件问题&#xff0c;谷歌已暂时将该APP从商店下架&#xff0c;并表示&#xff1a;将该APP下架是一种安全预防措施&#xff0c;已经下载的用户也会收到警告&#xff0c;提示他们进行卸载。 4月…

基于深度学习的动物识别系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;动物识别系统用于识别和统计常见动物数量&#xff0c;通过深度学习技术检测日常几种动物图像识别&#xff0c;支持图片、视频和摄像头画面等形式。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集以及PyQt的UI界面。动物识别系统主要用于常…

c/c++:算术运算符,赋值运算,逻辑运算,比较运算,三目运算,逗号运算,数据类型转换

c/c&#xff1a;算术运算符&#xff0c;赋值运算&#xff0c;逻辑运算&#xff0c;比较运算&#xff0c;三目运算&#xff0c;逗号运算&#xff0c;数据类型转换 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的…

【自定义表格穿梭框】自定义封装jqgrid表格穿梭框,支持分页复选全选(附完整源码及效果图)

【写在前面】其实之前业务中也有这个方面的需求&#xff0c;但是总觉得自己写的有点乱&#xff0c;此时也就借这个机会重新封装一个公共的函数去实现这个穿梭框的效果&#xff0c;支持分页勾选&#xff0c;页面展示已选中和未选择的数据&#xff0c;使得系统操作更友好。 涉及知…

数学建模(三):模拟退火算法(SA)

文章目录模拟退火算法&#xff08;SA&#xff09;一、 概述1、 算法简介2、 核心思想3、 数学原理4、 模拟退火的流程二、 实例分析1、 初始化参数2、 Metrospolis 准则3、 生成新的值4、 获取最优值5、 主程序6、 总代码模拟退火算法&#xff08;SA&#xff09; 一、 概述 1…

折叠屏市场起风,华为、OPPO“你追我赶”

配图来自Canva可画 现如今&#xff0c;智能手机已经成为了人们生活中不可或缺的重要工具&#xff0c;无论是出行&#xff0c;还是社交&#xff0c;亦或是支付&#xff0c;只需要一部智能手机就可以通通搞定。因此&#xff0c;在消费者多样化需求的助推下&#xff0c;智能手机行…

【Spring】—Spring中Bean的配置、作用域

一、Bean的配置 Spring用于生产和管理Spring容器中的Bean&#xff0c;需要开发者对Spring的配置文件进行配置。在实际开发中&#xff0c;最常采用XML格式的配置方式&#xff0c;即通过XML文件来注册并管理Bean之间的依赖关系。 在Spring中&#xff0c;XML配置文件的根元素是…

易基因:全基因组CpG密度和DNA甲基化分析方法比较(MeDIP、RRBS和WGBS)| 研究综述

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 CpG密度&#xff08;CpG density&#xff09;与各种组织中的DNA甲基化相关。基因组按CpG密度分为&#xff1a;CpG岛&#xff08;CpG island&#xff0c;CGI&#xff09;、CpG岛上下游2kb…

FFMPEG VCL Pack Crack显示位置支持或光标

FFMPEG VCL Pack Crack显示位置支持或光标 FFMPEG VCL Pack是一个组合解决方案和平台&#xff0c;用于在Delphi中录制、转换和传播音频和视频&#xff0c;其中包括音频/视频库中的前一个libavcodec。 FFMPEG VCL Pack功能和选项&#xff1a; 新的Live555公司基于Rtsp Media Ser…

基于深度学习的安全帽检测系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;安全帽检测系统用于自动化监测安全帽佩戴情况&#xff0c;在需要佩戴安全帽的场合自动安全提醒&#xff0c;实现图片、视频和摄像头等多种形式监测。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集&#xff0c;以及PyQt的UI界面。安全帽检…

设计模式之迭代器模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、迭代器模式是什么&#xff1f; 迭代器模式是一种行为型的软件设计模式&#xff0c;提供一种方法能顺序访问聚合对象中的各个元…

如何做好缓存设计?

大家好&#xff0c;我是易安&#xff01;今天我们来谈一谈缓存应该如何设计。 什么是缓存 缓存是一种临时储存数据的方式。当用户查询数据时&#xff0c;系统会首先在缓存中查找&#xff0c;如果数据已经存在于缓存中&#xff0c;则直接使用&#xff0c;否则系统会到数据的原始…

研报精选230410

目录 【行业230410西南证券】医药行业2023年4月投资月报&#xff1a;看好创新药和中药行情【行业230410国信证券】汽车行业4月投资策略&#xff1a;3月新能源乘用车批发销量预计同比增长32%&#xff0c;持续关注板块年报季报行情【行业230410西南证券】医药行业周报&#xff1a…

【集成架构】探索3种顶级「集成框架」Apache、Spring和Mule

正确的集成框架是绑定应用程序架构构建块的粘合剂。应用程序组件必须不断交换关键数据&#xff0c;以方便用户操作、服务扩展、威胁监视、后端操作、事件触发等。如果没有可靠的集成过程&#xff0c;应用程序和服务故障将淹没软件环境。正确的集成框架是绑定应用程序架构构建块…

【JAVA】#详细介绍!!! synchronized 加锁 详解(1)!

本文分以下几点来介绍synchronized&#xff08;根据JDK1.8&#xff09; 1. 介绍synchronized 2. synchronized 为什么能保证线程安全 3. synchronized 的 用法 4. synchronized 的锁特性 目录 1. 介绍synchronized 2. synchronized的用法 2.1 synchronized修饰指定代码块 2…

如何定位Spark数据倾斜问题,解决方案

文章目录前言一、数据倾斜和数据过量二、 数据倾斜的表现三、定位数据倾斜问题定位思路&#xff1a;查看任务-》查看Stage-》查看代码四、7种典型的数据倾斜场景解决方案一&#xff1a;聚合元数据解决方案二&#xff1a;过滤导致倾斜的key解决方案三&#xff1a;提高shuffle操作…

谁才是天下第一关?

什么是关&#xff0c;中华大地有多少关&#xff1f; 关是往来必由之要处。“山川扼要&#xff0c;是设关津。表封藏&#xff0c;以达道路&#xff0c;天险既呈&#xff0c;人力并济”。 关可分为&#xff1a; 关防&#xff0c;驻兵防守的要塞&#xff1b;关津&#xff0c;水陆…

python笔记:qgrid

在Jupyter Notebook中像在Excel一样操作pandas的DataFrames&#xff0c;如sort/filter&#xff0c;并轻松把操作后的数据用于后续分析。 0 安装 pip install qgrid jupyter nbextension enable --py --sys-prefix qgrid 1 基本使用方法 1.1 数据 import numpy as np import…

Carla 保姆级安装教程

一&#xff1a;电脑配置 carla支持windows,Linux系统构建&#xff0c;官方对于安装电脑的最低配置要求是拥有6G显存的GPU&#xff0c;推荐8G显存的GPU&#xff0c;至少需要20G的存储空间&#xff0c;所有对电脑的配置要求是不小的挑战。 我所使用电脑的硬件配置&#xff1a;3…