【问题标题】:count swap/comparisons numbers of merge sort algorithm计算合并排序算法的交换/比较数
【发布时间】:2018-05-30 17:38:52
【问题描述】:

我需要计算在合并排序期间发生了多少交换和比较,我认为我的比较数计数很好,只是由于递归,我得到的数字与我的数组长度一样多,不知何故我需要将这些数字存储到合并中的变量中排序功能?也很想知道如何计算总掉期

    void merge(double arr[], int l, int m, int r)
    {
        int counter = 0;//number of comparisons
        int i, j, k;
        int n1 = m - l + 1;
        int n2 =  r - m;
        int cc;
        /* create temp arrays */
        double L[n1], R[n2];
        /* Copy data to temp arrays L[] and R[] */
        for (i = 0; i < n1; i++)
            L[i] = arr[l + i];
        for (j = 0; j < n2; j++)
            R[j] = arr[m + 1+ j];
        /* Merge the temp arrays back into arr[l..r]*/
        i = 0; // Initial index of first subarray
        j = 0; // Initial index of second subarray
        k = l; // Initial index of merged subarray
        while (i < n1 && j < n2)
            {

                if (L[i] <= R[j])
                {
                    arr[k] = L[i];
                    i++;
                }
                else
                {
                    arr[k] = R[j];
                    j++;
                }
                k++;
                counter++;
        }
        cout << counter << endl;
    /* Copy the remaining elements of L[], if there
       are any */
        while (i < n1)
        {
            arr[k] = L[i];
            i++;
            k++;
        }
    /* Copy the remaining elements of R[], if there
       are any */
        while (j < n2)
        {
            arr[k] = R[j];
            j++;
            k++;
              }
    }
    void mergeSort(double arr[], int l, int r)
         {
          if (l < r)
         {
            // Same as (l+r)/2, but avoids overflow for
        // large l and h
        int m = l+(r-l)/2;
        // Sort first and second halves
        mergeSort(arr, l, m);
        mergeSort(arr, m+1, r);
        merge(arr, l, m, r);
        }
    }

【问题讨论】:

  • 如果你想搜索它,它通常被称为计数反转(而不是交换)。您可以在合并期间对它们进行计数,假设您返回并求和反转计数。
  • double L[n1], R[n2]; -- 这不是有效的 C++。 C++ 中的数组必须使用编译时常量声明,而不是变量。其次,您可以轻松地将整个代码放在一个类中,并拥有一个名为 swapCount 的成员变量,该变量会递增,而不是本地的 counter 变量。

标签: c++ algorithm sorting merge


【解决方案1】:

我会以不同的方式完成这项工作。

我不会尝试对排序本身进行检测以跟踪数量或比较和交换,而是创建一个类型来跟踪比较和/或交换的次数。我懒得写一个完整的合并排序来演示它,但这里有一个做冒泡排序:

#include <algorithm>
#include <iostream>
#include <vector>

namespace instrumented {

    template <class T>
    class wrapper {
        T value;
    public:
        static std::size_t comparisons;
        static std::size_t swaps;
        wrapper(T val) : value(val) {}
        bool operator<(wrapper const &other) { ++comparisons; return value < other.value; }
        operator T() const { return value; }

        static void reset() { comparisons = swaps = 0; }

        static std::ostream &report(std::ostream &os) {
            os << "comparisons: " << comparisons << "\n";
            os << "swaps: " << swaps << "\n";
            comparisons = 0;
            swaps = 0;
            return os;
        }
    };

    template <class T>
    std::size_t wrapper<T>::comparisons;

    template <class T>
    std::size_t wrapper<T>::swaps;

    template <class T>
    void swap(wrapper<T> &a, wrapper<T> &b) {
        ++wrapper<T>::swaps;
        auto temp{ a };
        a = b;
        b = temp;
    }
}

template <class T>
void sort(std::vector<T> &input) {
    std::vector<instrumented::wrapper<T>> values;

    for (auto const & i : input)
        values.push_back(i);

    for (auto i = 0; i < values.size() - 1; i++)
        for (auto j = i + 1; j < values.size(); j++)
            if (values[j] < values[i])
                swap(values[i], values[j]);

    values[0].report(std::cout);
}

int main() {
    std::vector<int> inputs1{ 5, 4, 3, 2, 1 };
    sort(inputs1);
    std::cout << "\n";

    std::vector<int> inputs2{ 10, 9, 7, 8, 5, 100, 2, 3, 1, 17, 6 };
    sort(inputs2);
}

请注意,有了这个,您应该能够(例如)获得std::sort、std::partial_sort 等的结果,而不仅仅是您自己的排序函数。

【讨论】:

  • 谢谢你的回答,这对我来说似乎有点太复杂了(刚开始编程 c++),但我会尝试一下。
【解决方案2】:

如果我理解正确,则在合并步骤中更改原始数组时会发生交换。因此,在每次合并调用中,我都会查看原始索引中的值,并将其与对应于该索引的新形成的值进行比较。如果它们不同,我会增加交换。

int swap=0;

int index(std::vector<double> v,double val){

auto match = std::find(v.begin(), v.end(), val);
return match-v.begin();

}

std::vector<double> merge(std::vector<double> v1,std::vector<double> v2,std::vector<double>& v,int start){

auto it1=std::begin(v1);
auto it2=std::begin(v2);

std::vector<double> newvec;

while(it1!=v1.end() && it2!=v2.end()){

    if(*it1<=*it2){

        newvec.push_back(*it1);

        const FloatingPoint<double> l1(*it1), r1(v.at(index(newvec,*it1)+start));

        if (!l1.AlmostEquals(r1)) swap++;

        it1++;

    }

    else{

        newvec.push_back(*it2);

        const FloatingPoint<double> l2(*it2), r2(v.at(index(newvec,*it2)+start));

        if (!l1.AlmostEquals(r1)) swap++;

        it2++;

    }

}

while(it1!=v1.end()){

    newvec.push_back(*(it1++));

    const FloatingPoint<double> l3(*it1), r3(v.at(index(newvec,*it1)+start));

    if (!l3.AlmostEquals(r3)) swap++;

}

while(it2!=v2.end()){

   newvec.push_back(*(it2++));

    const FloatingPoint<double> l4(*it2), r4(v.at(index(newvec,*it2)+start));

    if (!l4.AlmostEquals(r4)) swap++;


}

return newvec;

} 


 std::vector<double> merge_sort(std::vector<double> v,int start){ // start=0 when it is first called

int size=v.size();

if(size==1) return v;

std::vector<double> merged1,merged2;

auto it=v.begin();

merged1.assign(it,it+(size+1)/2);
merged2.assign(it+(size+1)/2,v.end());

std::vector<double> v1=merge_sort(merged1,start);
std::vector<double> v2=merge_sort(merged2,start+(size+1)/2);

v=merge(v1,v2,v,start);

return v; 

}

【讨论】:

    【解决方案3】:

    这类似于@JerryCoffin 给出的答案,但可能更容易让你消化。

    一个简单的解决方案是将这段代码放在一个类中,并有一个成员变量,可能称为int swapcount,每次交换完成时都会递增。这减轻了维护本地交换计数器变量的负担。

    class MergeSorter
    {
       int swapCount;
       void merge(double arr[], int l, int m, int r);
       void mergeSort(double arr[], int l, int r);
    
       public:
           MergeSorter() : swapCount(0) { }
           void startSort(double arr[], int l, int r);
           int getSwapCount() const { return swapCount; }
    };
    
    void MergeSorter::merge(double arr[], int l, int m, int r)
    {
       // code here to merge.  In here, you increment swapCount
    }
    
    void MergeSorter::mergeSort(double arr[], int l, int r)
    {
        if (l < r)
        {
            int m = l+(r-l)/2;
            mergeSort(arr, l, m);
            mergeSort(arr, m+1, r);
            merge(arr, l, m, r);
        }    
    }
    
    void MergeSorter::startSort(double arr[], int l, int r)
    {
      swapCount = 0;  // start at 0
      mergeSort(arr, l, r);
    }
    
    int main()
    {
       double arr[] = {1, 2, 3, 45, 5, 7};
       MergeSorter ms;
       ms.startSort(arr, 0, 5); // or whatever the arguments are
       std::cout << "The number of swaps is " << ms.getSwapCount();
    }
    

    请注意,我们有一个函数startSort,它在类中启动排序。在merge 函数中,swapCount 根据需要递增。最后我们只输出ms.swapCount的值。

    【讨论】:

    • 谢谢!在 MergeSorter 函数中,我在什么运算符下增加 swapCount?
    • 那比较数呢?它可能非常相似,如果你不介意的话,也很想知道如何计算它!
    • @TautvydasBūda -- 您以与之前完全相同的方式增加交换计数。这个答案简单地展示了如何设置一种方法来保持计数统计信息,而不是试图在局部变量周围玩弄。
    猜你喜欢
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    相关资源
    最近更新 更多