快排(非递归)及计数排序算法

news2024/10/7 20:27:16

都学了递归版的快速排序为何还要再学非递归实现?由于在递归过程中,如果数据量过大,那么实现时容易导致栈溢出,虽然代码没有问题,但是就是会崩,因此要将其改为非递归来实现

文章目录

  • 一、快速排序(非递归)
  • 二、计数排序


一、快速排序(非递归)

如何做到将递归算法改为非递归算法?

简单的递归可以直接将其改为循环(如斐波那契),但是如果是复杂的递归算法,再直接改为循环十分复杂,而一般选用栈辅助将其改为非递归

再来回顾一下快速排序的思想。

思想:在区间范围内选出一个关键字,经过单趟排序之后关键字位置左边的数据全小于或者等于它,关键字右边的数据全大于或者等于它。一趟排序将这个关键字排好了,同样也分隔出了它的左区间和右区间,再以同样的方法排它的左区间和右区间,直至区间范围为1或者不存在为止

而递归实现快速排序是每次控制的是区间,每次递归调用栈都是将区间压栈,每递归一次,区间都在变化。因此用栈实现快速排序时,入栈的是区间,而由于每次递归都是先排的左区间,而栈是一种后进先出的数据结构,所以在将区间入栈时要先将右区间压栈,然后再将左区间压栈,保证每次单趟排先将左区间排好再排右区间
在这里插入图片描述

单趟排。排出keyi此时分隔出keyi的左右区间,然后把他的左、右区间压栈,此时又对它的左右区间进行单趟排,排出keyi,分隔左右区间,每次单趟排完后会分隔出左右区间,然后左右区间入栈,直至最后区间为1或者不存在时,就不用再入栈了。总体是:

  1. 从栈中取一段区间,进行单趟排。
  2. 单趟排序后分隔子区间(左、右区间)入栈。
  3. 子区间只有一个值或者不存在就不入栈了
    在这里插入图片描述

每一次单趟排是如何排的,这里用前后指针法实现,每次单趟排好后,返回关键字所在下标

那么用栈辅助改递归,这个栈从和而来,我这里是以前写好了,保存下来的,在vs中只需要选中源文件
在这里插入图片描述
然后点击鼠标右键找到
在这里插入图片描述
找到以前保存栈实现的文件,将其拷贝
之后再点击源文件
在这里插入图片描述
再点击在这里插入图片描述

在这里插入图片描述
以前是新建但是现在是点击现有,然后找到当前程序所在目录,将刚才拷贝的栈实现的文件拷贝到当前程序中即可。

前后指针法排单趟

//前后指针法
int QuickSort3(int* a, int left, int right)
{
	
	int begin = left;
	int end = right;
	

	//随机选数,主要针对已经有序的情况,提高性能
	int randi = left + (rand() % (right - left));
	if (randi != left)
	{
		Swap(&a[randi], &a[left]);
	}

	int key = left;
	int cur = left + 1;
	int prev = left;

	while (cur <= right)
	{
		if (a[cur] < a[key] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}

	Swap(&a[key], &a[prev]);
	key = prev;
	return key;
	
}

//取区间入栈然后对其单趟排,单趟排好keyi之后分割出它的子区间,将分割出的子区间入栈,再进行单趟排,再分割子区间入栈,每次单趟排排好一个数,直至区间范围为一或者不存在
//
void QuicksortNone(int* a, int begin, int end)
{
	St st;
	STInit(&st);
	STPush(&st, end);
	STPush(&st, begin);

	while (!STEmpty(&st))
	{
		int begin1 = STTop(&st);
		STPop(&st);
		int end1 = STTop(&st);
		STPop(&st);
		int keyi = QuickSort3(a, begin1, end1);

		if (keyi + 1 < end1)
		{
			STPush(&st, end1);
			STPush(&st, keyi+1);
		}

		if (keyi > begin1)
		{
			STPush(&st, keyi - 1);
			STPush(&st, begin1);
		}
	}
	STDestroy(&st);
}

在这里插入图片描述
非递归快速排序时间复杂度O(nlogn),空间复杂度o(1)

二、计数排序

适用于数组存在大量重复数据且最大值和最小值之差不是特别大的情况
思想:统计数组中每个数据出现的次数,怎么统计?用一个新数组存储原数组数据出现的次数 。 这个数组如何来?当然是向内存动态申请开辟
新数组开辟多大空间合适?
由于存的是原数组数据出现次数,那么只需要数组数据值出现一次,那么它对应值作为下标的值就加一(开辟的数组内容全部初始化为0)
只要数组中的值出现一次,那么它对应的值作为新数组下标所对应的值就加一,那么新数组范围如何确定?
其实也就是原数组最大值与最小值之差,由于用原数组值作为下标 所以先遍历一遍找出数组中的最大值和最小值,这时确定新数组开辟大小
在这里插入图片描述

由于存储从0开始,所以需要原数组值减去它的最小值 最后将新开辟数组的下标再加上原数组最小值就可以直接覆盖原数组,如何覆盖的?
在这里插入图片描述

void CountSort(int* a, int n)
{
	int max = a[0], min = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] > max)
		{
			max = a[i];
		}

		if (a[i] < min)
		{
			min = a[i];
		}
	}

	int range = max - min + 1;//要包含0,所以这个存储数组大小要开最大值和最小值之差再加一

	//开一个数组用来统计数组数据出现的次数
	int* countA = (int*)malloc(sizeof(int) * range);
	if (countA == NULL)
	{
		perror("ocuntA fail\n");
		return;
	}
	//将新开的这个数组内容全部都初始化为0
	//由于它存储的内容是原数组数据出现的次数
	memset(countA, 0, sizeof(int) * range);//c语言内置库函数将每个字节都初始化为0

	//以原数组中的数据作为新开数组的下标,然后统计它出现的次数
	//由于原数组最小值很可能不是从0开始
	//而新数组要从0开始存储
	//所以新数组下标是a[i] - min这个表达式
	for (int i = 0; i < n; i++)
	{
		//将原数组内容它对应的数字为countA下标加加,即数组对应数据在数组中出现的次数
		countA[a[i]-min]++;
	}

	int j = 0;
	for (int i = 0; i < n; )//i<n后面的调整不可再加,原因是下面加了,如果再加会造成越界
	{
		//可以在这里做出调整,将其i--,但是这里多此一举
		while (countA[j]--)
		{
			a[i++] = j + min;
		}
		j++;
	}

	free(countA);
}

在这里插入图片描述


计数排序时间复杂度为O(n+range)当range<n时,时间复杂度为O(n),空间复杂度为O(range),但是它的条件十分苛刻,需要很多重复数据且这些数据最大值和最小值之差不可过大,所以在现实生活中很少用到,但是在有些场景下会用到,所以还是值得一学,毕竟时间复杂度为线性的嘛。

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

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

相关文章

如何使用Mac远程控制Windows电脑?

在你开始之前&#xff0c;设置您要远程处理的 Windows 计算机。 先安装 Microsoft Remote Desktop。 您可以在“应用程序”文件夹中检查它。 如果在个人计算机上安装&#xff0c;请转到 Apple App Store 并下载 Microsoft Remote Desktop。 如果在 TXST 计算机上安装&#xff0…

【C语言】递归解决经典题目(汉诺塔问题、青蛙跳台阶问题)

简单不先于复杂&#xff0c;而是在复杂之后。 目录 1. 汉诺塔问题 1.1 简介及思路 1.2 代码实现 2. 青蛙跳台阶问题 2.1 简介及思路 2.2 代码实现 1. 汉诺塔问题 1.1 简介及思路 汉诺塔问题是一种经典的递归问题&#xff0c;起源于印度传说中的塔 of Brahma。问题描…

手把手教你学习IEC104协议和编程实现 十 故障事件与复位进程

故障事件 目的 在IEC104普遍应用之前,据我了解多个协议,再综合自动化协议中,有这么一个概念叫“事故追忆”,意思是当变电站出现事故的时候,不但要记录事故的时间,还需记录事故前后模拟量的数据,从而能从一定程度上分析事故产生的原因,这个模拟量就是和今天讲解的故障…

silvaco 仿真BJT

本次实验为利用silvaco仿真BJT器件&#xff0c;分析不同p区厚度以及p区不同掺杂浓度研究其电流增益的变化。 一、器件要求 区域 掺杂方式 掺杂浓度或 峰值浓度&#xff08;/cm3&#xff09; 厚度&#xff08;um&#xff09; 宽度&#xff08;um&#xff09; N-漂移区 均匀…

微服务框架【笔记-Nacos注册中心】

接上篇&#xff0c;继续学习微服务框架中的Nacos注册中心。 Nacos注册中心 一、认识和安装Nacos 1.认识Nacos Nacos 是阿里巴巴的产品&#xff0c;现在是 SpringCloud 中的一个组件。相比 Eureka 功能更加丰富。 2.安装Nacos 下面给大家展示windows安装Nacos步骤&#xff1a;…

网络互联技术与实践教程(汪双硕、姚羽)——第四章 路由技术

第四章 路由技术 4.1 路由原理 路由是指通过相互连接的网络将数据从源地点转发到目标地点的过程。在路由过程中&#xff0c;数据通常会经过一个或多个中间节点&#xff0c;路由发生在网络层。路由包含两个主要的动作&#xff1a;确定最佳路径和通过网络传输信息&#xff0c;后…

刷题笔记【6】| 快速刷完67道剑指offer(Java版)

本文已收录于专栏&#x1f33b;《刷题笔记》文章目录前言&#x1f3a8; 1、包含min函数的栈题目描述思路&#xff08;双栈法&#xff09;&#x1f3a8; 2、栈的压入弹出序列题目描述思路&#xff08;辅助栈&#xff09;&#x1f3a8; 3、从上往下打印二叉树题目描述思路&#x…

chapter-4-数据库语句

以下课程来源于MOOC学习—原课程请见&#xff1a;数据库原理与应用 考研复习 概述 SQL发展 注&#xff1a;关键词是哪些功能&#xff0c;尤其第一个create alter drop是定义功能 1.SQL功能强大&#xff0c;实现了数据定义、数据操纵、数据控制等功能 2.SQL语言简洁&#xff…

【Java版oj】day26跳台阶扩展问题、快到碗里来

目录 一、跳台阶扩展问题 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、快到碗里来 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 一、跳台…

tomcat配置虚拟路径映射磁盘文件列表图片回显和放大功能实现springboot项目的文件虚拟路径映射

tomcat映射磁盘图片1.以E盘为例&#xff0c;在E盘创建目录testReceive2.配置tomcat虚拟路径映射e盘本地文件3.代码层面创建上传文件&#xff08;此处为图片&#xff09;工具类3.1&#xff08;校验图片格式、获取当前主机ip、上传图片至本机目的地&#xff0c;获取上传图片地址&…

javaWeb(HTTP、Tomcat、Servlet)

目录 HTTP Web 服务器 - Tomcat 简介 基本使用&#xff1a;下载、安装、卸载、启动、关闭、配置、部署项目 IDEA中创建 Maven Web项目​编辑 IDEA中使用 Tomcat Servlet 快速入门 Servlet 执行流程 Servlet 生命周期 Servlet 体系结构 Servlet urlPattern配置 XM…

【从零开始学Skynet】实战篇《球球大作战》(五):gateway代码设计(中)

1、编码和解码 我们来实现两个辅助方法str_unpack和str_pack&#xff0c;用于消息的解码和编码。 &#xff08;1&#xff09;str_unpack代码 local str_unpack function(msgstr)local msg {}while true dolocal arg, rest string.match( msgstr, "(.-),(.*)")if…

【web自动化测试】

文章目录web自动化测试第一章 web自动化入门1.什么是自动化&#xff1f;1.1 优点2.什么是自动化测试&#xff1f;2.1 自动化测试能解决什么问题&#xff1f;2.2 自动化相关知识2.2.1优点2.2.2 误区2.3 自动化测试分类3.什么是Web自动化测试&#xff1f;3.1 什么Web项目适合做自…

Flutter 了解 Element

一 Element 概念 这个玩意的概念。到底是什么 &#xff1f; 官方解释是在树中特定位置的实例。 二 继承关系 element 有 ComponentElement 和 RenderObjectElement 之分 1 ComponentElement class StatelessElement extends ComponentElement class StatefulElement extend…

计及调度经济性的光热电站储热容量配置方法

目录 1 主要内容 目标函数 光热电站能量传递过程 2 部分程序 3 程序结果 4 程序链接 1 主要内容 该程序复现《计及调度经济性的光热电站储热容量配置方法》模型&#xff0c;综合考虑火电机组发电成本、光热发电并网消纳的环境效益和运行维护成本、系统旋转备用成本等调度…

rk3568点亮LCD(RGB)

rk3568 Android11/12 调试 RGB 屏 RGB一般是指RGB色彩模型(RGB color model)&#xff0c;是工业界的一种颜色标准。RGB接口占用的资源较多&#xff0c;所以这个接口的LCD刷新率非常快&#xff0c;软件控制也比较简单。缺点是控制需要增加电路&#xff0c;软件初始化需要增加程…

【BOM浏览器对象模型】

BOM浏览器对象模型1 本节目标2 BOM概述3 window对象的常见事件3.1 窗口加载事件3.2 调整窗口大小事件4 定时器4.1 两种定时器4.2 setTimeout()定时器4.3 停止setTimeout()定时器4.4 setInterval()定时器4.5 停止setInterval()定时器4.6 this指向问题5 JS执行队列5.1 JS是单线程…

BUUCTF-.htaccess-sql.fuzz-D盾

第七周第一次 目录 WEB [MRCTF2020]你传你&#x1f40e;呢 ​编辑 [极客大挑战 2019]HardSQL Crypto 萌萌哒的八戒 传统知识古典密码 Misc 假如给我三天光明 后门查杀 WEB [MRCTF2020]你传你&#x1f40e;呢 文件上传 我们进行尝试 设置一个 1.jpg的一句话木马 G…

RabbitMQ之高级特性

文章目录一、消息确认机制&#x1f389;1.1 消息发送确认(生产者)&#x1f539;confirm 确认模式&#x1f539;return 回退模式&#x1f6a9;1.2 消息接收确认(消费者)&#x1f538;none 自动确认&#x1f538;auto 异常确认&#x1f538;manual 手动确认二、消费端限流 (prefe…

创略科技联合创始人兼总裁杨辰韵:AIGC、隐私计算赋能数字营销的本质是“以客户为中心”丨数据猿专访...

‍数据智能产业创新服务媒体——聚焦数智 改变商业MarTech概念现身已超十年&#xff0c;伴随着企业数字化转型的大背景&#xff0c;中国MarTech市场也迎来了高速发展。据《2022年中国MarTech市场洞察报告》数据显示&#xff0c;2017-2021年&#xff0c;中国 MarTech产业规模从…