快速排序最坏测试用例生成代码故障排查:基于中间基准的1~N数组构造问题
问题分析与修复方案
首先,咱们先明确核心目标:构造一个包含1~N的数组,让以中间元素为基准的快速排序执行的比较次数最大化。这个最坏情况的构造逻辑方向是对的——每次把当前最大的元素放在区间中间,这样作为基准时需要和左右所有元素比较,再递归处理左右子区间。但你的代码在递归逻辑和元素填充的细节上出了问题,导致无法生成正确的数组。
原代码的主要问题
1. 递归函数的返回值逻辑混乱
你的antiqs函数试图通过返回值传递剩余的最小元素,这种设计完全没必要,反而导致后续填充0的逻辑出错。递归过程中应该直接把元素放到对应位置,而不是留到main函数里补0,这会造成元素重复或者顺序错误。
2. 区间边界处理错误
当区间长度小于2时(也就是只有1个元素或者空区间),你没有直接填充当前应放的元素,而是返回一个值,导致这些位置被初始化为0,后续补值时逻辑混乱。比如N=4时,原代码会生成重复元素,就是这个原因。
3. 数组初始化和填充的冗余操作
初始化数组为0然后补0的方式多余且容易出错,递归过程中应该直接填充所有位置,不需要后续补全。
4. 栈溢出风险
原代码中用int array[n]是变长数组(VLA),当N达到70000时,栈内存会直接溢出,因为栈的容量通常远小于这个规模。
修复后的代码实现
我们重构递归函数,让它直接负责填充当前区间的元素,通过引用跟踪当前要放置的最大元素,同时改用动态数组避免栈溢出:
#include <iostream> #include <fstream> using namespace std; // 递归填充数组:在[start, end]区间构造最坏情况数组 void antiqs(int* array, int start, int end, int& current_max) { if (start > end) { return; // 空区间,直接返回 } if (start == end) { // 单个元素,直接放当前最大的元素 array[start] = current_max; current_max--; return; } // 计算当前区间的中间位置 int middle = (start + end) / 2; // 把当前最大元素放到中间 array[middle] = current_max; current_max--; // 递归处理左半区间和右半区间 antiqs(array, start, middle - 1, current_max); antiqs(array, middle + 1, end, current_max); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n; ifstream fileIn("antiqs.in.txt"); fileIn >> n; fileIn.close(); int* array = new int[n]; // 动态数组避免栈溢出 int current_max = n; antiqs(array, 0, n - 1, current_max); ofstream fileOut("antiqs.out.txt"); for (int i = 0; i < n; i++) { fileOut << array[i] << " "; } fileOut.close(); delete[] array; // 释放动态数组内存 return 0; }
修复后的关键改进
- 递归逻辑简化:递归函数直接填充每个区间的元素,通过引用传递
current_max,每次放置后递减,确保每个元素都是1~N的唯一值。 - 区间边界正确处理:单独处理空区间和单个元素的情况,直接放置当前最大元素,避免遗漏。
- 避免栈溢出:改用动态数组在堆上分配内存,适配N最大70000的场景。
- 去掉冗余操作:递归过程中直接填充所有位置,无需再处理0值,彻底避免元素重复或缺失。
测试验证
比如N=4时,修复后的代码生成数组[3,4,2,1]:
- 第一次基准是4,和3、2、1比较(3次)
- 左区间无需排序
- 右区间基准是2,和1比较(1次)
总比较次数4次,确实是最坏情况。
再比如N=5时,生成数组[4,5,3,1,2]:
- 基准5,和4、3、1、2比较(4次)
- 左区间无需排序
- 右区间基准是3,和1、2比较(2次)
总比较次数6次,符合最坏情况的要求。
内容的提问来源于stack exchange,提问作者user17109797
相关产品推荐
相关产品推荐

