C语言快速排序(非递归)图文详解

news2024/11/18 4:41:16

前言:

  上一期分析了快速排序的三种写法,这三种写法有一个相同点,都是采用递归形式来实现的,那么有没有非递归的方法实现呢?答案是当然有,用非递归的方法实现快速排序,其实可以借助数据结构中的栈来模拟实现递归的过程

思路图分析:

  因为使用c语言写的,所以需要我们自己写一个栈,栈的实现我这里不再过多赘述,我会把栈的码放在最后。假如我们现在有下面这组数组,我们要对它进行排序。(注意下面的数字代表下标)

好,接下来开始用栈模拟递归:(图中栈中的数字均表示下标)

1.第一次入栈:

将整个数组入栈,也就是下标为0-8

2.第一次出栈:

每次出栈,对出栈的下标区间进行一次部分排序,这里的部分排序,就是选出key,将其放在正确的位置有3种实现方法,如有不懂可以看我上一期博客,这里我选的是双指针法。第一次出栈进行第一趟部分排序后,数组的元素变为如下图:

此时的key也就是45就被放在了正确的位置,也就是左边的元素都比它小,右边的元素都比它大。

然后再将key的左区间和右区间分别入栈,也就是0-3和5-8

3.第二次出栈:

根据栈的性质后入先出,所以我们让5-8出栈:

跟上面一样,每次出栈对相应区间进行一次部分排序,排序完如下图:

因为在对这个区间进行部分排序时,67被选为key,此时67的右边已经全部比他大,所以排完序后不变,然后再将key的左区间和右区间分别入栈(注意此时的左区间和右区间加起来应该是5-8,因为我们是对5-8这个区间进行部分排序的,而不是0-8),左区间没有元素了也就是4-4,右区间6-8,注意这时候左区间就已经没有必要入栈了(因为少于2个元素必定有序了),只需将没排好序的右区间入栈即可:

4.第二次入栈:

然后只要栈不为空,我们就出栈然后进行和上面一样的操作。

现在就不难感受出,这其实是在模拟递归的过程。

5.第三次出栈:

部分排序后如下图:

跟上面同理左区间少于两个元素不必入栈,右区间入栈7-8

6.第三次入栈:

然后又是7-8出栈,再判断是否入栈,出栈,判断是否入栈,出栈,判断是否入栈一直重复,直到栈里面为空,就排好了,所以循环的使用在这里面也很重要,下面来看一下全部代码吧!

代码:

#include<stdio.h>
#include"Stack.h"

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int PartSort3(int* a, int begin, int end)//双指针法
{
	int keyi = begin;
	int prev = begin;
	int cur = begin + 1;
	while (cur <= end)
	{
		if (a[cur] < a[keyi] && ++prev != a[cur])
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	keyi = prev;
	return keyi;
}

void QuickSortNonR(int* a, int begin, int end)
{
	Stack s;
	StackInit(&s);
	StackPush(&s, end);
	StackPush(&s, begin);//第一次入栈首尾下标
	while (!StackEmpty(&s))//栈只要不为空,就一直出栈,判断是否入栈......
	{
		int left = StackTop(&s);
		StackPop(&s);
		int right = StackTop(&s);
		StackPop(&s);//出栈,首元素下标放在left,尾元素下标放在right,很形象
		int keyi = PartSort3(a, left, right);//进行一次部分排序,并将最后key的下标返回
		//[left,keyi-1]keyi[keyi+1,right]//拆分成的区间
		//下面为判断是否入栈
		if (left < keyi - 1)//如果左区间元素个数不少于2
		{
			StackPush(&s, keyi - 1);
			StackPush(&s, left);//入栈
		}
		if (keyi + 1 < right)//如果右区间元素个数不少于2
		{
			StackPush(&s, right);
			StackPush(&s, keyi+1);//入栈
		}
	}
	//循环结束,栈为空,排序完成
	StackDestroy(&s);//销毁栈
}

栈的实现代码:

#include"Stack.h"
void StackInit(Stack* ps)//初始化栈
{
	ps->a = NULL;
	ps->top = -1;
	ps->capacity = 0;
}
void StackPush(Stack* ps, STDateType data)//入栈
{
	StackCheck(ps);
	ps->top++;
	ps->a[ps->top] = data;
}
void StackCheck(Stack* ps)//检查容量
{
	assert(ps);
	if(ps->top+1==ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDateType* tmp = (STDateType*)realloc(ps->a, sizeof(STDateType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		else
		{
			ps->a = tmp;
			ps->capacity = newcapacity;
		}
	}
}
bool StackEmpty(Stack* ps)//判空函数
{
	return ps->top == -1;
}
STDateType StackTop(Stack* ps)//获取栈顶元素
{
	assert(ps);
	assert(ps->top+1 > 0);
	return ps->a[ps->top];
}
void StackPop(Stack* ps)//出栈
{
	assert(ps);
	ps->top--;
}
int StackSize(Stack* ps)//获取栈中有效元素的个数
{
	assert(ps);
	return ps->top+1;
}
void StackDestroy(Stack* ps)//销毁栈
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = -1;
	ps->capacity = 0;
}

栈的头文件:

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int STDateType;
typedef struct Stack
{
	STDateType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;
void StackInit(Stack* ps);//初始化栈
void StackCheck(Stack* ps);//检查容量
void StackPush(Stack* ps, STDateType data);//入栈
void StackPop(Stack* ps);//出栈
bool StackEmpty(Stack* ps);//判空函数
STDateType StackTop(Stack* ps);//获取栈顶元素
int StackSize(Stack* ps);//获取栈中有效元素的个数
void StackDestroy(Stack* ps);//销毁栈

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

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

相关文章

C++笔记(二)

函数的默认参数 如果我们自己传入数据&#xff0c;就用自己的数据&#xff0c;如果没有&#xff0c;就用默认值 语法&#xff1a; 返回值类型 函数名&#xff08;形参默认值&#xff09;{} int func&#xff08;int a&#xff0c;int b20&#xff0c;int c30&#xff09;{} …

HTTP与HTTPS的工作流程

HTTP与HTTPS的工作流程 http知识点回顾1、HTTP访问的过程2、HTTP常见状态码3、HTTP 协议一共五大特点 https的工作流程1、对称加密2、非对称加密3、https工作流程 http知识点回顾 1、HTTP访问的过程 &#xff08;1&#xff09;解析url&#xff0c;获取 url 中包含的域名&…

Unity3D Pico VR 手势识别物体交互 适配 MRTK3

当前Pico已经支持手势识别了&#xff0c;但是提供的PICO Unity Integration SDK 中是没有手势和物体交互的功能&#xff0c;Unity XR Interaction Toolkit提供的手势识别物体交互对 Quest适配的挺好的&#xff0c;Pico 当前只能用指尖点触还不能对物体进行抓握以及手势控制射线…

仅使用 Python 创建的 Web 应用程序(前端版本)第05章_共通代码

前面介绍了很多,但是让我们从本章开始实现 WTS。 在本章中,我们将实现所有页面的公共部分:SessionManager、MockDB、Model 和 Application。 SessionManger 与 Streamlit 会话交互。 在WTS中,我们的目标是使代码清晰,SessionManager负责读写st.session_state数据。 Mock…

数据结构:3_栈和队列

栈和队列 一.栈 1. 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。**进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。**栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#x…

【QML-Qt Design Studio】

QML编程指南 ■ Qt Design Studio &#xff08;Qt Quick UI设计工具&#xff09;■ 安装Qt Design Studio■ ■ Qt Design Studio &#xff08;Qt Quick UI设计工具&#xff09; Qt Design Studio是一个用于创建酷炫、优美UI的工具。 简单概括其功能就是让UI设计转换为qml&…

uniapp+vue3+ts--编写微信小程序对接e签宝签署时跳转刷脸效果(人脸识别)中间页代码

uniappvue3ts–编写微信小程序对接e签宝签署时跳转刷脸效果&#xff08;人脸识别&#xff09;中间页代码 e签宝内嵌H5方式集成签署页的文档说明&#xff1a;https://open.esign.cn/doc/opendoc/case3/ahb0sg 签署时跳转刷脸效果示意图&#xff1a; 1. 在文件夹新建一个文件&a…

java基础:有序数组中插入数字使其依然有序案例分析

问题目标是将用户输入的整数插入到一个已排序的数组中&#xff0c;以保持数组的有序性。 如何实现&#xff1f; 思路分析&#xff1a; 初始化已排序的数组&#xff1a;通过使用int[] arr {1, 2, 3, 4, 5, 6};语句创建一个已经排好序的数组。定义变量&#xff1a;index用于记…

2024年制造业展望

制造业是国民经济的主体&#xff0c;其重要性不言而喻。就2023年而言&#xff0c;制造业在技术创新、数字化转型和可持续发展方面都取得了重要的进展。以下是对于2024年制造业的发展进行的分析与预测。 1 保持业务平衡仍将是一项挑战 在过去的四年里&#xff0c;制造业高管人…

【IEEE会议征稿】2024年第九届智能计算与信号处理国际学术会议(ICSP 2024)

2024年第九届智能计算与信号处理国际学术会议&#xff08;ICSP 2024&#xff09; 2024年第八届智能计算与信号处理国际学术会议&#xff08;ICSP 2024&#xff09;将在西安举行&#xff0c; 会期是2024年4月19-21日&#xff0c; 为期三天, 会议由西安科技大学主办。 欢迎参会&…

Django开发_17_表单类

一、介绍 为了简化前端form表单代码 二、步骤 &#xff08;一&#xff09;创建form.py 创建一个表单类 from django import formsclass RegisterForm(forms.Form):reg_name forms.CharField(max_length10, label用户名)reg_pwd forms.CharField(max_length20, label密码…

【Pandora Next Notebook】

系列文章目录 一是为了说一说这个项目&#xff0c;第二点是为了介绍一下如何使用大善人Cloudflare的功能来配合v0.5.0的新功能。它就是全代理ChatXXX账号注册流程。 文章目录 系列文章目录前言一、[GPT_BOT](https://chat.oaifree.com/)这次借着v0.5.0发布了一个好玩的功能&…

配网故障定位装置:实现高效故障排查的利器

在现代社会&#xff0c;电力系统的稳定运行对于国家经济和民生至关重要。然而&#xff0c;随着电力系统的不断发展&#xff0c;配网故障问题日益严重&#xff0c;给电力系统带来了巨大的安全隐患。为了解决这一问题&#xff0c;恒峰智慧科技研发了一种基于成熟的行波测距技术的…

Vue+OpenLayers7:html原生网页如何使用OpenLayers7地图

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 尽管现在大部分网页都是使用Vue或者React开发了,但是还是有不少开发者使用的是网页原生html进行开发,或者是老项目维护的需要,所以为了照顾使用html原生网页的同学们,本章简单讲解一下如何使用原始html网页情况下…

1. Matplotlib的Figure基础概念

1. Matplotlib的Figure基础概念 一 **角色和作用**二 **类比&#xff1a;**三 **基本使用示例** Matplotlib是一个用于绘制二维图形的Python库&#xff0c;广泛应用于数据可视化领域。其灵活性和强大的功能使得用户能够轻松创建各种类型的图表&#xff0c;包括折线图、散点图、…

el-select选择之后值不显示在文本框的问题解决

问题场景如下图&#xff1a; 在el-collapse-item中使用子组件&#xff0c;子组件里是el-form-item代码。el-select在for循环中&#xff0c;可以有多个。 查了一下博客&#xff0c;有的说这种场景需要给el-select添加change事件&#xff0c;加上 this.$forceUpdate() 强制刷新即…

Spring Boot 中的外部化配置

Spring Boot 中的外部化配置 一、配置文件基础1.配置文件格式&#xff08;1&#xff09;YAML 基本语法规则&#xff08;2&#xff09;YAML 支持三种数据结构 2.application 文件3.application.properties 配置文件4.application.yml 配置文件5.Environment6.组织多文件7.多环境…

创新医疗服务:宠物在线问诊系统的搭建与应用

随着科技的不断进步&#xff0c;创新的医疗服务方式也日渐成为宠物主人关心爱宠健康的首选。本文将深入介绍如何搭建一套创新的宠物在线问诊系统&#xff0c;并展示其应用的技术代码。 1. 系统架构与技术选择 在开始搭建之前&#xff0c;我们需要设计系统的架构并选择合适的…

码农维权——案例分析之违法解除劳动合同(六)

目录 一、背景 二、案例分析&#xff1a;违法解除劳动合同 A、公司的主张 B、公司的主要证据&#xff08;公司单方面提交的&#xff0c;法院不一定认可采纳&#xff09; C、员工的质证/证据 D、判决结果 E、判决依据 三、写在最后 一、背景 当前互联网行业普遍以”变相…

Vue开始封装全局防抖和节流函数

封装文件 封装文件的实现思路如下&#xff1a; 首先&#xff0c;我们需要定义两个函数&#xff1a;防抖函数和节流函数。这两个函数的目的是为了减少频繁触发某个事件导致的性能问题&#xff1b;防抖函数的实现思路是创建一个计时器变量&#xff0c;用于延迟执行函数。当触发…