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

Merge Sort - return a new array instead of copying merged array to input array

本文关键字:数组 合并 输入 复制 排序 返回 新数组      更新时间:2023-10-16

我正在尝试实现一个非常幼稚的合并形式(不考虑为此目的考虑所有优化),我的目标是返回合并数组的新副本,而不是传统的通过参考传递输入数组并将合并元素复制到其中的方式。

到此为止,我的代码如下:

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;
}
  1. 我知道Merge的此数组是本地数组,因此我将其返回Mergesort,然后将其返回到Main。我假设这不是从中传递和出来的,我错了吗随后的递归电话?

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

我在这里缺少什么?

MergeSort递归调用什么都不做,因为 intArr是通过value (复制)进行的,而您不使用结果值。

类似的东西应该有效:

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

如评论中提到的Slava,访问result时还具有UB,因为它的size为0:

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

您应该在使用operator[]访问元素之前调用std::vector::resize

首先是merge-您应该将const引用传递给参数,否则您会制作太多不必要的副本。另外,当您在空白处创建并通过索引访问时,您可以从对result的界限访问。使用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;
}