簡體   English   中英

計算快速排序中元素比較的數量

[英]Counting the Number of Element Comparisons in Quick Sort

已為我提供了用於快速排序的預定義代碼,該代碼不會有太大變化:

我知道我們已經對此有疑問,但這是不同的,因為此處已預定義了邏輯。

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;
  }

我們只需要進行一些修改,以便quicksort返回它的比較次數,並且分區函數(總共)一起對給定數組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);
}

您確認后,我將與您分享我對此事的驚人研究結果。

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.

調用排序

您需要確保您在template參數中具有對比較器的引用。

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

確保未復制伴奏。

排序后,您可以在comp.count中找到比較數。

關於您對計數的評論

在Wikipedia頁面上廣泛討論了quicksort的行為。 可以預期排序后的數組表現不佳,而隨機元素表現良好。

關於分區功能的巧妙之處

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]);
  • 第一個for語句實際上並沒有計算任何內容,因此僅是偽裝了片刻。 它將以break語句結束。
  • 找到第一個要交換的大元素: while (a[++i] < v); 語句利用了樞軸“ v或a [r]”元素是最右邊的元素這一事實。 因此,樞軸元件在這里起着警衛的作用。
  • 找到第一個要交換的小元素: while (v < a[--j]) if (j == l) break; 沒有樞軸的保證。 而是檢查最左邊的限制。
  • 最后的檢查只是看分區是否完成。 如果是這樣,就跳出無限循環,最后
  • swap(a[i], a[r]); ,將樞軸元件布置到正確的位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM