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

 目录

前言

基数排序

算法思想

​编辑

算法示例

代码实现

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)
  • 基数排序是稳定的

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

 分享一张壁纸:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序如何禁止指定用户访问?如何设置指定用户才能访问?

​有些商家为了价格保密或者实行严格的会员制等原因&#xff0c;希望小程序能够限制某些人的访问或者设置指定人员才能访问。这种功能在小程序中&#xff0c;怎么支持这些功能呢&#xff1f;下面具体介绍。 一、禁止指定用户访问 禁止指定用户访问&#xff0c;可以通过小程序…

【三极管锯齿波电路】2022-3-23

缘由以晶体管作恒流源的锯齿波电路工作原理? - 24小时必答区

【数据结构】树与二叉树(廿六):树删除指定结点及其子树(算法DS)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲3. 搜索指定数据域的结点4. 删除结点及其左右子树a. 逻辑删除与物理删除b. 算法DSTc. 算法解析d. 代码实现递归释放树算法DS e. 算法测试 5. 代码整合…

基于C#实现三元组

我们知道矩阵是一个非常强大的数据结构&#xff0c;在动态规划以及各种图论算法上都有广泛的应用&#xff0c;当然矩阵有着不足的地方就是空间和时间复杂度都维持在 N2 上&#xff0c;比如 1w 个数字建立一个矩阵&#xff0c;在内存中会占用 1w*1w1 亿的类型空间&#xff0c;这…

【人工智能】Chatgpt的训练原理

前言 前不久&#xff0c;在学习C语言的我写了一段三子棋的代码&#xff0c;但是与我对抗的电脑是没有任何思考的&#xff0c;你看了这段代码就理解为什么了&#xff1a; void computerMove(char Board[ROW][COL], int row, int col) {while (1){unsigned int i rand() % ROW, …

BC76 [NOIP2008]ISBN号码

#include<stdio.h> int main() {char arr[13]; //存放13位的ISBNint i, j;scanf("%s",arr);int s 0;for(i0, j1; i<11; i){if(arr[i] ! -){s (arr[i]-0)*j; //将字符换成int累加&#xff1a;0162……29158j; //执行if的时候加&#xff0c;不执行不加…

Linxu 进程替换

进程替换的背景&#xff1a; 进程的替换我们需要调用execl这个接口,exxecl在3号手册&#xff0c;属于系统接口。 调用系统命令 execl 为了方便理解execl的作用&#xff0c;我们写一个程序&#xff1a; 单进程替换 我们发现运行结果是通过c库里的exec接口把系统命令 "l…

【深度学习】DAMO-YOLO,阿里,701类通用检测模型,目标检测

https://github.com/tinyvision/DAMO-YOLO/blob/master/README_cn.md DAMO-YOLO是由阿里巴巴达摩院智能计算实验室TinyML团队开发的一个兼顾速度与精度的目标检测框架,其效果超越了目前的一众YOLO系列方法&#xff0c;在实现SOTA的同时&#xff0c;保持了很高的推理速度。DAMO…

Error PostCSS plugin autoprefixer requires PostCSS 8

文章目录 一、情况一二、情况二三、总结 在启动 vue项目时&#xff0c;突然控制台报错&#xff1a; Error: PostCSS plugin autoprefixer requires PostCSS 8。然后依次出现下面几种情况&#xff0c;依次解决完&#xff0c;项目就可以正常启动了 一、情况一 error in ./src/…

【涂鸦T2-U】1、开发环境搭建

前言 本章介绍T2-U的开发环境搭建流程&#xff0c;以及一些遇到的问题。 一、资料 试用网址&#xff1a; 【新品体验】涂鸦 T2-U 开发板免费试用 涂鸦官网文档&#xff1a; 涂鸦 T2-U 开发板 T2-U 模组规格书 T2-U 开发板 淘宝(资料较全)&#xff1a; 涂鸦智能 TuyaOS开发…

软件测试职业规划导图

公司开发的产品专业性较强&#xff0c;软件测试人员需要有很强的专业知识&#xff0c;现在软件测试人员发展出现了一种测试管理者不愿意看到的景象&#xff1a; 1、开发技术较强的软件测试人员转向了软件开发(非测试工具开发)&#xff1b; 2、业务能力较强的测试人员转向了软件…

基于单片机的肺活量检测系统(论文+源码)

1.系统设计 在基于单片机的肺活量检测系统中&#xff0c;在硬件上整个系统通过利用主控制器STC89C52单片机来实现对整个系统进行控制的功能&#xff0c;通过采用LCD1602实现实时液晶显示数据的功能&#xff0c;通过肺活量传感器XGZP6847ADC0832实现监测肺活量的工作&#xff0…

ESP32网络开发实例-远程Web串口监视器

远程Web串口监视器 文章目录 远程Web串口监视器1、应用介绍2、软件准备3、硬件准备4、代码实现在本文中,我们将构建一个 ESP32 网络服务器,用作远程串行监视器。 基于 Web 的串行监视器的工作方式与通常用于调试目的的 Arduino IDE 串行监视器的工作方式相同。 1、应用介绍 …

系列十六、Spring IOC容器的扩展点

一、概述 Spring IOC容器的扩展点是指在IOC加载的过程中&#xff0c;如何对即将要创建的bean进行扩展。 二、扩展点 2.1、BeanDefinitionRegistryPostProcessor 2.1.1、概述 BeanDefinitionRegistryPostProcessor是bean定义的后置处理器&#xff0c;在BeanDefinition加载后&a…

cesium轨迹线(闪烁轨迹线)

cesium轨迹线(闪烁轨迹线) 下面有源码 实现思路 使用ellipse方法加载圆型,修改polyline中‘material’方法重写glsl来实现当前效果(cesium版本1.109) 示例代码 index.html <!DOCTYPE html> <html lang="en"><head

MyBatis框架_01

Web后端开发_03 MyBatis框架 什么是MyBatis? MyBatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发。MyBatis本是 Apache的一个开源项目iBatis&#xff0c;2010年这个项目由apache迁移到了google code&#xff0c;并且改名为MyBatis 。2013年11月迁移到Github。官网…

基于Pytest+Requests+Allure实现接口自动化测试

一、整体结构 框架组成&#xff1a;pytestrequestsallure 设计模式&#xff1a; 关键字驱动 项目结构&#xff1a; 工具层&#xff1a;api_keyword/ 参数层&#xff1a;params/ 用例层&#xff1a;case/ 数据驱动&#xff1a;data_driver/ 数据层&#xff1a;data/ 逻…

crontab计划任务

银河麒麟v10服务器版和桌面版执行周期计划任务分为两类&#xff1a;系统任务调度和用户任务调度。系统任务是由 cron (crond) 这个系统服务来控制的&#xff0c;这个系统服务是默认启动的&#xff0c;通过vim /etc/crontab执行。用户自己设置的计划任务则使用crontab 命令 配置…

SpringMVC系列-7 @CrossOrigin注解与跨域问题

背景 前段时间帮同事分析了一个跨域问题&#xff0c;正好系统分析和整理一下。 1.跨域 理解同源策略是理解跨域的前提。同源策略定义如下&#xff1a; 在同一来源的页面和脚本之间进行数据交互时&#xff0c;浏览器会默认允许操作&#xff0c;而不会造成跨站脚本攻击&#x…

柑橘病害数据集(四类图像分类,没有打yolo标签)

1.文件夹分为训练集和测试集 在这个数据集中&#xff0c;有一类是新鲜柑橘&#xff0c;还有另外三种疾病&#xff0c;溃疡病、黑斑病和绿化病。 2.train文件夹 2.1.blackspot&#xff08;黑斑病&#xff09; 文件夹 206张照片 2.2.canker&#xff08;溃疡病&#xff09; 文…