You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

快速排序算法比较次数统计结果与预期不符问题排查

问题:快速排序比较次数统计错误排查

我实现了结合三数取中(median-of-three) pivot选择与插入排序优化的快速排序算法,尝试统计排序过程中的比较次数。使用固定种子生成大小为10、100、1000、10000的随机数组,确保每次数组元素一致以便验证计数准确性。当前得到的比较次数为13、147、1506、11014,但预期结果应为25、630、10292、132882。


相关代码

quicksort.hpp

/**
 * @file quicksort.hpp
 */

#ifndef QUICKSORT_H
#define QUICKSORT_H

#include <algorithm>

static const int MIN_SIZE  = 10; // Smallest size of an array that quicksort will sort

/**
 * Sorts the items in an array into ascending order.
 * @pre  None.
 * @post  theArray is sorted into ascending order; n is unchanged.
 * @param theArray  The given array.
 * @param first  The first element to consider in theArray.
 * @param last  The last element to consider in theArray.
 * @return the number of comparisons
 */
template<class ItemType>
int insertionSort(ItemType theArray[], int first, int last) {
    int counter = 0;
    for (int unsorted = first + 1; unsorted <= last; unsorted++) {
        ItemType nextItem = theArray[unsorted];
        int loc = unsorted;
        while ((loc > first) && (counter++, theArray[loc - 1] > nextItem)) {
            
            theArray[loc] = theArray[loc - 1];
            loc--;
        }
        theArray[loc] = nextItem;
    }
    return counter;
}

/**
 * Arranges two specified array entries into sorted order by
 * exchanging them, if necessary.
 * @param theArray  The given array.
 * @param i  The index of the first entry to consider in theArray.
 * @param j  The index of the second entry to consider in theArray.
 * */
template<class ItemType>
void order(ItemType theArray[], int i, int j) {
    if (theArray[i] > theArray[j]) {
        std::swap(theArray[i], theArray[j]);
    }
}

/** 
 * Arranges the first, middle, and last entry in an array in sorted order.
 * @pre  theArray[first..last] is an array; first <= last.
 * @post  theArray[first..last] is is arranged so that its
 * first, middle, and last entries are in sorted order.
 * @param theArray  The given array.
 * @param first  The first entry to consider in theArray.
 * @param last  The last entry to consider in theArray.
 * @return  The index of the middle entry.
 */
template<class ItemType>
int sortFirstMiddleLast(ItemType theArray[], int first, int last) {
    int mid = first + (last - first) / 2;
    order(theArray, first, mid); // Make theArray[first] <= theArray[mid]
    order(theArray, mid, last);  // Make theArray[mid] <= theArray[last]
    order(theArray, first, mid); // Make theArray[first] <= theArray[mid]

    return mid;
}

/**
 * Partitions the entries in an array about a pivot entry for quicksort.
 * @pre  theArray[first..last] is an array; first <= last.
 * @post  theArray[first..last] is partitioned such that:
 * S1 = theArray[first..pivotIndex-1] <= pivot * theArray[pivotIndex] == pivot
 * S2 = theArray[pivotIndex+1..last]  >= pivot
 * @param theArray  The given array.
 * @param first  The first entry to consider in theArray.
 * @param last  The last entry to consider in theArray.
 * @return  The index of the pivot.
 */
template<class ItemType>
int partition(ItemType theArray[], int first, int last, int counter) {
    // Choose pivot using median-of-three selection
    int pivotIndex = sortFirstMiddleLast(theArray, first, last);

    // Reposition pivot so it is last in the array
    std::swap(theArray[pivotIndex], theArray[last - 1]);
    pivotIndex = last - 1;
    ItemType pivot = theArray[pivotIndex];

    // Determine the regions S1 and S2
    int indexFromLeft = first + 1;
    int indexFromRight = last - 2;

    bool done = false;
    while (!done) {
        // Locate first entry on left that is >= pivot
        
        while (counter++, theArray[indexFromLeft] < pivot) {
            
            indexFromLeft = indexFromLeft + 1;
        }
        
        // Locate first entry on right that is <= pivot
        while (counter++, theArray[indexFromRight] > pivot) {
            indexFromRight = indexFromRight - 1;
            
        }
    
        if (indexFromLeft < indexFromRight) {
            std::swap(theArray[indexFromLeft], theArray[indexFromRight]);
            indexFromLeft = indexFromLeft + 1;
            indexFromRight = indexFromRight - 1;
            
        }
        else {
            done = true;
        }
    }

    // Place pivot in proper position between S1 and S2, and mark its new location
    std::swap(theArray[pivotIndex], theArray[indexFromLeft]);
    pivotIndex = indexFromLeft;

    counter++;

    return pivotIndex;
}

/**
 * Sorts an array into ascending order. Uses the quick sort with
 * median-of-three pivot selection for arrays of at least MIN_SIZE
 * entries, and uses the insertion sort for other arrays.
 * @pre  theArray[first..last] is an array.
 * @post  theArray[first..last] is sorted.
 * @param theArray  The given array.
 * @param first  The first element to consider in theArray.
 * @param last  The last element to consider in theArray.
 * @return the number of comparisons
 */
template<class ItemType>
int quicksort(ItemType theArray[], int first, int last, int& counter) {
    
    if (last - first + 1 < MIN_SIZE) {
        counter += insertionSort(theArray, first, last);
    }
    else {
        // Create the partition: S1 | Pivot | S2
        int pivotIndex = partition(theArray, first, last, counter);

        // Sort subarrays S1 and S2
        quicksort(theArray, first, pivotIndex - 1, counter);
        quicksort(theArray, pivotIndex + 1, last, counter);
    }
    return counter; 
}

#endif

主函数调用代码

std::cout << "Quicksort                               ";
    std::cout << "    " << std::left << quicksort(makeRandomArray(10, seed), 0, 10-1, comparisons);
    comparisons = 0;
    std::cout << "    " << quicksort(makeRandomArray(100, seed), 0, 100-1, comparisons);
    comparisons = 0;
    std::cout << "    " << quicksort(makeRandomArray(1000, seed), 0, 1000-1, comparisons);
    comparisons = 0;
    std::cout << "    " << quicksort(makeRandomArray(10000, seed), 0, 10000-1, comparisons) << std::endl;

随机数组生成代码

int* makeRandomArray(int n, int seed) {
srand(seed);
int * a = new int[n];
for (int i = 0; i < n; i++) {
    a[i] = rand() % 1000;
}
return a;
}

错误排查与修正

你的计数逻辑存在多处遗漏和错误,导致统计结果远低于预期,具体问题和修复方案如下:

1. partition函数计数器传递方式错误

当前partition的counter是按值传递,函数内的累加不会影响外部的引用变量,必须改为引用传递:

// 修改前
int partition(ItemType theArray[], int first, int last, int counter) {
// 修改后
int partition(ItemType theArray[], int first, int last, int& counter) {
}

2. sortFirstMiddleLast中的比较未计数

order函数中的元素比较是快速排序的一部分,但完全未被统计。需要修改order函数并传递计数器引用:

// 修改后的order函数
template<class ItemType>
void order(ItemType theArray[], int i, int j, int& counter) {
    counter++; // 统计本次比较
    if (theArray[i] > theArray[j]) {
        std::swap(theArray[i], theArray[j]);
    }
}

// 修改后的sortFirstMiddleLast函数
template<class ItemType>
int sortFirstMiddleLast(ItemType theArray[], int first, int last, int& counter) {
    int mid = first + (last - first) / 2;
    order(theArray, first, mid, counter);
    order(theArray, mid, last, counter);
    order(theArray, first, mid, counter);

    return mid;
}

同时在partition中调用sortFirstMiddleLast时传入counter:

int pivotIndex = sortFirstMiddleLast(theArray, first, last, counter);

3. partition末尾的多余计数

partition最后一行的counter++;没有对应的比较操作,属于无效计数,直接删除。

4. 插入排序的计数逻辑遗漏边界比较

原插入排序的循环条件仅在loc > first为真时才计数,会漏掉部分元素比较。修改为明确计数每一次元素对比:

template<class ItemType>
int insertionSort(ItemType theArray[], int first, int last) {
    int counter = 0;
    for (int unsorted = first + 1; unsorted <= last; unsorted++) {
        ItemType nextItem = theArray[unsorted];
        int loc = unsorted;
        while (loc > first) {
            counter++;
            if (theArray[loc - 1] > nextItem) {
                theArray[loc] = theArray[loc - 1];
                loc--;
            } else {
                break;
            }
        }
        theArray[loc] = nextItem;
    }
    return counter;
}

内容的提问来源于stack exchange,提问作者imnapr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:10:55