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
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(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()
也可能采用常量引用。实现“排序到新向量”要求的一个简单方法是在排序之前复制到新向量中。您需要仔细考虑返回类型-