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

时间:2016-12-13 16:38:24

标签: c++ arrays algorithm sorting mergesort

我试图实现一个非常天真的Merge Sort版本(不考虑所有用于此目的的优化),其中我的目标是返回合并数组的新副本而不是传递输入的传统方式通过引用数组并将合并的元素复制到其中。

为此,我的代码如下:

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,而mergesort又将它返回到main。 我错误地认为这不是传入和传出的 后续的递归调用?

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

  3. 我在这里缺少什么?

2 个答案:

答案 0 :(得分:3)

MergeSort的递归调用不执行任何操作,因为intArr由值(已复制)执行,并且您未使用结果值。

这样的事情应该有效:

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

答案 1 :(得分:1)

首先是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;
}