c++中如何实现快速排序的非递归版本_c++使用栈优化排序算法【详解】

发布时间 - 2026-01-24 00:00:00    点击率:
非递归快排需用显式栈模拟递归调用顺序:先压右区间再压左区间,确保左子区间先处理;partition须原地交换并返回基准索引;边界检查l>=r时跳过,避免栈溢出。

为什么快速排序的递归版本容易栈溢出

递归版 quick_sort 在最坏情况下(如已排序数组)会退化为 O(n) 递归深度,每层调用压栈函数帧,std::stack 或系统栈都可能耗尽。尤其在嵌入式或栈空间受限环境(如 Windows 默认 1MB 栈),std::bad_alloc 或段错误很常见。

非递归的核心是:把「待排序区间」抽象成 pair(左右下标),用显式栈代替函数调用栈。

std::stack 实现非递归快排的正确写法

关键不是“能不能用栈”,而是“压栈顺序”和“边界处理”是否与递归逻辑严格等价。错误写法(如先压左再压右)会导致分区后处理顺序错乱,影响稳定性(虽快排本就不稳定)或逻辑错误。

  • 每次从栈中弹出一个区间 [l, r],若 l >= r 直接跳过
  • 调用 partition 得到基准位置 pivot_idx
  • 必须先压入右子区间([pivot_idx + 1, r]),再压入左子区间([l, pivot_idx - 1])——这样才能保证左子区间先被处理(模拟递归中先递归左再递归右的执行顺序)
  • partition 必须使用原地交换,且返回的是最终基准索引,不能只返回值
void quick_sort_iterative(std::vector& arr) {
    if (arr.size() <= 1) return;
    std::stack> stk;
    stk.push({0, static_cast(arr.size()) - 1});
while (!stk.empty()) {
    auto [l, r] = stk.top();
    stk.pop();
    if (l >= r) continue;

    int pivot_idx = partition(arr, l, r);
    stk.push({pivot_idx + 1, r}); // 右区间后压,先处理
    stk.push({l, pivot_idx - 1}); // 左区间先压,后处理
}

}

立即学习“C++免费学习笔记(深入)”;

int partition(std::vector& arr, int l, int r) { int pivot = arr[r]; int i = l; for (int j = l; j

如何避免小数组带来的栈开销和性能损失

纯非递归对小数组(如长度 c++ 的 std::sort)一定混合使用插入排序回退。

  • while (!stk.empty()) 循环内,弹出区间后先判断 r - l + 1 ,满足则调用 insertion_sort(arr, l, r)
  • 不要在 partition 前做判断,否则小数组仍被压栈
  • 插入排序实现要 inline 或定义为 static,避免函数调用开销

手写栈 vs std::stack:什么时候该换

std::stack 默认基于 std::deque,内存不连续,频繁 p

ush/pop 有分配开销;但安全、无需手动管理。手写固定大小数组栈(如 std::array<:pair>, 64>)仅适合已知最大深度场景(如 2^20 元素最多需约 20 层栈),且必须加溢出检查。

  • 若确定输入规模上限(如游戏引擎中排序顶点索引,最大 65536),可用静态栈避免动态分配
  • 否则坚持 std::stack,但用 std::stack<:pair>, std::vector<:pair>>> 替代默认 deque,提升缓存友好性
  • 永远不要用 malloc + free 手写栈——C++ 中无 RAII 保障,异常安全难保证

非递归快排真正难的不是“怎么写栈”,而是分区函数的边界细节(比如 lr 是否闭区间)、压栈顺序与递归语义的一致性,以及小数组优化的插入时机——这三个地方写错一个,结果就可能错位或变慢。


# windows  #   # ai  # c++  # win  # 排序算法  # 为什么  # Static  # Array  # if  # sort  # for  # while  # 递归  # 插入排序  # 快速排序  # int  # 循环  # 算法  # 弹出  # 跳过  # 的是  # 后处理  # 最多  # 就不  # 什么时候  # 能不  # 这三个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 高性能网站服务器配置指南:安全稳定与高效建站核心方案  PHP 500报错的快速解决方法  如何用已有域名快速搭建网站?  如何在万网开始建站?分步指南解析  清除minerd进程的简单方法  利用JavaScript实现拖拽改变元素大小  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  Laravel如何实现用户密码重置功能?(完整流程代码)  美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  Laravel的.env文件有什么用_Laravel环境变量配置与管理详解  JS弹性运动实现方法分析  如何在宝塔面板创建新站点?  手机网站制作与建设方案,手机网站如何建设?  php 三元运算符实例详细介绍  canvas 画布在主流浏览器中的尺寸限制详细介绍  如何快速启动建站代理加盟业务?  如何自定义建站之星模板颜色并下载新样式?  如何获取上海专业网站定制建站电话?  Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件  详解Huffman编码算法之Java实现  教学论文网站制作软件有哪些,写论文用什么软件 ?  标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南  Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议  bing浏览器学术搜索入口_bing学术文献检索地址  如何在企业微信快速生成手机电脑官网?  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  详解MySQL数据库的安装与密码配置  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  简历在线制作网站免费版,如何创建个人简历?  简单实现jsp分页  JavaScript如何操作视频_媒体API怎么控制播放  Win11怎么关闭资讯和兴趣_Windows11任务栏设置隐藏小组件  敲碗10年!Mac系列传将迎来「触控与联网」双革新  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程  如何基于云服务器快速搭建网站及云盘系统?  Laravel如何使用Blade模板引擎?(完整语法和示例)  Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】  Android 常见的图片加载框架详细介绍  Laravel怎么连接多个数据库_Laravel多数据库连接配置  Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程  佛山网站制作系统,佛山企业变更地址网上办理步骤?  Swift中swift中的switch 语句  JS中页面与页面之间超链接跳转中文乱码问题的解决办法  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  ,在苏州找工作,上哪个网站比较好?  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境  微信小程序 scroll-view组件实现列表页实例代码