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

使用合并排序计数反转

刘泰
2023-03-14

我知道Stack中有很多这样的实现,但我遇到了一个我无法处理的问题。

首先,我用javascript在khanacademy实现了合并排序,然后我将代码重写为C,并尝试计算数组中的反转次数。

我尽我所能,花了一个小时试图了解我做错了什么。我确实在堆栈中搜索了另一个实现,并试图纠正我的代码。不幸的是,我不知道我做错了什么。我想我计算每一个反转。提前感谢您帮助您了解问题所在。

我的代码:

int lowhalflength(int p, int q)
{
    return q - p + 1;
}

int highhalflength(int q, int r)
{
    return r - q;
}


int merge(int array[], int p, int q, int r, int lowhalf[], int highhalf[])
{
    int k = p;
    int i;
    int j;
    int count = 0;
    for (int i = 0; k <= q; i++ , k++)
    {
        lowhalf[i] = array[k];
    }
    for (int i = 0; k <= r; i++ , k++)
    {
        highhalf[i] = array[k];
    }

    k = p;
    i = 0;
    j = 0;

    while (i <= (q - p) && j <= r - (q + 1))
    {
        if (lowhalf[i] <= highhalf[j])
        {
            array[k] = lowhalf[i];
            i++;
        }
        else
        {
            array[k] = highhalf[j];
            j++;
            count += q - 1;
        }

        k++;
    }

    while (i < lowhalflength(p, q))
    {
        array[k] = lowhalf[i];
        k++;
        i++;
    }

    while (j < highhalflength(q, r))
    {
        array[k] = highhalf[j];
        k++;
        j++;
    }


    return count;
}

合并排序函数:

int mergeSort(int array[], int p, int r)
{
    int q = ((p + r) / 2);
    int* lowhalf = new int[lowhalflength(p, q)];
    int* highhalf = new int[highhalflength(q, r)];

    int count = 0;
    if (p < r)
    {
        q = ((p + r) / 2);
        count = mergeSort(array, p, q);
        count += mergeSort(array, q + 1, r);
        count += merge(array, p, q, r, lowhalf, highhalf);
    }
    delete[] lowhalf;
    delete[] highhalf;
    return count;
}

对于数组 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1],输出为 46,而应为 45。

编辑:答案是将下面一行< code>q-1改为< code > q j-k。我自己发现的,但我不知道应该如何解释它。任何提示或证明为什么它是正确的将是非常可取的。

共有2个答案

裘嘉木
2023-03-14

非常感谢你们所有人,尤其是@Shiv和@WhozCraig,你们给了我并知道如何解决它。答案是将 q-1 更改为 q j-k

程和蔼
2023-03-14

您可以使用我的代码来计算反转对,您的合并函数应该以更有效的方式如下所示:

int merge(int *array, int lower, int mid, int upper) {

    // Initialisation of the sizes of two subarrays and subarrays also.
    int left_array_size = mid - lower + 1;
    int right_array_size = upper - mid;
    int left_array[left_array_size], right_array[right_array_size];

    int j = 0;
    for (int i = lower; i <= mid; i++) {
        left_array[j++] = array[i];
    }
    j = 0;
    for (int i = mid + 1; i <= upper; i++) {
        right_array[j++] = array[i];
    }

    // Performing merging in a non-increasing manner and count inversion pairs..
    int i = 0, k;
    j = 0;
    int resultIntermediate = 0;
    for (k = lower; k <= upper; ) {
        if (left_array[i] <= right_array[j]) {
            array[k++] = left_array[i++];
            if (i >= left_array_size)   break;
        }
        else {
            array[k++] = right_array[j++];

            // If a element in left_array_size is greater than an element from
            // right_array_size then rest of all other elements will also be
            // greater than that element of right_array_size because both
            // subarrays are sorted in non-decreasing order.
            resultIntermediate += left_array_size - i;

            if (j >= right_array_size)  break;
        }
    } //end of for loop.


    // Performing merging if i or j doesn't reach to its
    // maximum value i.e. size of the subarrays.
    while (i < left_array_size) {
        array[k++] = left_array[i++];
    }
    while (j < right_array_size) {
        array[k++] = right_array[j++];
    }

    // Returning the result...
    return resultIntermediate;

} //end of the merge function.

并用于计数反转对

int countInversionPair(int *array, int lower, int upper) {
    int count_inv_pair = 0;
    // Do recusion untill the problem / array can be subdevided.
    if (lower < upper) {

        // Partition the Array into two subproblems.
        int mid = (lower + upper) / 2;

        // Call the countInversionPair() function for these two
        // subarrays / subproblems recursively to count number of
        // inversion for these subproblems / subarrays.
        count_inv_pair = countInversionPair(array, lower, mid);
        count_inv_pair += countInversionPair(array, mid + 1, upper);

        // Merge these two subarrays into a sigle array
        count_inv_pair += merge(array, lower, mid, upper);
    }
    return count_inv_pair;
}

现在您可以通过从main调用函数来获取反转对的数量:

int count_inv_pair = countInversionPair(array, 0, size - 1);

现在你会得到你的答案。。

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

  • 问题内容: 在对重复的字符串进行排序时遇到问题, 这是我的代码。 我成功地对第一个数组进行了排序,但是在第二个数组中(使用重复的字符串)似乎输出不井井有条,您能帮助我追踪代码中的错误吗。 这是输出: … 问题答案: 更改 与 输出

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

  • 双向合并排序与递归合并排序有何不同? 假设在合并排序中有5个数字需要排序8,9,1,6,4,我们按如下步骤1进行划分:{8,9,1}{6,4} 步骤2:{8,9}{1}{6}{4} 步骤3:{8}{9}{1}{6}{4} 现在合并 步骤4:{8,9}{1}{4,6} 步骤5:{1,8,9}{4,6} 第六步:{1,4,6,8,9} 但在双向合并排序中,我们将数组分为两个元素(但根据维基百科,在合并

  • 本文向大家介绍合并排序,包括了合并排序的使用技巧和注意事项,需要的朋友参考一下 合并排序技术基于分而治之。我们将整个数据集分成较小的部分,然后按排序顺序将它们合并成较大的部分。在最坏情况下它也非常有效,因为该算法在最坏情况下的时间复杂度也较低。 合并排序技术的复杂性 时间复杂度: 所有情况下为O(n log n) 空间复杂度:  O(n) 输入输出 算法 合并(数组,左,中,右) 输入- 数据集数

  • 我在名为的类中有一个链表,它包含以下属性: 我有另一个类,它是“实际列表”,它只包含对列表头部的引用,这个类被称为“文本列表”,它接收一个字符串,并假设将该字符串的每个单词排序在列表中。例如,对于句子: 链接列表如下所示: 箭头就像指向列表中下一个节点的指针。 我想先把所有的单词放在一个链表中(类),然后做一个MERGE SORT来对链表中的单词进行排序。 我想做的是采用拆分方法将列表拆分为两个列