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();
        }
    }
}

程序运行如图:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Django开发入门 – 3.用Django创建一个Web项目

Django开发入门 – 3.用Django创建一个Web项目 Build A Web Based Project With Django By JacksonML 本文简要介绍如何利用最新版Python 3.13.2来搭建Django环境&#xff0c;以及创建第一个Django Web应用项目&#xff0c;并能够运行Django Web服务器。 创建该Django项目需…

SQL布尔盲注、时间盲注

一、布尔盲注 布尔盲注&#xff08;Boolean-based Blind SQL Injection&#xff09;是一种SQL注入技术&#xff0c;用于在应用程序不直接显示数据库查询结果的情况下&#xff0c;通过构造特定的SQL查询并根据页面返回的不同结果来推测数据库中的信息。这种方法依赖于SQL查询的…

【Python网络爬虫】爬取网站图片实战

【Python网络爬虫】爬取网站图片实战 Scrapying Images on Website in Action By Jackson@ML *声明:本文简要介绍如何利用Python爬取网站数据图片,仅供学习交流。如涉及敏感图片或者违禁事项,请注意规避;笔者不承担相关责任。 1. 创建Python项目 1) 获取和安装最新版…

【docker知识】快速找出服务器中占用内存较高的容器

本文由Markdown语法编辑器编辑完成。 1.背景&#xff1a; 近期在处理现场问题&#xff0c;观察服务器时&#xff0c;会遇到某些进程占用较高内存的情况。由于我们的服务&#xff0c;基本上都是以容器的方式在运行&#xff0c;因此就需要找到&#xff0c;到底是哪个容器&#…

图数据库neo4j进阶(一):csv文件导入节点及关系

CSV 一、load csv二、neo4j-admin import<一>、导入入口<二>、文件准备<三>、命令详解 一、load csv 在neo4j Browser中使用Cypher语句LOAD CSV,对于数据量比较大的情况,建议先运行create constraint语句来生成约束 create constraint for (s:Student) req…

10. Hbase Compaction命令

一. 什么是Compaction 在 HBase 中&#xff0c;频繁进行数据插入、更新和删除操作会生成许多小的 HFile&#xff0c;当 HFile 数量增多时&#xff0c;会影响HBase的读写性能。此外&#xff0c;垃圾数据的存在也会增加存储需求。因此&#xff0c;定期进行 Compact操作&#xff…

【工业场景】用YOLOv8实现火灾识别

火灾识别任务是工业领域急需关注的重点安全事项,其应用场景和背景意义主要体现在以下几个方面: 应用场景:工业场所:在工厂、仓库等工业场所中,火灾是造成重大财产损失和人员伤亡的主要原因之一。利用火灾识别技术可以及时发现火灾迹象,采取相应的应急措施,保障人员安全和…

软件开发 | GitHub企业版常见问题解读

什么是GitHub企业版&#xff1f; GitHub企业版是一个企业级软件开发平台&#xff0c;专为现代化开发的复杂工作流程而设计。 作为可扩展的平台解决方案&#xff0c;GitHub企业版使组织能够无缝集成其他工具和功能&#xff0c;并根据特定需求定制开发环境&#xff0c;提高整体…

CEF132 编译指南 MacOS 篇 - depot_tools 安装与配置 (四)

1. 引言 在 CEF132&#xff08;Chromium Embedded Framework&#xff09;的编译过程中&#xff0c;depot_tools 扮演着举足轻重的角色。这套由 Chromium 项目精心打造的脚本和工具集&#xff0c;专门用于获取、管理和更新 Chromium 及其相关项目&#xff08;包括 CEF&#xff…

NLP Word Embeddings

Word representation One-hot形式 在上一周介绍RNN类模型时&#xff0c;使用了One-hot向量来表示单词的方式。它的缺点是将每个单词视为独立的&#xff0c;算法很难学习到单词之间的关系。 比如下面的例子&#xff0c;即使语言模型已经知道orange juice是常用组合词&#xf…

python实现YouTube关键词爬虫(2025/02/11)

在当今数字化时代&#xff0c;YouTube作为全球最大的视频分享平台之一&#xff0c;拥有海量的视频资源。无论是进行市场调研、内容创作还是学术研究&#xff0c;能够高效地获取YouTube上的相关视频信息都显得尤为重要。今天&#xff0c;我将为大家介绍一个基于Python实现的YouT…

Jenkins 配置 Git Parameter 四

Jenkins 配置 Git Parameter 四 一、开启 项目参数设置 勾选 This project is parameterised 二、添加 Git Parameter 如果此处不显示 Git Parameter 说明 Jenkins 还没有安装 Git Parameter plugin 插件&#xff0c;请先安装插件 Jenkins 安装插件 三、设置基本参数 点击…

自然语言处理NLP入门 -- 第三节词袋模型与 TF-IDF

目标 了解词袋模型&#xff08;BoW&#xff09;和 TF-IDF 的概念通过实际示例展示 BoW 和 TF-IDF 如何将文本转换为数值表示详细讲解 Scikit-learn 的实现方法通过代码示例加深理解归纳学习难点&#xff0c;并提供课后练习和讲解 3.1 词袋模型&#xff08;Bag of Words, BoW&a…

C++模板编程——typelist的实现

文章最后给出了汇总的代码&#xff0c;可直接运行 1. typelist是什么 typelist是一种用来操作类型的容器。和我们所熟知的vector、list、deque类似&#xff0c;只不过typelist存储的不是变量&#xff0c;而是类型。 typelist简单来说就是一个类型容器&#xff0c;能够提供一…

fastadmin 接口请求提示跨域

问题描述 小程序项目&#xff0c;内嵌h5页面&#xff0c;在h5页面调用后端php接口&#xff0c;提示跨域。网上查找解决方案如下&#xff1a; 1&#xff0c;设置header // 在入口文件index.php直接写入直接写入 header("Access-Control-Allow-Origin:*"); header(&q…

只需三步!5分钟本地部署deep seek——MAC环境

MAC本地部署deep seek 第一步:下载Ollama第二步:下载deepseek-r1模型第三步&#xff1a;安装谷歌浏览器插件 第一步:下载Ollama 打开此网址&#xff1a;https://ollama.com/&#xff0c;点击下载即可&#xff0c;如果网络比较慢可使用文末百度网盘链接 注&#xff1a;Ollama是…

idea 错误: 找不到或无法加载主类 @C:\Users\admin\AppData\Local\Temp\idea_arg_file1549212448

idea 错误: 找不到或无法加载主类 C:\Users\admin\AppData\Local\Temp\idea_arg_file1549212448 该错误往往和左下角爱弹出的如下提示是一个意思 Error running ‘PayV3Test1.testTransferBatchesBatchId’ Error running PayV3Test1.testTransferBatchesBatchId. Command lin…

Excel 笔记

实际问题记录 VBA脚本实现特殊的行转列 已知&#xff1a;位于同一Excel工作簿文件中的两个工作表&#xff1a;Sheet1、Sheet2。 问题&#xff1a;现要将Sheet2中的每一行&#xff0c;按Sheet1中的样子进行转置&#xff1a; Sheet2中每一行的黄色单元格&#xff0c;为列头。…

【故障处理】- ora-39126

【故障处理】- ora-39126 一、概述二、报错原因三、解决方法 一、概述 使用xtts迁移源端12.1.0.2版本&#xff0c;进行全库导入时&#xff08;目标端19c&#xff09;&#xff0c;报错ORA-39126. 二、报错原因 根据mos反馈&#xff0c;是数据库bug导致&#xff0c;该bug会在20.…

C#运动控制——轴IO映射

1、IO映射的作用 该功能允许用户对专用 IO 信号的硬件输入接口进行任意配置&#xff0c;比如轴的急停信号&#xff0c;通过映射以后&#xff0c;可以将所有轴的急停信号映射到某一个IO输入口上&#xff0c;这样&#xff0c;我们只要让一个IO信号有效就可以触发所有轴的急停。 进…