数据结构【初阶】--排序(归并排序和基数排序)

news2024/12/29 10:28:33

目录

一.归并排序的非递归写法

1.思想应用 

2.代码基本实现 

(1)单趟归并逻辑 

(2)多趟(循环)的控制条件

① 迭代条件:i+=2*gap

② 结束条件:i(或i<=n-2*gap)<>

(3)代码展示 

① 单趟逻辑

②整体逻辑 

3.优化代码 

(1)end1和begin2越界 

(2)begin2不越界而end2越界

 二.计数排序

1.思想应用 

2.(直接映射)逻辑图示 

3.优点以及局限性 

4.针对分散的数据进行优化 

(1)(相对映射)图示解析 

(2)代码实现 


一.归并排序的非递归写法

1.思想应用 

采用思想:一个数肯定是有序的,就每一个数和另一个数归并成一个含有两个数的有序序列,然后一个含有两个数的有序序列在和另一个含有两个数的有序序列归并成一个含有四个数的有序序列,依次类推,最后整体有序。 

  • 图示 

 

2.代码基本实现 

(1)单趟归并逻辑 

  • 图示 

 

(2)多趟(循环)的控制条件

① 迭代条件:i+=2*gap
  • 图示 
② 结束条件:i<n(或i<=n-2*gap)

 

(3)代码展示 

① 单趟逻辑
    int* tmp = (int*)malloc(sizeof(int) * n);//开辟一个新数组
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
    int gap = 1;
	for (size_t i = 0;i<n;i+=2*gap)
	{
		int begin1 = i,end1=i+gap-1;//第一组数据的首尾
		int begin2 = i + gap,end2=i+2*gap-1;//第二组数据的首尾
		//[begin1,end1][begin2,end2]--归并区间
		int j = begin1;
		while (begin1 <= end1 && begin2 <= end2)
		{
            //小数向前调(尾插)
			if (a[begin1] < a[begin2])
			{
				tmp[j++] = a[begin1++];
			}
            //大数向后调(尾插)
			else
			{
				tmp[j++] = a[begin2++];
			}
		}
        //由于上面的begin1和begin2是分别向后走,一定有一个没走完
        //这里控制没走完的继续走
		while (begin1 <= end1)
		{
			tmp[j++] = a[begin1++];
		}

		while (begin2 <= end2)
		{
			tmp[j++] = a[begin2++];
		}
		memcpy(a + i, tmp + i, sizeof(int) *2*gap);//每归并两个数就拷贝回去
	}
	gap *= 2;
  • 效果 

 

②整体逻辑 
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1;
	while (gap < n)//控制多趟
	{
		for (size_t i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			//[begin1,end1][begin2,end2]--归并区间
			int j = begin1;

			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}

			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}

			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + i, tmp + i, sizeof(int) * 2 * gap);//每归并两个数就拷贝回去
		}
		gap *= 2;
	}
	free(tmp);
}
  • 效果演示 

 

  •  存在问题 

此样例给的数组数据个数恰好可以通过测试,但是代码本身存在问题导致其并不适用于所有样例,例如:

 我们观察一下分割的区间来看一看问题所在:

下面对代码进行改进。

3.优化代码 

(1)end1和begin2越界 

由于begin1=i,所以可以判断begin1是不可能越界的,那么越界的就可能是end1和begin2。(这里先不考虑begin2不越界而end2越界的情况。)

  • 解决方式 :发生越界时直接跳出循环
	if (end1 >= n || begin2 >= n)//begin2或end1越界
	{
		break;
	}

(2)begin2不越界而end2越界

  • 解决方式:修改end2的值,并且调整拷贝数据的大小 
//优化部分
if (end1 >= n || begin2 >= n)//begin2或end1越界
{
	break;
}
if (end2 >= n)
{
	end2 = n - 1;
}

memcpy(a + i, tmp + i, sizeof(int) * (end2-i+1));
  • 完整代码 
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1;
	while (gap < n)
	{
		for (size_t i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			//[begin1,end1][begin2,end2]--归并区间
			int j = begin1;
			if (end1 >= n || begin2 >= n)//begin2或end1越界
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] <= a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}

			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}

			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + i, tmp + i, sizeof(int) * (end2-i+1));//每归并两个数就拷贝回去
		}
		gap *= 2;
	}
	free(tmp);
}
  • 效果 

 

 二.计数排序

1.思想应用 

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。

操作步骤

  1. 统计相同元素出现次数
  2. 根据统计的结果将序列回收到原来的序列中 

2.(直接映射)逻辑图示 

 

 

3.优点以及局限性 

优点

  1. 效率极高
  2. 时间复杂度为O(aN+countN(有一个范围))

局限性

1.不适合分散的数据,更适合集中的数据

2.不适合浮点数、字符串、结构体数据排序,只适合整数

4.针对分散的数据进行优化 

(1)(相对映射)图示解析 

 

(2)代码实现 

void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];
		if (a[i] > max)
			max = a[i];
	}
	int range = max - min + 1;//相对映射开的数组大小
	int* count = (int*)calloc(range, sizeof(int));
	if (count == NULL)
	{
		printf("calloc fail\n");
		return;
	}
	//统计次数
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}
	//排序
	int i = 0;
	for (int j = 0; j < range; j++)
	{
		while (count[j]--)
		{
			a[i++] = j + min;//把相对映射还原回去
		}
	}
}
  • 结果 

 

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

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

相关文章

《HTML 简易速速上手小册》第6章:HTML 语义与结构(2024 最新版)

文章目录 6.1 语义化标签的重要性6.1.1 基础知识6.1.2 案例 1&#xff1a;使用 <article>, <section>, <aside>, <header>, 和 <footer>6.1.3 案例 2&#xff1a;构建带有嵌套语义化标签的新闻网站6.1.4 案例 3&#xff1a;创建一个带有 <mai…

HAL库之看门狗

一、看门狗的介绍 &#xff08;1&#xff09;独立看门狗(IWDG)&#xff1a;独立看门狗由专用的低速时钟(LSI)驱动&#xff0c;即使主时钟发生故障它也仍然有效。因此叫独立&#xff0c;同时因此在低功耗模式下不能启动看门狗&#xff0c;低功耗详情见之前文章。IWDG比WWDG更精…

macos Android平台签名证书(.keystore)

一、申请appid的使用说明&#xff08;有appid的请忽略申请appid&#xff09; 创建应用 申请的appid在源码视图填写后会自动生成一个对应的包名 ⚠️注意&#xff1a;申请appid的时候应用名称和项目名称保持一致。 二、 Android如何使用自用证书进行打包 1.找到安装jdk的路径…

D25XB100-ASEMI整流桥D25XB100参数、封装、规格

编辑&#xff1a;ll D25XB100-ASEMI整流桥D25XB100参数、封装、规格 型号&#xff1a;D25XB100 品牌&#xff1a;ASEMI 正向电流&#xff08;Id&#xff09;&#xff1a;25A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;1000V 正向浪涌电流&#xff1a;350A 正向…

win10设置重启自动运行

大家知道windows系列非常不稳定&#xff0c;经常更新&#xff0c;蓝屏&#xff0c;死机等。 所以服务部署在上面会经常挂掉。当他重启后&#xff0c;对应的服务要是没有开启成功就会出问题。 所以我们需要在重启后启动。 1.首先把你想要的执行的程序写一个bat脚本 这个是我的…

C语言第十三弹---VS使用调试技巧

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 VS调试技巧 1、什么是bug 2、什么是调试&#xff08;debug&#xff09;&#xff1f; 3、Debug和Release​编辑​ 4、VS调试快捷键 4.1、环境准备 4.2、调试…

学习Spring的第十二天

Bean基本注解开发 创建一个空Maven项目: 创建完如下 之后在pom文件配置坐标 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.7</version></depe…

翻译: GPT-4 Vision征服LLM幻觉hallucinations 升级Streamlit六

GPT-4 Vision 系列: 翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式一翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式二翻译: GPT-4 Vision静态图表转换为动态数据可视化 升级Streamlit 三翻译: GPT-4 Vision从图像转换为完全可编辑的表格 升级St…

Windows系统安装OpenSSH+VS Code结合内网穿透实现远程开发

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…

Netty-ChannelHandle的业务处理

ChannelHandle结构 ChannelHandler基础接口 基础接口里面定义的基础通用方法。增加handler&#xff0c;移除handler&#xff0c;异常处理。 ChannelInboundHandler public interface ChannelInboundHandler extends ChannelHandler {/*** The {link Channel} of the {link Ch…

学习PyQt5

1、布局之后&#xff0c;无法移动对象到指定区域&#xff0c;无法改变对象大小。 原因&#xff1a;因为CtrlA选中了整个窗口&#xff0c;然后布局的时候就相当于整个窗口都按照这种布局&#xff0c;如选了水平布局&#xff0c;按钮一直在中间&#xff0c;无法拖到其它位置。 …

如何安装配置HFS并实现无公网ip远程访问本地电脑共享文件

文章目录 前言1.下载安装cpolar1.1 设置HFS访客1.2 虚拟文件系统 2. 使用cpolar建立一条内网穿透数据隧道2.1 保留隧道2.2 隧道名称2.3 成功使用cpolar创建二级子域名访问本地hfs 总结 前言 在大厂的云存储产品热度下降后&#xff0c;私人的NAS热度快速上升&#xff0c;其中最…

那些年与指针的情仇(二)---二级指针指针与数组的那点事函数指针

关注小庄 顿顿解馋(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e; 欢迎回到我们的大型纪录片《那些年与指针的爱恨情仇》&#xff0c;在本篇博客中我们将继续了解指针的小秘密&#xff1a;二级指针&#xff0c;指针与数组的关系以及函数指针。请放心食用&a…

【Kafka】服务器Broker与Controller详解

这里写自定义目录标题 Broker概述Broker总体工作流程Broker重要参数 Controller为什么需要Controller具体作用数据服务Leader选举选举流程脑裂问题羊群效应触发leader选举 Broker 概述 Kafka服务实例&#xff0c;负责消息的持久化、中转等功能。一个独立的Kafka 服务器被就是…

[N-135]基于springboot,vue高校图书馆管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;gradle-5.6.4 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatisred…

【HarmonyOS应用开发】ArkUI 开发框架-基础篇-第一部分(七)

常用基础组件 一、组件介绍 组件&#xff08;Component&#xff09;是界面搭建与显示的最小单位&#xff0c;HarmonyOS ArkUI声明式开发范式为开发者提供了丰富多样的UI组件&#xff0c;我们可以使用这些组件轻松的编写出更加丰富、漂亮的界面。组件根据功能可以分为以下五大类…

Web 开发 9:Django 框架基础

在本篇文章中&#xff0c;我们将深入探讨 Django 框架的基础知识。Django 是一个功能强大且流行的 Python Web 框架&#xff0c;它提供了一套完整的工具和功能&#xff0c;用于开发高效、可扩展的 Web 应用程序。 什么是 Django&#xff1f; Django 是一个基于 Python 的免费…

STM32——中断系统和外部中断EXTI

一、中断 1.1中断系统 中断系统是管理和执行中断的逻辑结构&#xff1b; 1.2中断 系统在执行主程序过程中&#xff0c;出现了特定的触发条件&#xff08;触发源&#xff09;&#xff0c;系统停止执行当前程序&#xff0c;转而去执行中断程序&#xff0c;执行完毕后&#xf…

Java基础数据结构之Lambda表达式

一.语法 基本语法&#xff1a;(parameters)->expression或者(parameters)->{statements;} parameters&#xff1a;类似方法中的形参列表&#xff0c;这里的参数是函数式接口里面的参数。这里的参数可以明确说明&#xff0c;也可以不声明而由JVM隐含的推断。当只有一个推…

C++大学教程(第九版)7.30 打印array对象 7.31 逆序打印字符串(递归练习题)

文章目录 题目代码运行截图题目代码运行截图 题目 (打印array对象)编写一个递归函数printArray它以一个array对象一个开始下标和一个结束下标作为实参&#xff0c;不返回任何值并打印这个array对象。当开始下标和结束下标相等时&#xff0c;这个函数应该停止处理并返回。 代码…