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

合并排序-返回一个新数组,而不是将合并的数组复制到输入数组

张玺
2023-03-14

我试图实现一个非常简单的合并排序版本(不考虑为此目的进行的所有优化),我的目标是返回合并数组的新副本,而不是通过引用传递输入数组并将合并元素复制到其中的传统方法。

为此,我的代码如下:

vector<int> merge(vector<int> left, vector<int> right)
{
    vector<int> result;
    int leftIdx = 0;
    int rightIdx = 0;
    int resultIdx = 0;

    while (leftIdx < left.size() && rightIdx < right.size()) {
        if (left[leftIdx] < right[rightIdx]) {
            result[resultIdx++] = left[leftIdx++];
        } else {
            result[resultIdx++] = right[rightIdx++];
        }
    }

    while (leftIdx < left.size()) {
        result[resultIdx++] = left[leftIdx++];
    }

    while (rightIdx < right.size()) {
        result[resultIdx++] = right[rightIdx++];
    }

    return result;
}

vector<int> MergeSort(vector<int> intArr)
{
    vector<int> recresult;

    // base - if array is of length 1, nothing to do, return it as is
    if (intArr.size() == 1) {
        return intArr;
    } else {
        int mid = intArr.size() / 2;
        // copy left half
        vector<int> leftArr(intArr.begin(), intArr.begin() + mid);
        // copy right half
        vector<int> rightArr(intArr.begin() + mid, intArr.end());

        MergeSort(leftArr);
        MergeSort(rightArr);

        recresult = merge(leftArr, rightArr);
    }

    return recresult;
}

>

  • 我知道来自合并的这个数组是一个本地数组,因此我将它返回给mergesort,而mergesort又将它返回给main。假设这不会从后续的递归调用中传入和传出,我是否错了?

    我对这段代码的测试输入是{1,0,9}。我应该得到{0,1,9},但我得到32767。

    我错过了什么?

  • 共有2个答案

    谯翔
    2023-03-14

    首先对于merge——应该将常量引用传递给参数,否则会产生太多不必要的副本。此外,当您在empty中创建并按索引访问时,还可以访问结果。使用int作为索引不是一个好主意。所以简化的版本可能是:

    vector<int> merge(const vector<int> &left, const vector<int> &right)
    {
        vector<int> result;
        auto lit = left.begin();
        auto rit = right.begin();
        while( lit != left.end() || rit != right.end() ) {
            bool lft = false;
            if( rit == right.end() )
                lft = true;
            else {
                if( lit != left.end() )
                    lft = *lit < *rit;
            }
            result.push_back( lft ? *lit++ : *rit++ );
       }
       return result;
    }
    

    或更接近您的版本:

    vector<int> merge(const vector<int> &left, const vector<int> &right)
    {
        vector<int> result( left.size() + right.size() );
        auto rst = result.begin();
        auto lit = left.begin();
        auto rit = right.begin();
        while( lit != left.end() && rit != right.end() )
            *rst++ = *lit < *rit ? *lit++ : *rit++;
    
        std::copy( lit, left.end(), rst );
        std::copy( rit, right.end(), rst );
        return result;
    }
    
    尉迟明贤
    2023-03-14

    MergeSort的递归调用不起任何作用,因为intArr是按值(复制)获取的,而您没有使用结果值。

    像这样的方法应该有用:

    auto newLeft = MergeSort(leftArr);
    auto newRight = MergeSort(rightArr);
    
    recresult = merge(newLeft, newRight);
    

    正如Slava在评论中提到的,在访问结果时也有UB,因为它的大小为0:

    vector<int> result; // size = 0
    // ...
    result[resultIdx++] = left[leftIdx++]; // UB! 
    

    在使用操作符[]访问元素之前,应该调用std::vector::resize

     类似资料:
    • 我想写一个时间O(n*lgk)的算法,将k个排序数组合并成一个排序数组,其中n是所有输入数组的元素总数。 你能告诉我怎么做吗? 编辑:我编写了以下算法: 你能告诉我这是否正确吗?

    • 我写了3个方法来实现递归合并排序,参数数量有限(没有aux、lo、mid、hi)。我认为我的工作是这样的,但它并没有返回一个排序数组,尽管它在运行时没有任何编译错误。我已经摆弄了4个小时,似乎无法弄清楚我做错了什么,没有合并一个有序数组。我只从我的助教那里得到了非常模糊的输入,并且能够修复我正在遇到的一些问题,但是该方法仍然没有对项数组进行排序。欢迎任何关于我在这里做错了什么的建议。谢谢!

    • 我想用Javascript实现合并排序作为一种学习经验。我有mergeSort(unsortedArray)函数,它接受一个未经排序的数组,并使用合并排序策略对其进行排序。mergeSort()调用merge(leftArray,rightArray),后者将两个数组合并在一起,得到一个数组。 我认为问题出在merge()函数上。在数组[8,8,7,5,4,6,3,2,1,5,9,8,7,6,5,

    • 问题内容: 这是在采访中问我的,这是我提供的解决方案: 有没有更有效的方法可以做到这一点? 编辑:更正的长度方法。 问题答案: 稍有改进,但是在主循环之后,当到达另一个输入数组的末尾时,可以用来复制其中一个输入数组的结尾。但是,那不会改变你解决方案的性能特征。

    • 问题内容: 给定两个排序数组,如下所示: 我希望输出为: 要么: 我知道我可以执行以下操作: 我只是想知道是否有一种更快的方法,因为我要处理的数组具有数百万个元素。 任何想法都欢迎。谢谢 问题答案: 由于您使用numpy,因此我怀疑bisec根本不会对您有所帮助。因此,我建议您做两件事: 千万 不能 使用,使用方法,而不是这种种取代阵列,避免了复制。 必须使用没有到位的。因此,不要手动使用逻辑。I

    • 问题是关于从16:43到23:34的视频中的合并排序http://youtu.be/M814OagXWTI?t=16m43s 在退出左/右排序合并递归后,我不清楚我们是如何合并回这些子数组的。让我们从最底部开始,当我们的元素被分成两个子数组时,一个左子数组称为B,一个右子数组称为C。在16:43左右,我们跳转到合并函数,对数组B和C进行排序,这两个数组只有8和3。合并排序函数(下面的代码)基本上通