需要帮助找出我在这个Inversions算法中做错了什么(基于合并排序)

时间:2016-07-16 05:48:05

标签: c++ algorithm sorting

目标是找到整数数组中的反转次数。例如,

  

给出:(1,3,5,2,4,6)

     

反转是:(3,2),(5,4),(5,2)。

也就是说,共有三个反转。 O(n ^ 2)解决方案需要两个for循环,但对于大型输入数组需要太长时间。由于合并排序需要O(n(log(n)))时间,因此在这种情况下实现它是有意义的。

通过划分&征服方法,我们可以实现O(n(log(n)))。解决方案是所采取的倒置的总和。反转如下(对于大小为'n'的输入数组):

  如果i,j <= n / 2

,则

左反转      如果i,j&gt;

正确反转n / 2

     如果i <= n / 2

,则分裂反转。 Ĵ

注意:当arr [i]&gt;时,完成分割反转。 arr [j]和i&lt;学家

在上述权利要求的基础上,这是我写的下面的算法(其中我首先编写了合并排序,然后相应地调整它以返回反转次数),我得到了错误的输出。我无法弄清楚我哪里出错了。

(如果需要,请询问其他信息。我已经坚持了一段时间)。

#include<iostream>
#include<vector>
using namespace std;

int merge(vector <int> & arr, int l, int m , int r)
{
    int i,j,k;
    int count = 0;
    int n1, n2;

    n1=m-l+1;
    n2=r-m;

    //temporary arrays to store the elements.

    int L[n1];
    int R[n2];

    for (int i = 0; i < n1; ++i)
    {
        L[i]=arr[l+i];
    }

    for (int j = 0; j < n2; ++j)
    {
        R[j]=arr[m+1+j];
    }

    i=0;
    j=0;
    k=l;

    while(i<n1 && j<n2)
    {
        if (L[i]<R[j])
        {
            arr[k]=L[i];
            i++;
        }

        else
        {
            arr[k]=R[j];
            j++;
            count=count+(m-i);
        }
        k++;
    }

    while(i<n1)
    {
        arr[k]=L[i];
        i++;
        k++;
    }

    while(j<n2)
    {
        arr[k]=R[j];
        j++;
        k++;
    }

    return count;
}

int mergeSort(vector <int> & arr, int l, int r)
{
    int m;
    int count=0;

    /*
     if (l<r)

     {

     m=l+(r-l)/2;



     mergeSort(arr, l, m);//used to recursively sort the left half of the array

     mergeSort(arr,m+1,r);//used to recursively sort the right half of the array

     merge(arr,l,m,r);//merges both arrays together.

     }
     */


    if(l<r)
    {

        m = (l + r) / 2;

        count =

        (mergeSort(arr, l, m) +

         mergeSort(arr, m+1, r) +

         merge(arr, l, m, r));

        return count;

    }

    else

        return 0;

}


void printArray(vector <int> A, int size)

{

    for (int i = 0; i < size; ++i)

    {
        cout<<A[i]<< " ";
    }

    cout<<endl;

}

int main()

{

    int n;

    cin>>n;

    //int arr[n];

    vector<int> arr(n);

    int i;


    for (i=0; i<n; i++) {

        cin>>arr[i];

    }
    /*
     cout<<"the given array is : "<<endl;
     printArray(arr, n);
     */        
    cout<<"the number of inversions are : "<<endl;
    cout<< mergeSort(arr, 0, n - 1) <<endl;
    /*        
     cout<<"the sorted array is : "<<endl;
     printArray(arr, n);
     */      
    return 0;

}
  

测试用例:

     

案例1

     

输入:

     

(对于n = 6)

     

1 3 5 2 4 6

     

预期产出:   3

     

获得输出:   1

     

案例2

     

输入:

     

(对于n = 15)

     

9 12 3 1 6 8 2 5 14 13 11 7 10 4 0

     

预期产出:   56

     

获得输出:   125

1 个答案:

答案 0 :(得分:2)

问题在于计算我们在每一步中获得的反转次数。让我们来看看合并: 我们有两个数组L和R,并且在每次迭代中我们查看每个数组中的第一个数字(因为它们已经被排序):

1)。 L [i]&lt; = R [j]。这意味着L [i]不会使用来自R的一些剩余元素创建新的反转。

2)。 L [i]&gt; [R [J]。这意味着R [j]将产生L [i],L [i + 1],L [i + 2],...,L [n1 - 1]的反演。从我看到你的错误是计数计算。您添加(m - i)而不是(n1 - i)。 我看到的另一个错误是计数类型。如果你假设尺寸相当大(~10 ^ 5),你需要一些更大的类型来存储你的价值。

希望这有帮助。