排序算法-----基数排序

 目录

前言

基数排序

算法思想

​编辑

算法示例

代码实现

1.队列queue.h 头文件

2.队列queue.c 源文件 

 3.主函数(radix_sort实现)

算法分析


前言

        今天我想把前面未更新完的排序算法补充一下,也就是基数排序的一种,这是跟计数排序一样类型的排序算法,是属于非比较型的排序算法,下面我们就一起来看看吧。

基数排序

        基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机 (Tabulation Machine)上的贡献。它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。 基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

算法思想

 上面这些理论思想看上去不太好理解,那下面我举个例子去简单解释一下。

算法示例

比如有这么一个数组 array = {53, 3, 542, 748, 14, 214, 154, 63, 616}  现在要去进行基数排序。

这里我们需要去创建一个长度为10的队列数组。Queue que[10]。然后这个队列数组作为根据基数储存数据的队列表。

这里,我们对数组中的每一个数字去进行遍历,然后进行按位求余,最先是个位数,得到的结果,根据对应的队列数组下标去进行入队操作。基数分配结果如下所示:

第一次基数分配(根据个位数分配)

que[0]----->NULL

que[1]----->NULL

que[2]----->542----->NULL

que[3]----->53------>3----->63----->NULL

que[4]----->14----->214----->154----->NULL

que[5]----->NULL

que[6]----->616----->NULL

que[7]----->NULL

que[8]----->748----->NULL

que[9]----->NULL

然后根据第一次基数计算出的结果,重新去排放这个数组,对这个队列表进行遍历(从上到下),然后出队操作,出队的结果放入到数组当中,第一次数组更新结果如下:

[ 542, 53, 3, 63, 14, 214, 154, 616, 748 ]

 第二次基数分配(根据十位数分配)

在进行第二次分配的时候,我们就根据上面已经跟新好了的数组去重新分配,这一次我们就要去进一位来分配。结果如下:

que[0]----->3----->NULL

que[1]----->14----->214----->616----->NULL

que[2]----->NULL

que[3]----->NULL

que[4]----->542----->748----->NULL

que[5]----->53----->154----->NULL

que[6]----->63----->NULL

que[7]----->NULL

que[8]----->NULL

que[9]----->NULL

根据第二次基数计算出的结果,重新去排放这个数组,对这个队列表进行遍历(从上到下),然后出队操作,出队的结果放入到数组当中,第二次数组更新结果如下: 

 [ 3, 14, 214 ,616, 542, 748, 53, 154, 63  ]

  第三次基数分配(根据百位数分配)

我们接着取上面第二次分配的数组结果,然后再次根据百位数求余数分配。结果如下:

que[0]----->3----->14----->53----->63----->NULL

que[1]----->154----->NULL

que[2]----->214----->NULL

que[3]----->NULL

que[4]----->NULL

que[5]----->542----->NULL

que[6]----->616----->NULL

que[7]----->748----->NULL

que[8]----->NULL

que[9]----->NULL

 根据第三次基数计算出的结果,重新去排放这个数组,对这个队列表进行遍历(从上到下),然后出队操作,出队的结果放入到数组当中,第三次数组更新结果如下:

 [ 3, 14, 53, 63, 154, 214, 542, 616, 748 ]

这里我们可以看出,已经拍好序了,但是我建议还是继续去第四次分配,直到全部的数字都在队列que[0]上。 

第四次基数分配(根据千位数分配)

同样的,这里我们把基数再进一位

que[0]----->3----->14----->53----->63----->154----->214----->542----->616----->748----->NULL

que[1]----->NULL

que[2]----->NULL

que[3]----->NULL

que[4]----->NULL

que[5]----->NULL

que[6]----->NULL

que[7]----->NULL

que[8]----->NULL

que[9]----->NULL

 此时的全部数字都在第一个队列上,这时候就完成了排序,只需要去对这个队列进行出队,然后把数据重新放入到数组当中,结果如下,至此,排序结束。

  [ 3, 14, 53, 63, 154, 214, 542, 616, 748 ]

 整体分配过程:

  • 假设r是排序码的基数,d是排序码的位数每位的类型是KeyType
  • 待排序的文件采用带表头结点的链表表示,类型为RadixList
  • 口为了便于实现记录的分配和收集,建立r个链表表示的队列,每个队列的类型为Queue

动态图:

代码实现

1.队列queue.h 头文件
#pragma once
#include<stdlib.h>//数据类型
typedef int Datatype;//节点
typedef struct node {Datatype data;struct node* next;
}Lnode;
//队列
typedef struct queue {int curnum;Lnode* front, * rear;
}Queue;//队列初始化
void queue_init(Queue* que);
//判空
int isEmpty(Queue q);
//入队列
void enqueue(Queue *que, Datatype data);
//出队列
Lnode* dequeue(Queue* que);
//获取队头元素
Datatype get_headdata(Queue que);
2.队列queue.c 源文件 
#include"queue.h"
#include<assert.h>//队列初始化
void queue_init(Queue* que) {que->curnum = 0;que->front = que->rear = NULL;
}//创建一个节点
Lnode* create_node(Datatype data) {Lnode* node = (Lnode*)malloc(sizeof(Lnode));assert(node);node->data = data;node->next = NULL;return node;
}//判空
int isEmpty(Queue q) {return q.curnum == 0;
}//入队列
void enqueue(Queue *que,Datatype data) {Lnode* add = create_node(data);if (isEmpty(*que)) {que->front = que->rear = add;que->curnum++;}else {que->rear->next = add;que->rear = add;que->curnum++;}
}//出队列
Lnode* dequeue(Queue *que) {if (isEmpty(*que))return NULL;if (que->curnum == 1)que->rear = NULL;Lnode* de = que->front;que->front = de->next;que->curnum--;return de;
}//获取队头元素
Datatype get_headdata(Queue que) {return que.front->data;
}
 3.主函数(radix_sort实现)
#include<stdio.h>
#include<stdlib.h>
#include"queue.h"void radix_sort(int* arr, int n) {Queue que[10];//创建下标为0~9的队列for (int i = 0; i < 10; i++) {queue_init(&que[i]);//初始化队列}for (int i = 0; i < n; i++) {enqueue(&que[arr[i] % 10], arr[i]);//把数组个位数的数字依次入队}int k = 0;int count = 10;while (que[0].curnum != n) {//如果数字里面全部的数据到第0个队列的时候就结束for (int i = 0; i < 10; i++) {while (!isEmpty(que[i])) {Lnode* pop = dequeue(&que[i]);//出队arr[k++] = pop->data;//重新放置数组//释放空间free(pop);pop = NULL;}}k = 0;for (int i = 0; i < n; i++) {//除以count取整,此时指向进一位数字,进行入队操作int x = arr[i] / count;enqueue(&que[x % 10], arr[i]);}count *= 10;//}
}int main() {int array[] = { 123,0, 25,24,6,65,11,43,22,51 ,999 };printf("排序前:");for (int i = 0; i < sizeof(array) / sizeof(int); i++) {printf("%d ", array[i]);}//基数排序radix_sort(array, sizeof(array) / sizeof(int));printf("\n排序后:");for (int i = 0; i < sizeof(array) / sizeof(int); i++) {printf("%d ", array[i]);}
}

输出结果:

算法分析

  • 基数排序算法中,时间主要耗费在修改指针上一趟排序的时间为O(r+n),总共要进行d趟排序,基数排序的时间复杂度T(n) = O(d*(r+n))采用链表存储,排序时只修改链接指针,操作效率不受记录的信息量大小的影响
  • 排序中每个记录中增加了一个next字段(链表指针),还增加了一个queue 数组,故辅助空间S(n) = O(n+r)
  • 基数排序是稳定的

以上就是本期的全部内容了,我们下次见咯~

 分享一张壁纸:

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

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

相关文章

ubuntu 使用webrtc_ros 编译linux webrtc库

ubuntu 使用webrtc_ros 编译linux webrtc库 webrtc_ros 使用WebRTC流式传输ROS图像主题 该节点提供了一个WebRTC对等方&#xff0c;可以将其配置为流ROS图像主题并接收发布到ROS图像主题的流。 该节点托管一个提供简单测试页面的Web服务器&#xff0c;并提供可用于创建和配置W…

基于Vue+SpringBoot的APK检测管理系统

项目编号&#xff1a; S 038 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S038&#xff0c;文末获取源码。} 项目编号&#xff1a;S038&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 开放平台模块2.3 软…

电子学会C/C++编程等级考试2021年09月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:字符统计 给定一个由a-z这26个字符组成的字符串,统计其中哪个字符出现的次数最多。输入 输入包含一行,一个字符串,长度不超过1000。输出 输出一行,包括出现次数最多的字符和该字符出现的次数,中间以一个空格分开。如果有多…

Python入门03变量

目录 1 什么是变量2 变量声明3 变量命名规则4 变量类型5 类型转换总结 1 什么是变量 编程语言中变量就像容器一样&#xff0c;可以用来存放东西 我的变量就像杯子一样&#xff0c;可以用来盛放各种饮料。在Python中变量用来存放各种各样的数据&#xff0c;比如整数、浮点数、…

【计算机网络】HTTP 协议

文章目录 前言什么是 HTTP理解 HTTP 请求和响应格式HTTP 的请求格式1. 首行2. 请求头3. 空行4. 正文&#xff08;body&#xff09; HTTP 的响应格式1. 首行2. 响应头3. 空行4. 正文&#xff08;body&#xff09; 首行GET 和 POST 方法有什么区别针对 GET 方法和 POST 方法的区别…

ubuntu挂载硬盘方法

1.关闭服务器加上新硬盘 2.启动服务器&#xff0c;以root用户登录 3.查看硬盘信息 fdisk -l4.格式化分区 找到需要分区的目录,并记录分区的uuid&#xff0c;用于后面修改/etc/fstab永久挂载配置文件 mkfs.ext4 /dev/nvme0n1 mkfs.ext4 /dev/nvme1n1 Filesystem UUID: a1c…

【C++】构造函数和析构函数第四部分(深拷贝和浅拷贝)--- 2023.11.25

目录 什么是浅拷贝&#xff1f;浅拷贝的问题使用深拷贝解决浅拷贝问题结束语 什么是浅拷贝&#xff1f; 如果在一个类中没有人为定义拷贝函数&#xff0c;则系统会提供默认拷贝函数。那么在此默认拷贝函数中主要进行了简单的赋值操作&#xff0c;那这个简单的赋值操作我们一般…

STM32-使用固件库新建工程

参考链接: 【入门篇】11-新建工程—固件库版本&#xff08;初学者必须认认真真看&#xff09;_哔哩哔哩_bilibili 使用的MCU是STM32F103ZET6 。 这篇参考的是野火的资料&#xff0c;可以在“野火大学堂”或者它的论坛上下载。&#xff08;我通常是野火和正点原子的资料混着看的…

leetCode 226.翻转二叉树 递归 + 非递归 + 前中后序 + 层序遍历 【深度和广度优先遍历】

我的往期文章&#xff1a; leetCode 226.翻转二叉树-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/134613347?spm1001.2014.3001.5501 &#xff08;一&#xff09;递归做法&#xff08;深度&#xff09; C代码&#xff1a;前序遍历 class Solution { pu…

java spring-boot 修改打包的jar包名称

修改pom文件 <finalName>lzwd</finalName><build><finalName>lzwd</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plu…

【模型融合】集成学习(boosting, bagging, stacking)原理介绍、python代码实现(sklearn)、分类回归任务实战

文章目录 概览boostingbaggingStacking投票平均Stack 代码实现1. 分类1.0 数据集介绍1.1 boosting1.2 bagging1.3 stacking 2. 回归2.0 数据集介绍stacking 概览 简单来说&#xff0c;集成学习是一种分类器结合的方法&#xff08;不是一种分类器&#xff09;。 宏观上讲集成学…

如何搭建zerotier服务器组网实现内网穿透

小白花了四天的下班时间终于把zerotier网络调通&#xff0c;此刻坐在桌前舒畅地喝口茶&#xff5e;&#xff5e; 下面来详细记录下这几天踩的坑&#xff1a; 起因就在于一直在iPad上用向日葵连接公司电脑的我觉得向日葵的界面用的实在难受&#xff0c;vs code操作十分不灵光&…

LemMinX-Maven:帮助在eclipse中更方便地编辑maven的pom文件

LemMinX-Maven&#xff1a;https://github.com/eclipse/lemminx-maven LemMinX-Maven可以帮助我们在eclipse中更方便地编辑maven工程的pom.xml文件&#xff0c;例如补全、提示等。不用单独安装&#xff0c;因为在安装maven eclipse插件的时候已经自动安装了&#xff1a; 例…

记一次简单的PHP反序列化字符串溢出

今天朋友给的一道题&#xff0c;让我看看&#xff0c;来源不知&#xff0c;随手记一下 <?php // where is flag error_reporting(0); class NFCTF{ public $ming,$id,$payload,$nothing;function __construct($iii){$this->ming$ii…

QT已有项目导入工程时注意事项

文章目录 从qt其他版本上开发的工程导入另一qt版本时 从qt其他版本上开发的工程导入另一qt版本时 这里以之前在qt5.12.2上开发的项目为例&#xff0c;现在到在qt6.5.3上运行。 不能直接导入IDE上&#xff0c;否则会报各种莫名奇妙的错误。 首先要把扩展名位.pro.user文件 删掉…

linux开启apache服务

vim /etc/apache2/ports.conf 键盘输入i 进入插入编辑模式&#xff0c;修改apache2默认监听端口号为8080 &#xff0c;编辑好后&#xff0c;按Esc键“&#xff1a;wq!” 保存退出。&#xff08;注&#xff1a;端口也可以不修改&#xff09; 在终端输入“/etc/init.d/apache2 …

01_MySQL介绍及安装

#任务背景 一、真实案例 某公司现在有几套不同版本的MySQL数据库&#xff0c;现在大部分的生产和测试环境都已经切换到5.7版本&#xff0c;由于历史原因&#xff0c;有一套测试环境版本为MySQL-5.5。现为了将测试环境版本统一&#xff0c;需要将原来测试环境数据库MySQL-5.5版…

B/S前后端分离的Java医院云HIS信息管理系统源码(LIS源码+电子病历源码)

HIS系统采用主流成熟技术开发&#xff0c;软件结构简洁、代码规范易阅读&#xff0c;SaaS应用&#xff0c;全浏览器访问前后端分离&#xff0c;多服务协同&#xff0c;服务可拆分&#xff0c;功能易扩展。多医院、多集团统一登录患者主索引建立、主数据管理&#xff0c;统一对外…

RPC和HTTP的区别

目录 1、RPC是什么 1.1 概念 1.2 RPC的组成部分 1.3 常见的 RPC 技术和框架 1.4 RPC的工作流程 2、HTTP是什么 2.1 概念 2.2 HTTP的消息格式 2.3 HTTP响应状态码有哪些 3、⭐RPC和HTTP的区别 小结 1、RPC是什么 1.1 概念 RPC&#xff08;Remote Procedure Call&am…

YOLOv8改进 | 2023 | FocusedLinearAttention实现有效涨点

论文地址&#xff1a;官方论文地址 代码地址&#xff1a;官方代码地址 一、本文介绍 本文给大家带来的改进机制是Focused Linear Attention&#xff08;聚焦线性注意力&#xff09;是一种用于视觉Transformer模型的注意力机制(但是其也可以用在我们的YOLO系列当中从而提高检测…