当前位置: 首页 > article >正文

C#快速排序QuickSort将递归算法修改为堆栈Stack非递归方式

我们知道,方法的调用是采用Stack的方式[后进先出:LIFO],

在DeepSeek中快速搜索C#快速排序,

搜索结果如图:

我们会发现是采用递归的方式 .

递归的优点:

简单粗暴,类似于直接写数学公式,因代码量较少,易于理解.递归与循环迭代的运行次数都是一致的

递归的缺点:

占用大量的内存空间,每一次的递归都需要保存[案发现场]出栈和进栈数据,因操作系统为每个线程分配的内存空间是有限的,当递归超过内存空间限度时,会引发堆栈溢出异常:StackOverflowException

我们这里,使用Stack来将快速排序算法进行改造,改造为非递归的快速排序算法

先复制DeepSeek快速排序示例代码,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace QuickSortDemo
{class Program{static void Main(string[] args){int[] arr = { 10, 7, 8, 9, 1, 5, 18, 15, 4, 32, 25 };Console.WriteLine("原始数组:");PrintArray(arr);Sort(arr);Console.WriteLine("排序后的数组:");PrintArray(arr);Console.ReadLine();}// 快速排序的主函数public static void Sort(int[] arr){if (arr == null || arr.Length == 0)return;QuickSortRecursive(arr, 0, arr.Length - 1);}// 递归实现快速排序private static void QuickSortRecursive(int[] arr, int left, int right){if (left < right){int pivotIndex = Partition(arr, left, right);// 递归排序左半部分QuickSortRecursive(arr, left, pivotIndex - 1);// 递归排序右半部分QuickSortRecursive(arr, pivotIndex + 1, right);}}// 分区函数,返回基准元素的最终位置private static int Partition(int[] arr, int left, int right){int pivot = arr[right];  // 选择最后一个元素作为基准int i = left - 1;  // i是小于基准的元素的最后一个位置for (int j = left; j < right; j++){if (arr[j] < pivot){i++;Swap(arr, i, j);}}// 将基准元素放到正确的位置Swap(arr, i + 1, right);return i + 1;  // 返回基准元素的索引}// 交换数组中两个元素的位置private static void Swap(int[] arr, int i, int j){int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}// 打印数组public static void PrintArray(int[] arr){foreach (var item in arr){Console.Write(item + " ");}Console.WriteLine();}}
}

实现方法:

我们可以发现:对于递归Recursive代码更新为堆栈Stack循环代码,仅需三个步骤即可实现:

①将所有参数封装为元组Tuple或者一个自定义类

如递归方法void QuickSortRecursive(int[] arr, int left, int right)

就定义一个元组 Tuple<int[], int, int> 作为整体元素[参数集合]传递

②定义一个泛型Stack,每个元素都是一个元组

如Stack<Tuple<int[], int, int>> stack ,并将入口参数推入到堆栈stack中

stack.Push(Tuple.Create(arr, left, right));

然后一直死循环判断堆栈stack集合是否不为空,循环体第一步就去抓取并删除一个元素[Pop]

while (stack.Count > 0)

{

    Tuple<int[], int, int> tuple = stack.Pop();

     //.......

}

③将原来的使用递归方法调用自身的使用修改为推入堆栈中[Push]

stack.Push(Tuple.Create(arr, left, pivotIndex - 1));

至此更新完毕.这三个步骤同样适用于队列Queue,仅仅将方法更新为Enqueue()和Dequeue()

 更新后的代码如下:

同时增加另一种代码改造:Queue队列

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace QuickSortDemo
{class Program{static void Main(string[] args){int[] arr = { 10, 7, 8, 9, 1, 5, 18, 15, 4, 32, 25, 11 };int[] arrStack = new int[arr.Length];int[] arrQueue = new int[arr.Length];Array.Copy(arr, arrStack, arr.Length);Array.Copy(arr, arrQueue, arr.Length);ShowSort("Recursive", arr, QuickSortRecursive);ShowSort("Stack", arrStack, QuickSortStack);ShowSort("Queue", arrQueue, QuickSortQueue);Console.ReadLine();}/// <summary>/// 显示快速排序的耗时/// </summary>/// <param name="sortMethodName"></param>/// <param name="arr"></param>/// <param name="actionQuickSort"></param>private static void ShowSort(string sortMethodName, int[] arr, Action<int[], int, int> actionQuickSort) {Console.WriteLine($"【{sortMethodName}】原始数组:");PrintArray(arr);Stopwatch stopwatch = new Stopwatch();stopwatch.Start();Sort(arr, actionQuickSort);stopwatch.Stop();Console.WriteLine($"【{sortMethodName}】排序后的数组(耗时:{stopwatch.Elapsed.TotalMilliseconds}ms):");PrintArray(arr);}// 快速排序的主函数public static void Sort(int[] arr, Action<int[], int, int> actionQuickSort){if (arr == null || arr.Length == 0)return;//QuickSortRecursive(arr, 0, arr.Length - 1);actionQuickSort(arr, 0, arr.Length - 1);}// 递归实现快速排序private static void QuickSortRecursive(int[] arr, int left, int right){if (left < right){int pivotIndex = Partition(arr, left, right);// 递归排序左半部分QuickSortRecursive(arr, left, pivotIndex - 1);// 递归排序右半部分QuickSortRecursive(arr, pivotIndex + 1, right);}}/// <summary>/// 使用堆栈Stack实现快速排序/// </summary>/// <param name="arr"></param>/// <param name="left"></param>/// <param name="right"></param>private static void QuickSortStack(int[] arr, int left, int right){Stack<Tuple<int[], int, int>> stack = new Stack<Tuple<int[], int, int>>();stack.Push(Tuple.Create(arr, left, right));while (stack.Count > 0){Tuple<int[], int, int> tuple = stack.Pop();arr = tuple.Item1;left = tuple.Item2;right = tuple.Item3;if (left < right){int pivotIndex = Partition(arr, left, right);// 排序左半部分 放入堆栈中stack.Push(Tuple.Create(arr, left, pivotIndex - 1));// 排序右半部分 放入堆栈中stack.Push(Tuple.Create(arr, pivotIndex + 1, right));}}            }/// <summary>/// 使用队列Queue实现快速排序/// </summary>/// <param name="arr"></param>/// <param name="left"></param>/// <param name="right"></param>private static void QuickSortQueue(int[] arr, int left, int right){Queue<Tuple<int[], int, int>> queue = new Queue<Tuple<int[], int, int>>();queue.Enqueue(Tuple.Create(arr, left, right));while (queue.Count > 0){Tuple<int[], int, int> tuple = queue.Dequeue();arr = tuple.Item1;left = tuple.Item2;right = tuple.Item3;if (left < right){int pivotIndex = Partition(arr, left, right);// 排序左半部分 放入堆栈中queue.Enqueue(Tuple.Create(arr, left, pivotIndex - 1));// 排序右半部分 放入堆栈中queue.Enqueue(Tuple.Create(arr, pivotIndex + 1, right));}}}// 分区函数,返回基准元素的最终位置private static int Partition(int[] arr, int left, int right){int pivot = arr[right];  // 选择最后一个元素作为基准int i = left - 1;  // i是小于基准的元素的最后一个位置for (int j = left; j < right; j++){if (arr[j] < pivot){i++;Swap(arr, i, j);}}// 将基准元素放到正确的位置Swap(arr, i + 1, right);return i + 1;  // 返回基准元素的索引}// 交换数组中两个元素的位置private static void Swap(int[] arr, int i, int j){int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}// 打印数组public static void PrintArray(int[] arr){foreach (var item in arr){Console.Write(item + " ");}Console.WriteLine();}}
}

程序运行如图:

相关文章:

C#快速排序QuickSort将递归算法修改为堆栈Stack非递归方式

我们知道,方法的调用是采用Stack的方式[后进先出:LIFO], 在DeepSeek中快速搜索C#快速排序, 搜索结果如图: 我们会发现是采用递归的方式 . 递归的优点: 简单粗暴,类似于直接写数学公式,因代码量较少,易于理解.递归与循环迭代的运行次数都是一致的 递归的缺点: 占用大量的内…...

15.最大二叉树、合并二叉树、二叉搜索树

最大二叉树 就是一个提供了额外信息的中序遍历 class Solution { public:TreeNode* sol(vector<int>& nums,int start,int end){if(startend)return nullptr;int maxnums[start],indexstart;for(int istart;i<end;i){if(nums[i]>max){maxnums[i];indexi;}}Tr…...

【DeepSeek × Postman】请求回复

新建一个集合 在 Postman 中创建一个测试集合 DeepSeek API Test&#xff0c;并创建一个关联的测试环境 DeepSeek API Env&#xff0c;同时定义两个变量 base_url 和 api_key 的步骤如下&#xff1a; 1. 创建测试集合 DeepSeek API Test 打开 Postman。点击左侧导航栏中的 Co…...

Repo命令使用

repo 命令与 git 类似&#xff0c;但它主要用于管理多个 Git 仓库的操作。以下是等效的 repo 命令&#xff1a; 1. 获取新仓库代码 克隆仓库 repo init -u <manifest_url> -b <branch_name> repo sync repo init&#xff1a;初始化 repo&#xff0c;指定远程清单…...

npm install 失败

考虑原因&#xff1a; node版本不符代理镜像连接失败权限不足 症状1&#xff1a; 卡住 尝试降低nodejs版本 症状2&#xff1a;报错 报错1&#xff1a;permission not permitted 报错2&#xff1a; 超时 应对方法&#xff1a; node版本不符 降版本 镜像失败 – 切换镜像 …...

排序算法整理(冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序、计数排序、桶排序、基数排序)

排序算法是计算机科学中用于将数据元素按照特定顺序进行排列的算法&#xff0c;常见的排序算法有以下几类&#xff1a; 比较排序 冒泡排序&#xff1a;通过重复地走访要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。走访数列的工作…...

Kimi实战1/100 - 读接口文档,编写接口

文章目录 Kimi实战1/100 - 读接口文档&#xff0c;编写接口接口调用requests 调用代码说明注意事项 接口提供FastAPI 接口代码代码说明测试方法 Kimi实战1/100 - 读接口文档&#xff0c;编写接口 接口调用 User: 根据 接口文档 https://www.eiisys.com/home/apiDetails?id00…...

Spring Cache @Cacheable:提升应用性能的利器

在构建企业级应用时&#xff0c;性能优化至关重要。Spring Cache 提供了一种简便而强大的方式来缓存方法调用的结果&#xff0c;从而减少数据库访问、提高响应速度。其中&#xff0c;Cacheable 注解是 Spring Cache 的核心&#xff0c;本文将深入剖析 Cacheable 注解&#xff0…...

css块级元素和行内元素区别

在CSS中&#xff0c;元素可以分为两大类&#xff1a;块级元素&#xff08;Block-level elements&#xff09;和行内元素&#xff08;Inline elements&#xff09;。这两种元素在网页布局中起着不同的作用&#xff0c;主要体现在它们的显示方式、尺寸控制、以及与其他元素的交互…...

AWTK fscript 中的 TCP/UDP 客户端扩展函数

fscript 是 AWTK 内置的脚本引擎&#xff0c;开发者可以在 UI XML 文件中直接嵌入 fscript 脚本&#xff0c;提高开发效率。本文介绍一下 fscript 中的 TCP/UDP 客户端扩展函数。 1.iostream_tcp_create 创建 TCP 客户端输入输出流对象。 原型 iostream_tcp_create(host, por…...

[免费]Springboot+Vue医疗(医院)挂号管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringbootVue医疗(医院)挂号管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue医疗(医院)挂号管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 在如今社会上&#xff0c;关于信息上…...

计算机毕业设计PySpark+hive招聘推荐系统 职位用户画像推荐系统 招聘数据分析 招聘爬虫 数据仓库 Django Vue.js Hadoop

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

Jmeter+Influxdb+Grafana平台监控性能测试过程

一、Jmeter自带插件监控 下载地址&#xff1a;https://jmeter-plugins.org/install/Install/ 安装&#xff1a;下载后文件为jmeter-plugins-manager-1.3.jar&#xff0c;将其放入jmeter安装目录下的lib/ext目录&#xff0c;然后重启jmeter&#xff0c;即可。 启动Jmeter&…...

fatal: unable to access ‘https://github.com/xxx/‘: SSL peer certificat

从github上clone代码时报错 F:\Projects>git clone https://github.com/xxx into xxx... fatal: unable to access https://github.com/xxx/: SSL peer certificate or SSH remote key was not OK **可能的原因****解决方法****1. 检查系统时间****2. 禁用 SSL 验证&#xf…...

Prompt通用技巧

Prompt 的典型构成 角色:给 AI定义一个最匹配任务的角色&#xff0c;比如:「你是一位软件工程师」「你是一位小学老师」指示:对任务进行描述上下文: 给出与任务相关的其它背景信息(尤其在多轮交互中)。例子 : 必要时给出举例&#xff0c;学术中称为 one-shot learning,few-sho…...

ROACH

End-to-End Urban Driving by Imitating a Reinforcement Learning Coach CARLA-Roach ICCV‘21论文&#xff1a;模仿一个强化学习教练的端到端城市驾驶 文章目录 Roach输入BEV语义分割图像测量向量 Roach输出训练策略网络价值网络 具体实现由 Roach 监督的模仿学习&#xff08…...

机械臂运动学笔记(一):正向运动学

正向运动学指的是通过相邻关节间的转动和移动坐标&#xff0c;将末端的坐标计算出来。 反向运动学指的是已知机械臂末端的坐标&#xff0c;反算每个关节可能的转动和移动参数。 参考资料&#xff1a;4.机械臂几何法与DH表示法_哔哩哔哩_bilibili 一.任意连杆连接的变量定义&a…...

【DuodooBMS】给PDF附件加“受控”水印的完整Python实现

给PDF附件加“受控”水印的完整Python实现 功能需求 在实际工作中&#xff0c;许多文件需要添加水印以标识其状态&#xff0c;例如“受控”“机密”等。对于PDF文件&#xff0c;添加水印不仅可以增强文件的可识别性&#xff0c;还可以防止未经授权的使用。本代码的功能需求是…...

GitCode 助力 Dora SSR:开启游戏开发新征程

项目仓库&#xff08;点击阅读原文链接可直达&#xff09; https://gitcode.com/ippclub/Dora-SSR 跨越技术藩篱&#xff0c;构建游戏开发乐园 Dora SSR 是一款致力于打破游戏开发技术壁垒的开源游戏引擎。其诞生源于开发者对简化跨平台游戏开发环境搭建的强烈渴望&#xff0…...

Mediamtx+Python读取webrtc流

一、功能思路&#xff1a; 1、我采用ffmpeg -re -stream_loop -1 -i xcc.mp4 -c:v libx264 -profile:v baseline -x264opts "bframes0:repeat_headers1" -b:v 1500k -preset fast -f flv rtmp://127.0.0.1:1835/stream/111推流到mediamtx的rtmp上 2、通过mediamtx自…...

每日一题——矩阵最长递增路径

矩阵最长递增路径问题 题目描述数据范围&#xff1a;进阶要求&#xff1a;示例示例 1示例 2 题解思路算法步骤&#xff1a;代码实现代码解释复杂度分析总结 题目描述 给定一个 n 行 m 列的矩阵 matrix&#xff0c;矩阵内所有数均为非负整数。你需要在矩阵中找到一条最长路径&a…...

【CLIP系列】4:目标检测(ViLD、GLIP)

目录 1 ViLD2 GLIP2.1 前言2.2 损失计算2.3 模型框架 1 ViLD OPEN-VOCABULARY OBJECT DETECTION VIA VISION AND LANGUAGE KNOWLEDGE DISTILLATION 从标题就能看出来&#xff0c;作者是把CLIP模型当成一个Teacher&#xff0c;去蒸馏他自己的网络&#xff0c;从而能Zero Shot去…...

Cesium for Unity Linux版本

Cesium for Unity 直装不支持Linux 参照官方开发流程一些操作命令issues 宝藏最后运行图 参照官方开发流程 https://github.com/CesiumGS/cesium-unity/blob/main/Documentation~/developer-setup.md 系统已经安装过dotnet和cmake xuefeixuefei:~$ dotnet --version 9.0.102 …...

Spring Boot过滤器链:从入门到精通

文章目录 一、过滤器链是什么&#xff1f;二、为什么需要过滤器链&#xff1f;三、Spring Boot中的过滤器链是如何工作的&#xff1f;&#xff08;一&#xff09;过滤器的生命周期&#xff08;二&#xff09;过滤器链的执行流程 四、如何在Spring Boot中定义自己的过滤器&#…...

关于 IoT DC3 中驱动(Driver)的理解

在开源IoT DC3物联网系统中&#xff0c;驱动&#xff08;Driver&#xff09;扮演着至关重要的角色&#xff0c;它充当了软件系统与物理设备之间的桥梁。驱动的主要功能是依据特定的通信协议连接到设备&#xff0c;并根据设备模板中配置的位号信息进行数据采集和指令控制。不同的…...

微信小程序地图标记点,安卓手机一次性渲染不出来的问题

问题描述&#xff1a; 如果微信小程序端&#xff0c;渲染的标记物太多&#xff0c;安卓手机存在标记物不显示的问题&#xff0c;原因初步判断是地图还没有渲染完&#xff0c;标记物数据已经加载完了&#xff0c;导致没有在地图上显示。 解决办法&#xff1a; 使用map组件的b…...

一维差分与二维差分

差分&#xff08;Difference&#xff09;是一种与前缀和密切相关的技术&#xff0c;主要用于高效处理区间更新操作。差分数组的核心思想是通过记录相邻元素的差值来表示原数组的变化&#xff0c;从而将区间更新操作的时间复杂度从 O(n) 优化到 O(1)。下面详细讲解一维差分和二维…...

EasyRTC嵌入式WebRTC视频通话SDK支持Web浏览器、Linux、ARM、Android、iOS

随着互联网技术的飞速发展&#xff0c;实时通信&#xff08;RTC&#xff09;已经成为现代应用中不可或缺的一部分。无论是视频会议、在线教育、远程医疗&#xff0c;还是社交娱乐&#xff0c;实时通信技术都在其中扮演着重要角色。 然而&#xff0c;WebRTC技术在PC和移动端的支…...

数据库脚本MySQL8转MySQL5

由于生产服务器版本上部署的是MySQL5&#xff0c;而开发手里的脚本代码是MySQL8。所以只能降版本了… 升级版本与降级版本脚本转换逻辑一样 MySQL5与MySQL8版本SQL脚本区别 大多数无需调整、主要是字符集与排序规则 MySQL5与MySQL8版本SQL字符集与排序规则 主要操作&…...

【PGCCC】commit_delay 对性能的提升:PostgreSQL 基准测试

通过禁用参数可以来调整事务工作负载synchronous_commit。该措施有惊人效果。但在操作系统崩溃期间丢失已提交事务的可能性使其成为许多应用程序无法启动的因素。因此我决定写下来。 WAL 刷新是事务数据库工作负载的瓶颈 为了确保已提交的事务不会丢失&#xff0c;PostgreSQL…...