计算快速排序中的元素比较数

时间:2015-04-23 16:59:13

标签: c++ sorting

我已经为快速排序提供了这个预定义的代码,不需要做太多改动:

我知道我们已经对此有疑问,但这是不同的,因为这里预定了逻辑。

void quicksort(int a[], int l, int r)
  {
    if (r <= l) return;
   /* call for partition function that you modify */ 
    quicksort(a, l, i-1);
    quicksort(a, i+1, r);
  }

int partition(int a[], int l, int r)
  { int i = l-1, j = r; int v = a[r];
    for (;;)
      { 
        while (a[++i] < v) ;
        while (v < a[--j]) if (j == l) break;
        if (i >= j) break;
        exch(a[i], a[j]);
      }
    exch(a[i], a[r]);
    return i;
  }

我们只需要稍作修改,以便快速排序返回它的比较次数,并且分区函数(总计)在排序给定数组a时执行了。 **在这些比较中,只计算涉及数组元素的比较。在计算这些比较时,不允许使用任何全局变量。 **

我已按照以下方式实施,如果我在某个地方弄错了,请告诉我:

int partition(int a[], int l, int r, int& count) {
    int i = l - 1, j = r; int v = a[r];
    for (;;) {
        while (a[++i] < v) count++;
        while (v < a[--j]) {
            count++;
            if (j == l) break;
        }
        if (i >= j) break;
        swap(a[i], a[j]);
    }
    swap(a[i], a[r]);
    return i;
}


int quickSort(int a[], int l, int r) {
    int count = 0;
    if (r <= l) return 0;
    int i = partition(a, l, r, count);
    return count + quickSort(a, l, i - 1) + quickSort(a, i + 1, r);
}

一旦你确认,我将与你分享我对此研究的惊人结果。

1 个答案:

答案 0 :(得分:0)

ricis评论作为解决方案很好。有一种可能采用的替代方法可以推广到std :: sort和其他算法,那就是进行计数比较。

的内容
struct CountingComparer{
    CountingComparer():count(0){}
    CountingComparer(const CountingComparer& cc):count(cc.count){}

    bool operator()(int lhs, int rhs){  
        count;  
        return lhs < rhs; 
    }

    size_t count;
};

现在您需要更改函数的签名以将比较器添加为最后一个参数。喜欢

template<typename COMP>
void quicksort( .... , COMP comp){

和分区功能一样的改变。然后通过

进行比较
 while (comp(a[++i],v))   and
 while (comp(v, a[--j])) respectively.

调用排序

您需要确保在模板参数中有对比较器的引用。

CountingComparer comp;
quicksort(...  , std::ref(comp));

确保不复制comp。

排序后,您可以在comp.count中找到比较次数。

关于您对计数的评论

维基百科页面上广泛讨论了您的快速排序行为。预计排序的数组表现不佳,而随机元素表现良好。

关于分区功能的聪明才智

for (;;)
  { 
    while (a[++i] < v) ;
    while (v < a[--j]) if (j == l) break;
    if (i >= j) break;
    exch(a[i], a[j]);
  }
exch(a[i], a[r]);
  • 第一个声明并不真正计算任何东西,所以这只是一段时间(真实)的伪装。它将以 break 语句结束。
  • 找到要交换的第一个大元素:while (a[++i] < v);语句利用了枢轴`v或a [r]&#39;元素是最右边的元素。所以枢轴元件就像一个守卫。
  • 找到要交换的第一个小元素:while (v < a[--j]) if (j == l) break;没有透视的保证。而是检查最左边的限制。
  • 最后检查是为了查看分区是否完成。如果是这样就打破了无限循环,最后
  • swap(a[i], a[r]);,将枢轴元素排列到正确的位置。