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

C++ 合并排序-返回新数组,而不是将合并的数组复制到输入数组,c++,arrays,algorithm,sorting,mergesort,C++,Arrays,Algorithm,Sorting,Mergesort,我正在尝试实现一个非常简单的合并排序版本(不考虑为此目的进行的所有优化),其中我的目标是返回合并数组的新副本,而不是通过引用传递输入数组并将合并元素复制到其中的传统方法 vector<int> merge(const vector<int> &left, const vector<int> &right) { vector<int> result( left.size() + right.size() ); auto

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

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;
}
为此,我的代码如下:

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;
}
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;
}
向量合并(向量左、向量右)
{
矢量结果;
int leftIdx=0;
int rightIdx=0;
int-resultix=0;
而(leftIdx
  • 我知道merge中的这个数组是一个本地数组,因此我将它返回到mergesort,mergesort将把它返回到main。 我是否错误地认为,这不是通过进出 后续递归调用

  • 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;
    }
    
  • 我对这段代码的测试输入是{1,0,9}。我应该得到{0,1,9},但我得到32767

  • 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;
    }
    

    这里我缺少什么?

    MergeSort
    的递归调用什么都不做,因为
    intar
    是按值(复制)获取的,而您没有使用结果值

    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;
    }
    
    像这样的方法应该会奏效:

    auto newLeft = MergeSort(leftArr);
    auto newRight = MergeSort(rightArr);
    
    recresult = merge(newLeft, newRight);
    
    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;
    }
    

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

    vector<int> result; // size = 0
    // ...
    result[resultIdx++] = left[leftIdx++]; // UB! 
    
    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;
    }
    
    向量结果;//大小=0
    // ...
    结果[resultIdx++]=左[leftIdx++];//乌布!
    

    在使用
    操作符[]
    访问元素之前,应该调用对
    MergeSort
    的递归调用,因为
    intArr
    是按值(复制)获取的,而不是使用结果值

    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;
    }
    
    像这样的方法应该会奏效:

    auto newLeft = MergeSort(leftArr);
    auto newRight = MergeSort(rightArr);
    
    recresult = merge(newLeft, newRight);
    
    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;
    }
    

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

    vector<int> result; // size = 0
    // ...
    result[resultIdx++] = left[leftIdx++]; // UB! 
    
    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;
    }
    
    向量结果;//大小=0
    // ...
    结果[resultIdx++]=左[leftIdx++];//乌布!
    

    对于
    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;
    }
    
    向量合并(常量向量与左、常量向量与右)
    {
    矢量结果;
    自动点亮=左。开始();
    auto rit=右。开始();
    while(lit!=left.end()| | rit!=right.end()){
    bool-lft=false;
    if(rit==right.end())
    lft=真;
    否则{
    if(lit!=left.end())
    lft=*发光<*rit;
    }
    结果。推回(lft?*lit++:*rit++);
    }
    返回结果;
    }
    
    或更接近您的版本:

    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;
    }
    
    向量合并(常量向量与左、常量向量与右)
    {
    向量结果(left.size()+right.size());
    自动重新设置=结果。开始();
    自动点亮=左。开始();
    auto rit=右。开始();
    while(lit!=left.end()&&rit!=right.end())
    *rst++=*lit<*rit?*lit++:*rit++;
    std::copy(lit,left.end(),rst);
    std::copy(rit,right.end(),rst);
    返回结果;
    }
    
    首先,对于
    合并
    ,应该将常量引用传递给参数,否则会产生太多不必要的副本。当您在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;
    }
    
    向量合并(常量向量与左、常量向量与右)
    {
    矢量结果;
    自动点亮=左。开始();
    auto rit=右。开始();
    while(lit!=left.end()| | rit!=right.end()){
    bool-lft=false;
    if(rit==right.end())
    lft=真;
    否则{
    if(lit!=left.end())
    lft=*发光<*rit;
    }
    结果。推回(lft?*lit++:*rit++);
    }
    返回结果;
    }
    
    或更接近您的版本:

    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;
    }
    
    向量合并(常量向量与左、常量向量与右)
    {
    向量结果(left.size()+right.size());
    自动重新设置=结果。开始();
    自动点亮=左。开始();
    auto rit=右。开始();
    while(lit!=left.end()&&rit!=right.end())
    *rst++=*lit<*rit?*lit++:*rit++;
    std::copy(lit,left.end(),rst);
    std::copy(rit,right.end(),rst);
    返回结果;
    }
    
    有UB用于
    结果的越界
    也有UB用于
    结果的越界
    您可能应该使用常量引用(
    const vector&intArr
    )作为
    MergeSort()
    的参数,以便在复制时保存而不修改原始数组。
    merge()
    也可能采用常量引用。实现“排序到新向量”要求的一个简单方法是在排序之前复制到新向量中。您需要仔细考虑返回类型-