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

目录

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越接近中间-->越能二分-->越接近满二叉树-->深度越均匀-->效率越高

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

从上方的总结上分析一般情况下快排的时间复杂度:类似于二叉树

lgn的算法:设总行数为x

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

第一行排n次,第二行排(n/2)*2次,第三行排(n/3)*3次,...,第lgn行排n次

因此总次数为n*log_2 n,时间复杂度为O(n*lgn)

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

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

相关文章

如何使用 `uiautomator2` 控制 Android 设备并模拟应用操作_VIVO手机

在 Android 自动化测试中,uiautomator2 是一个非常强大的工具,能够帮助我们通过 Python 控制 Android 设备执行各种操作。今天,我将通过一个简单的示例,介绍如何使用 uiautomator2 控制 Android 设备,执行特定的应用启动、广告跳过以及其他 UI 操作。此示例的目标是自动化…

Swift Combine 学习(七):实践应用场景举例

Swift Combine 学习&#xff08;一&#xff09;&#xff1a;Combine 初印象Swift Combine 学习&#xff08;二&#xff09;&#xff1a;发布者 PublisherSwift Combine 学习&#xff08;三&#xff09;&#xff1a;Subscription和 SubscriberSwift Combine 学习&#xff08;四&…

使用 PyInstaller 和 hdiutil 打包 Tkinter 应用为 macOS 可安装的 DMG 文件

在这篇文章中&#xff0c;我们将逐步演示如何将基于 Python 的 Tkinter 应用程序打包成一个 macOS .app 文件&#xff0c;并将其封装为 .dmg 文件&#xff0c;供用户安装。 环境准备 在开始之前&#xff0c;请确保您的开发环境满足以下条件&#xff1a; macOS 系统。安装了 …

DC-2 靶场渗透

目录 环境搭建 开始渗透 扫存活 扫端口 扫服务 看一下80端口 看一下指纹信息 使用wpscan扫描用户名 再使用cewl生成字典 使用wpscan爆破密码 登陆 使用7744端口 查看shell rbash绕过 切换到jerry用户 添加环境变量 现在可以使用su命令了 提权 使用git提权 环…

如何在 Ubuntu 22.04 上优化 Apache 以应对高流量网站教程

简介 在本教程中&#xff0c;我们将学习如何优化 Apache 以应对高流量网站。 当运行高流量网站时&#xff0c;确保你的 Apache Web 服务器得到优化对于有效处理负载至关重要。在本指南中&#xff0c;我们将介绍配置 Apache 以提高性能和可扩展性的基本技巧。 为高流量网站优…

安卓NDK视觉开发——手机拍照文档边缘检测实现方法与库封装

一、项目创建 创建NDK项目有两种方式&#xff0c;一种从新创建整个项目&#xff0c;一个在创建好的项目添加NDK接口。 1.创建NDK项目 创建 一个Native C项目&#xff1a; 选择包名、API版本与算法交互的语言&#xff1a; 选择C版本&#xff1a; 创建完之后&#xff0c;可…

02.01、移除重复节点

02.01、[简单] 移除重复节点 1、题目描述 编写代码&#xff0c;移除未排序链表中的重复节点。保留最开始出现的节点。 2、解题思路 为了实现这一目标&#xff0c;我们可以使用一个哈希表&#xff08;或集合&#xff09;来记录已经遇到的节点值&#xff0c;逐步遍历链表并删…

反向传播算法的偏置更新步骤

偏置的更新步骤 假设我们有一个三层神经网络&#xff08;输入层、隐藏层和输出层&#xff09;&#xff0c;并且每层的激活函数为 sigmoid 函数。我们需要更新隐藏层和输出层的偏置。以下是详细的步骤&#xff1a; 1. 计算误差项&#xff08;Error Term&#xff09; 输出层的…

【Ubuntu】不能连上网络

1. ping路由器的IP地址 ping 192.168.1.1 如果ping不通的话&#xff0c;可能是网络故障导致的。需要重启配置ip地址。配置文件 sudo vi /etc/network/interface 2. ping 8.8.8.8 如果ping不通的话&#xff0c;可能是路由器不能链接往外网&#xff1b; 或者路由器显示了当…

深入解析爬虫中的算法设计:提升效率与准确度

在网络爬虫&#xff08;Web Scraping&#xff09;中&#xff0c;设计高效、准确的算法是关键&#xff0c;尤其当面对大量数据或复杂的网站结构时&#xff0c;精心设计的爬虫算法能显著提高爬取速度并提升数据提取的准确性。本篇博客将详细讲解爬虫算法的设计与优化策略&#xf…

《C++设计模式》策略模式

文章目录 1、引言1.1 什么是策略模式1.2 策略模式的应用场景1.3 本文结构概览 2、策略模式的基本概念2.1 定义与结构2.2 核心角色解析2.2.1 策略接口&#xff08;Strategy&#xff09;2.2.2 具体策略实现&#xff08;ConcreteStrategy&#xff09;2.2.3 上下文&#xff08;Cont…

Spring源码分析之事件机制——观察者模式(一)

目录 事件基类定义 事件监听器接口 事件发布者接口及实现 事件广播器实现 小小总结 Spring源码分析之事件机制——观察者模式&#xff08;一&#xff09;-CSDN博客 Spring源码分析之事件机制——观察者模式&#xff08;二&#xff09;-CSDN博客 Spring源码分析之事件机制…

Spring Security(maven项目) 3.0.2.4版本

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

stm32 移植RTL8201F(正点原子例程为例)

最近在工作中需要使用RTL8201F&#xff0c;在网上找了很多帖子&#xff0c;没有找到合适的&#xff0c;自己翻资料移植了一个。 模板工程使用的是正点原子的f407探索版的例程&#xff0c;原子使用的是LAN8720,需要把他的驱动修改成为我们自己用的RTL8201F。 1.将PHY_TYPE改成我…

Unity学习笔记(四)如何实现角色攻击、组合攻击

前言 本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记 实现动画 首先实现角色移动的动画&#xff0c;动画的实现过程在第二篇&#xff0c;这里仅展示效果 attack1 触发攻击动画 实现脚本 接下来我们通过 Animator 编辑动画之间的过渡&#…

redis的集群模式与ELK基础

一、redis的集群模式 1.主从复制 &#xff08;1&#xff09;概述 主从模式&#xff1a;这是redis高可用的基础&#xff0c;哨兵和集群都是建立在此基础之上。 主从模式和数据库的主从模式是一样的&#xff0c;主负责写入&#xff0c;然后把写入的数据同步到从服务器&#xff…

一套比较简单的仓储系统

自己编写的一套比较简单的仓储系统&#xff0c;多仓库&#xff0c;入库、出库、明细、统计等相关功能 基于偌依的单体架构&#xff1a;springbootvueuniapp 后端&#xff1a;https://download.csdn.net/download/qq_30641447/90214834 前端&#xff1a;https://download.csdn…

网络IP协议

IP&#xff08;Internet Protocol&#xff0c;网际协议&#xff09;是TCP/IP协议族中重要的协议&#xff0c;主要负责将数据包发送给目标主机。IP相当于OSI&#xff08;图1&#xff09;的第三层网络层。网络层的主要作用是失陷终端节点之间的通信。这种终端节点之间的通信也叫点…

设计模式 创建型 原型模式(Prototype Pattern)与 常见技术框架应用 解析

原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;其核心思想在于通过复制现有的对象&#xff08;原型&#xff09;来创建新的对象&#xff0c;而非通过传统的构造函数或类实例化方式。这种方式在需要快速创建大量相似对象时尤为高效&#x…

MySQL(二)MySQL DDL数据库定义语言

1. MySQL DDL数据库定义语言 1.1. MySQL定义语言 进入MySQL mysql -u root -p(回车后输入密码&#xff0c;即可进入mysq1)1.1.1. 数据库操作 &#xff08;1&#xff09;查看数据库 mysql>show databases;注:MySQL语句分隔符为“&#xff1b;”   mysql库很重要它里面有…