C++带比较计数的快速排序实现输出与预期不符问题
快速排序计数结果偏差的原因与修正
问题根因
你当前的比较计数存在系统性漏算,导致所有规模下的输出值比预期低40%左右,核心漏算点分为三类:
- 中值选取环节的比较完全未统计:
sortFirstMiddleLast及底层调用的order函数,每次会做3次数组元素大小判断,但这部分逻辑完全没有接入计数体系,每调用一次中值排序就会漏算3次有效比较。 - 双指针移动的计数逻辑不完整:C++的
while循环是先判断条件、再执行循环体,你现在仅在循环体内(即条件成立、指针移动时)累加计数器,完全漏掉了那些条件不成立、直接触发循环退出的比较场景。比如左指针第一次访问的元素就大于等于 pivot 时,这次大小判断你根本没有做计数。 - 计数器传递链路断裂:当前的引用计数器仅覆盖了双指针移动的统计逻辑,没有关联到中值选取环节的比较行为。
具体修正操作
1. 打通中值环节的计数传递
将order函数改造为可返回单次比较次数的形式,匹配插入排序的计数规则(只要执行元素大小判断就计数,不管是否触发交换):
template<class ItemType> int order(ItemType theArray[], int i, int j) { if (theArray[i] > theArray[j]) { std::swap(theArray[i], theArray[j]); } return 1; // 每次判断固定为1次有效比较 }
调整sortFirstMiddleLast函数,将三次order调用的比较次数累加到外部计数器:
template<class ItemType> int sortFirstMiddleLast(ItemType theArray[], int first, int last, int &counter) { int mid = first + (last - first) / 2; counter += order(theArray, first, mid); counter += order(theArray, mid, last); counter += order(theArray, first, mid); return mid; }
2. 修正双指针循环的计数逻辑
替换partition函数中左右指针的移动逻辑,确保每一次大小判断都被计数,和插入排序的计数标准完全对齐:
原代码仅在指针移动时计数,漏算退出循环的场景:
// 原有错误逻辑 while (theArray[indexFromLeft] < pivot) { counter++; indexFromLeft++; } while (theArray[indexFromRight] > pivot) { counter++; indexFromRight--; }
修正后覆盖所有判断场景:
// 左指针:每次判断先计数,再决定是否移动指针 while (true) { counter++; if (theArray[indexFromLeft] >= pivot) break; indexFromLeft++; } // 右指针:每次判断先计数,再决定是否移动指针 while (true) { counter++; if (theArray[indexFromRight] <= pivot) break; indexFromRight--; }
3. 适配参数传递
修改partition函数内调用sortFirstMiddleLast的代码,将计数器作为参数传入:
int pivotIndex = sortFirstMiddleLast(theArray, first, last, counter);
修正效果
按照上述逻辑调整后,固定seed的测试下:
- 数组规模10时的比较次数将达到预期的35次
- 规模100、1000、10000的计数会逐步匹配630、10292、132882的预期值
注:你当前设置的
MIN_SIZE = 10的分支判断逻辑是正确的——数组长度小于10时走插入排序,大于等于10时走快排分支,和测试要求一致,无需调整阈值。
内容的提问来源于stack exchange,提问作者NinjaBanna
相关产品推荐
相关产品推荐

