121.【C语言】数据结构之快速排序(未优化的Hoare排序存在的问题)以及时间复杂度的分析

news2025/1/8 4:34:46

目录

1.未优化的Hoare排序存在的问题

测试代码

"量身定制"的测试代码1

运行结果

"量身定制"的测试代码2

运行结果

"量身定制"的测试代码3

运行结果

分析代码1、2和3栈溢出的原因

 排有序数组的分析

分析测试代码1:给一个升序数组,要求排升序

分析测试代码2:给一个降序数组,要求排升序

分析测试代码3:给一个元素全相同的数组,要求排升序

分析排有序和数组元素全相同的时间复杂度

分析一般情况下快排的时间复杂度


1.未优化的Hoare排序存在的问题

将120.【C语言】数据结构之快速排序(详解Hoare排序算法)文章的Hoare排序代码的性能(116.【C语言】测试排序性能的模板代码 点我跳转)

测试代码

在VS2022+Debug+x86环境下,试试下面这个为没有优化的Hoare排序"量身定制"的修改过的测试性能的两个代码

"量身定制"的测试代码1

void ShellSort(int* arr, int n)//排升序
{
	int gap = n;
	while (gap > 1)
	{
		gap /= 2;
		for (int i = gap; i < n; i++)//交替排序,每次i+1
		{
			int end = i - gap;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (tmp < arr[end])
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

void TestTime()
{
	srand((unsigned int)time(0));
	const int N = 10000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	if (a1 == NULL)
	{
		perror("malloc");
		return;
	}

	for (int i = 0; i < N; i++)
	{
		a1[i] = rand();
	}
	ShellSort(a1, N);
	
	clock_t begin2 = clock();
	QuickSort(a1, 0, N-1);
	clock_t end2 = clock();
	printf("QuickSort's time=%ldms\n", end2 - begin2);

	free(a1);
}

int main()
{
	TestTime();
	return 0;
}
运行结果

虽然N==10000不是很大,但是栈溢出(Stack overflow)

"量身定制"的测试代码2

void ShellSort(int* arr, int n)//排降序
{
	int gap = n;
	while (gap > 1)
	{
		gap /= 2;
		for (int i = gap; i < n; i++)//交替排序,每次i+1
		{
			int end = i - gap;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (tmp > arr[end])
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

void TestTime()
{
	const int N = 10000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	if (a1 == NULL)
	{
		perror("malloc");
		return;
	}

	for (int i = 0; i < N; i++)
	{
		a1[i] = rand();
	}
	ShellSort(a1,N);
	clock_t begin2 = clock();
	QuickSort(a1, 0, N-1);
	clock_t end2 = clock();
	printf("QuickSort's time=%ldms\n", end2 - begin2);

	free(a1);
}

int main()
{
	TestTime();
	return 0;
}
运行结果

"量身定制"的测试代码3

void TestTime()
{
	const int N = 10000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	if (a1 == NULL)
	{
		perror("malloc");
		return;
	}

	for (int i = 0; i < N; i++)
	{
		a1[i] = 2;
	}
	
	clock_t begin2 = clock();
	QuickSort(a1, 0, N-1);
	clock_t end2 = clock();
	printf("QuickSort's time=%ldms\n", end2 - begin2);

	free(a1);
}

int main()
{
	TestTime();
	return 0;
}
运行结果

三个测试代码的运行结果都Stack overflow(栈溢出)

分析代码1、2和3栈溢出的原因

仔细看看测试代码1是怎么"量身定制"的:(下面展示关键代码)

ShellSort(a1, N);//调用希尔排序先对数组a1排升序一次
//......
//调用120.【C语言】数据结构之快速排序(详解Hoare排序算法)文章的Hoare排序代码
QuickSort(a1, 0, N-1);
//......

发现

① 希尔排序和快速排序排的都是同一个数组

② 先用希尔排序将数组a1升序再用快速排序排

 仔细看看测试代码2是怎么"量身定制"的:(下面展示关键代码)

ShellSort(a1, N);//调用希尔排序先对数组a1排降序一次
//......
//调用120.【C语言】数据结构之快速排序(详解Hoare排序算法)文章的Hoare排序代码
QuickSort(a1, 0, N-1);
//......

 发现

① 希尔排序和快速排序排的都是同一个数组

② 先用希尔排序将数组a1升序再用快速排序排

仔细看看测试代码3是怎么"量身定制"的:(下面展示关键代码)

	for (int i = 0; i < N; i++)
	{
		a1[i] = 2;
	}

发现 a1[0]==a1[1]==a1[2]==...==a1[N-1]

由发现可得知:未优化的快速排序会对有序或接近优先有序或每个元素都相同的数组产生栈溢出的问题,由于是递归调用,则栈溢出的原因显然是递归调用次数过多导致开辟的栈帧空间过多而溢出导致的


 排有序数组的分析

分析测试代码1:给一个升序数组,要求排升序

分析测试代码2:给一个降序数组,要求排升序

分析测试代码3:给一个元素全相同的数组,要求排升序

从三个测试代码可以看出:关键值key并没有起到分割数组的作用,反而每次都需要对数组的整体进行排序,这样导致函数的栈帧开辟的空间越来越大,函数没有没有及时返回(销毁),从而导致栈溢出

分析排有序和数组元素全相同的时间复杂度

上述三种是快排最坏情况循环的次数为N+N-1+N-2+...+1,为等差数列求和,时间复杂度为O(N^2)

总结:影响快速排序的性能为key(arr[key_i]==key),key_i越接近中间-->越能二分-->越接近满二叉树-->深度越均匀-->效率越高

分析一般情况下快排的时间复杂度

从上方的总结上分析一般情况下快排的时间复杂度:类似于二叉树,设n为要排序的数组的元素的个数

按最好情况分析,每一趟排序后都能将记录序列均匀地分割成两个长度大致相等的子数组

lgn的算法:设总行数为x

2^x=n因此x=log_2 n(简写为lgn)

第一行排n次,第二行排(n/2-1)*2次(-1是去掉key本身),第三行排(n/3-2)*3次,...,第lgn行排n-(n-1)次

因此总次数约为n*log_2 n,时间复杂度为O(n*lgn),可见快速排序的趟数取决于递归树的深度

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

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

相关文章

【操作系统不挂科】操作系统期末考试卷<2>(单选题&简答题&计算与分析题&程序分析题&应用题)

前言 大家好吖&#xff0c;欢迎来到 YY 滴 操作系统不挂科 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 本章为系列题库&#xff0c;其他章节看下面传送门其他博客 【操作系统不挂科】&#xff1c;操作系统概论&#xff08;1&#xff09;&#xff1e…

解密人工智能:如何改变我们的工作与生活

引言&#xff1a;AI崛起背后的思考 在过去的几十年里&#xff0c;人工智能&#xff08;AI&#xff09;从科幻小说中的神秘存在&#xff0c;逐渐走进了我们的日常生活。无论是智能手机的语音助手&#xff0c;还是推荐心仪商品的电商平台&#xff0c;AI技术已悄然融入工作与生活的…

LLM - 使用 LLaMA-Factory 部署大模型 HTTP 多模态服务 教程 (4)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144881432 大模型的 HTTP 服务,通过网络接口,提供 AI 模型功能的服务,允许通过发送 HTTP 请求,交互大模型,通常基于云计算架构,无需在本地部署复杂的模型和硬件,…

Chapter 1 Understanding Large Language Models

文章目录 Understanding Large Language ModelsWhat is an LLM?Applications of LLMSStages of building and using LLMsUsing LLMS for different tasksA closer look at the GPT architectureBuilding a large language modelSummary Understanding Large Language Models …

游戏社交趋势下,游戏语音再升级!

如今&#xff0c;游戏已成为我们社交生活的一个重要娱乐方式&#xff0c;春节临近&#xff0c;与亲朋好友一起畅玩“开黑”无疑是节假日的一大乐趣。在游戏社交互动中&#xff0c;“游戏语音”不可或缺。在传统游戏语音领域&#xff0c;多人在线游戏如 MOBA、FPS 和 MMORPG 的实…

CTFshow—远程命令执行

29-35 Web29 代码利用正则匹配过滤了flag&#xff0c;后面加了/i所以不区分大小写。 可以利用通配符绕过 匹配任何字符串&#xff0f;文本&#xff0c;包括空字符串&#xff1b;*代表任意字符&#xff08;0个或多个&#xff09; ls file * ? 匹配任何一个字符&#xff08;不…

Elasticsearch 入门教程

掌握Elasticsearch&#xff1a;从入门到入门 一、ES 背景1.1 ElasticSearch 的背景1.2 ElasticSearch 的应用场景 二、ES 简介2.1 ElasticSearch 简介2.2 ElasticSearch 的定义与特点2.3 ElasticSearch 与传统数据库的区别2.4 ElasticSearch 的优势和劣势 三、ES 的核心概念3.1…

【Vue学习】Vue 组件实例的生命周期(四个阶段,八个钩子)

一、为什么要理解生命周期&#xff1f; 理解生命周期就像是知道了一部电影的剧情走向&#xff0c;能让你在适当的时机做出反应。Vue 生命周期的钩子让你可以在不同的阶段插入你的逻辑&#xff0c;像是提前准备、后期清理或者在数据更新时做点事情。这种“精确控制”的能力会让你…

【Vim Masterclass 笔记08】第 6 章:Vim 中的文本变换及替换操作 + S06L20:文本的插入、变更、替换,以及合并操作

文章目录 Section 6&#xff1a;Transforming and Substituting TextS06L21 Inserting, Changing, Replacing, and Joining1 定位到行首非空字符&#xff0c;并启用插入模式2 在紧挨光标的下一个字符位置启动插入模式3 定位到一行末尾&#xff0c;并启用插入模式4 定位到光标的…

vip与haproxy构建nginx高可用集群传递客户端真实ip

问题 系统使用了vip与haproxy实现高可用以及对nginx进行负载均衡&#xff0c;但是发现在上游的应用服务无法拿到客户端的请求ip地址&#xff0c;拿到的是主haproxy机器的ip&#xff0c;以下是nginx与haproxy的缩减配置&#xff1a; location ~* ^/(xx|xx) {proxy_pass http:/…

YOLOv5部署到web端(flask+js简单易懂)

文章目录 前言最终实现效果图后端实现 主界面检测函数检测结果显示 前端实现 主界面(index.html&#xff09;显示图片界面 总结 前言 最近&#xff0c;老板让写一个程序把yolov5检测模型部署到web端&#xff0c;在网页直接进行目标检测。经过1个星期的努力&#xff0c;终于实…

【Vue】分享一个快速入门的前端框架以及如何搭建

先上效果图: 登录 菜单: 下载地址: 链接&#xff1a;https://pan.baidu.com/s/1m-ZlBARWU6_2n8jZil_RAQ 提取码&#xff1a;ui20 … 主要是可以自定义设置token,更改后端请求地址较为方便。 应用设置: 登录与token设置: 在这里设置不用登录,可以请求的接口: request.js i…

【Linux】RPMSG通讯协议介绍

RPMSG协议通讯协议介绍 RPMSG&#xff0c;全称Remote processor Messaging。是一种核间通讯协议。在Linux Kernel中&#xff0c;已经内置了RPMSG。 Linux RPMSG基于共享内存&#xff0c;利用RPMSG可以高效的实现核间通信。比如Linux与FreeRTOS、Linux与Android&#xff0c;都可…

【51单片机-零基础chapter1】

安装软件(配套的有,不多赘述) 1.管理员身份运行keil和破解软件kegen 将CID代码复制粘贴到 一定要管理员方式,不然会error 插入板子 我的电脑,管理 1.如果是拯救者,查看端口,如果没有则显示隐藏 2.苹果不知道,好像不可以 3.其他电脑在"其他设备找" (注:本人在校已…

计算机网络-数据链路层(CSMA/CD协议,CSMA/CA协议)

2.2 ppp协议 点对点协议ppp是目前使用最广泛的点对点数据链路层协议。 2.3 媒体接入控制基本概念 共享信道要着重考虑的一个问题就是如何协调多个发送和接收站点对一个共享传输媒体的占用&#xff0c;即媒体接入控制MAC。 2.3.1 静态划分信道 频分复用 时分复用 波分复用 码分复…

JMeter + Grafana +InfluxDB性能监控 (二)

您可以通过JMeter、Grafana 和 InfluxDB来搭建一个炫酷的基于JMeter测试数据的性能测试监控平台。 下面&#xff0c;笔者详细介绍具体的搭建过程。 安装并配置InfluxDB 您可以从清华大学开源软件镜像站等获得InfluxDB的RPM包&#xff0c;这里笔者下载的是influxdb-1.8.0.x86_…

李宏毅机器学习笔记-Transformer

目录 1. Seq2seq 2. encoder Transformer 中的 Block 结构 3. Decoder 4.Encoder和Decoder间的信息传递 5.Training 6.Tips 1. Seq2seq Transformer 是一个seq2seq的model。Seq2seq指的是input是一个序列&#xff0c;输出也是一个序列&#xff0c;输出的长度是由机器自己…

【AWS SDK PHP】This operation requests `sigv4a` auth schemes 问题处理

使用AWS SDK碰到的错误&#xff0c;其实很简单&#xff0c;要装个扩展库 保持如下 Fatal error: Uncaught Aws\Auth\Exception\UnresolvedAuthSchemeException: This operation requests sigv4a auth schemes, but the client currently supports sigv4, none, bearer, sigv4-…

Qt 5.14.2 学习记录 —— 일 新项目

文章目录 1、创建2、查看代码 ---- main.cpp3、查看代码 ---- widgt.h4、查看代码 ---- widgt.cpp和widget.ui5、查看代码 ---- Empty.pro6、运行产生的中间文件 1、创建 左上角的文件&#xff0c;新建文件或项目。如果要写一个GUI程序&#xff0c;应当选择Application&#x…

Spring MVC和servlet

1.Spring MVC是Spring框架的一个扩展 2.Spring MVC工作流程 1、用户发送请求至前端控制器DispatcherServlet。 2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找)&#xff0c;生成处理器对象及…