当前位置: 首页 > 知识库问答 >
问题:

基于CLRS的合并排序算法介绍,带反转计数,C语言实现

戚浩淼
2023-03-14

我基于CLRS合并排序伪代码实现了一个计算逆序的合并排序,但是答案不正确,不能对数组进行排序,也不能正确计算逆序。

反转的定义:设A[1… n]是一个由n个不同整数组成的数组。如果我

我使用引用传递来处理相同的向量。

int mergeSortInvCount(vector<int> &arr, int izq, int der);
int mergeInvCount(vector<int> &arr, int izq, int mitad, int der);

void invCountRecursivo(vector<int> &arr, int n){



    int numInversiones = mergeSortInvCount(arr, 1, n);
    cout << "Num inversiones:" << numInversiones << endl;
    for(int i=0; i < n; i++){

        cout<<arr[i]<<endl;
    }
}

int mergeSortInvCount(vector<int> &arr, int izq, int der){

    int invCount = 0;

    if(izq < der){

        int mitad = (izq + der)/2;

        invCount = mergeSortInvCount(arr, izq, mitad);
        invCount += mergeSortInvCount(arr, mitad+1, der);
        invCount += mergeInvCount(arr, izq, mitad, der);
    }

    return invCount;
}

int infinito = numeric_limits<int>::max();

int mergeInvCount(vector<int> &arr, int izq, int mitad, int der){

    int n1 = mitad - izq + 1;
    int n2 = der - mitad;

    int invCount = 0;

    vector<int> vectorIzq;
    vector<int> vectorDer;

    for(int k=0;k<n1;k++){

        vectorIzq.push_back(arr[izq+k-1]);
    }

    vectorIzq.push_back(infinito);

    for(int k=0;k<n2;k++){

        vectorDer.push_back(arr[mitad+k]);
    }

    vectorDer.push_back(infinito);

    int i = 0;
    int j = 0;

    for(int k = izq; k <= der; k++){

        if(vectorIzq[i] <= vectorDer[j]){

            arr[k] = vectorIzq[i];
            i++;
        }
        else{

            arr[k] = vectorDer[j];
            j++;
            invCount += (mitad - i);
        }
    }

    return invCount;
}

对于输入:{4,3,1,8,2}和5,正确答案是6逆,排序后的数组是{1,2,3,4,8}。它返回5个反演和{4,4,4,3,4}。

共有1个答案

贡念
2023-03-14

好吧,几个月过去了,尽管我确实使代码实现返回排序数组,但反转计数仍然存在错误。今天我研究并解决了它,所以它在这里。

首先,在mergeInvCount方法的最后一个for中,arr是用基于1的索引访问的,所以它不起作用,修复了它减去1以用基于0的索引访问。

其次,在比较要合并的两个辅助数组的条件中,我们必须计算反转的情况是不正确的。

当左辅助数组上的元素大于右辅助数组上的元素时,我们必须为该数字计算 1 次反转,为它之后的每个其他元素计算 1 次反转,除了“无限”comodin。由于辅助数组是由于递归调用而排序的,因此这是正确的。

当左辅助数组从索引1开始时,它就起作用了,因为减法(mid-i)返回有序辅助数组中剩余的元素数,而不考虑comodin。

但是当我们合并数组并且左侧不是从1开始时,减法无法在数组中的实际索引之后返回正确数量的元素。

所以这个问题的解决方案是使用n1,它存储左辅助数组中元素的数量。这样,(n1 - i)会返回正确的数字。

下面是工作代码:

int mergeSortInvCount(vector<int> &arr, int izq, int der);
int mergeInvCount(vector<int> &arr, int izq, int mitad, int der);

void invCountRecursivo(vector<int> &arr, int n){

    int numInversiones = mergeSortInvCount(arr, 1, n);
    cout << "Num inversiones:" << numInversiones << endl;
    cout << "Ordered array, ascendant order" << endl;
    for(int i=0; i < n; i++){
        cout<<arr[i]<<endl;
    }
}

int mergeSortInvCount(vector<int> &arr, int izq, int der){

    int invCount = 0;

    if(izq < der){

        int mitad = (izq + der)/2;
        invCount = mergeSortInvCount(arr, izq, mitad);
        invCount += mergeSortInvCount(arr, mitad+1, der);
        invCount += mergeInvCount(arr, izq, mitad, der);
    }

    return invCount;
}

int infinito = numeric_limits<int>::max();

int mergeInvCount(vector<int> &arr, int izq, int mitad, int der){

    int n1 = mitad - izq + 1;
    int n2 = der - mitad;

    int invCount = 0;

    vector<int> vectorIzq;
    vector<int> vectorDer;

    for(int k=0;k<n1;k++){

        vectorIzq.push_back(arr[izq+k-1]);
    }

    vectorIzq.push_back(infinito);

    for(int k=0;k<n2;k++){

        vectorDer.push_back(arr[mitad+k]);
    }

    vectorDer.push_back(infinito);

    int i = 0;
    int j = 0;

    for(int k = izq; k <= der; k++){

        if(vectorIzq[i] <= vectorDer[j]){

            arr[k-1] = vectorIzq[i];
            i++;
        }
        else{

            arr[k-1] = vectorDer[j];
            j++;
            invCount += (n1 - i);
        }
    }

    return invCount;
}

int main(){

    vector<int> v = {4,3,1,8,2};
    invCountRecursivo(v, 5);
    // Returns 6, the correct # of inversions of A

    return 0;
}
 类似资料:
  • 我正在学习如何在c中实现Mergesort,遇到了以下问题。 这是我的合并函数,它将两个排序数组合并为一个排序数组。 在任何时候,我都使用代码A或代码B。当我使用代码A时,函数按预期执行。然而,当我使用CODE B时,函数会用随机数据填充数组列表。 printArray是一个自定义函数,用于打印数组、列表。当对一组数字{4,2,6,9}进行排序时,我从printArray函数中得到以下输出:

  • 因此,我理解了使用合并排序对数组中的反转进行计数的一般思路。在合并过程中,您可以递归地计算左子数组和右子数组中的倒数。 这是我为此编写的一些代码。 我很难理解的是为什么在向其附加元素之前必须清除函数中的数组?有没有其他方法可以不清除数组?我问是因为我习惯于用编写合并排序

  • 我知道Stack中有很多这样的实现,但我遇到了一个我无法处理的问题。 首先,我用javascript在khanacademy实现了合并排序,然后我将代码重写为C,并尝试计算数组中的反转次数。 我尽我所能,花了一个小时试图了解我做错了什么。我确实在堆栈中搜索了另一个实现,并试图纠正我的代码。不幸的是,我不知道我做错了什么。我想我计算每一个反转。提前感谢您帮助您了解问题所在。 我的代码: 合并排序函数

  • 本文向大家介绍C语言实现冒泡排序算法,包括了C语言实现冒泡排序算法的使用技巧和注意事项,需要的朋友参考一下 BubblSort.c 以上所述就是本文的全部内容了,希望对大家学习C语言能够有所帮助。

  • 问题内容: 我正在尝试使用mergesort-我得到的- 计算列表中拆分反转的数量(也就是说,未排序列表的前半部分中的元素应该出现在列表的后半部分中的给定元素之后未排序的列表;例如[3 2 1 4]将包含分割反转(3,1),但不包含(3,2),因为3和2都在上半部。当我到达最终的打印语句时,我得到了我期望的答案- 在这种情况下为9-但是返回值都是不正确的,因为它通过递归返回分割值。我尝试了各种索引

  • 本文向大家介绍C语言字符串基本介绍,包括了C语言字符串基本介绍的使用技巧和注意事项,需要的朋友参考一下 示例 在C语言中,字符串是由空字符('\ 0')终止的字符序列。 我们可以使用字符串文字创建字符串,字符串文字是由双引号引起来的字符序列;例如,使用字符串literal "hello world"。字符串文字会自动以空值结尾。 我们可以使用几种方法创建字符串。例如,我们可以声明achar *并将