C++:合并排序合并数组
C++: Merge Sort Merging Arrays
当我运行代码时,我得到很多重复的数字和/或大的负数,当你把东西添加到数组中时,这些数字和/或大的负数通常就会出现。我相信问题是当我进行合并本身时。
void mergeSort( int list[], int lb, int ub )
{
int mid;
if ( lb < ub )
{
mid = (lb + ub) / 2;
mergeSort(list, lb, mid);
mergeSort(list, mid + 1, ub);
myMerge(list, lb, mid , ub);
}
}
template <class M>
void myMerge( M list[], int lb, int mid, int ub )
{
int i, j;
int size1 = mid - lb + 1;
int size2 = ub - mid;
M* tmpArray1 = new M[size1 + 1];
M* tmpArray2 = new M[size2 + 1];
for( i=0; i<size1; i++ )
{
tmpArray1[i] = list[lb + i - 1];
}
for( j=0; j<size2; j++ )
{
tmpArray2[j] = list[mid + j];
}
tmpArray1[size1 + 1] = INT_MAX;
tmpArray2[size2 + 1] = INT_MAX;
i = 0;
j = i;
for( int k=lb; k<ub; k++ )
{
if ( tmpArray1[i] <= tmpArray2[j] )
{
list[k] = tmpArray1[i];
i++;
}
else
{
list[k] = tmpArray2[j];
j++;
}
}
}
这可能是像迭代问题一样愚蠢的事情......有什么想法吗?
在这一行中:
tmpArray1[i] = list[lb + i - 1];
你的意思肯定是这样的:
tmpArray1[i] = list[lb + i];
否则,您将从给定的合并边界之外获取一个值,这将解释重复的数字。 写回列表时不使用该逻辑。
我假设mergeSort
代码是正确的,这意味着ub
应该是要排序的范围的最后一个索引。如果不是这种情况,mergeSort
就被错误地实现了(merge
仍然会如此,但方式略有不同)。
填充tmpArray1
时,您可以从范围之前访问元素:
for( i=0; i<size1; i++ )
{
tmpArray1[i] = list[lb + i - 1];
}
范围中的第一个元素是 list[lb]
,而不是 list[lb-1]
。
填充tmpArray2
时,您会忽略范围末尾的一个元素:
for( j=0; j<size2; j++ )
{
tmpArray2[j] = list[mid + j];
}
这应该在那里list[mid + 1 + j]
。
时,不会将所有元素合并回来:
for( int k=lb; k<ub; k++ )
{
if ( tmpArray1[i] <= tmpArray2[j] )
{
list[k] = tmpArray1[i];
i++;
}
else
{
list[k] = tmpArray2[j];
j++;
}
}
这应该在循环控制中k <= ub
。
但是,最让我揉搓的是
tmpArray1[size1 + 1] = INT_MAX;
tmpArray2[size2 + 1] = INT_MAX;
如果数组包含 INT_MAX
,则必然会失败,如果元素类型为 long long
.
哨兵值来标记数组的末尾是不合理的,您应该使用索引来检测它。
你的算法有几个问题。
首先,它会导致内存泄漏,因为它分配了永远不会删除的数组。需要一些delete[]
说明来解决问题。
其次,存在索引错误:有些索引变为负数,这肯定是你不希望的(例如,当你做tmpArray1[i] = list[lb + i - 1];
时,因为lb
和i
都可以是0)。
第三,你缺少一个基本步骤:你从不交换两个元素的值。你的递归步骤看起来不错,但递归必须在某个时候结束并做一些具体的事情(即当你的范围只跨越 2 个元素时)。您的 mergeSort()
函数拆分范围,只是递归地为第一个和第二个子范围调用自身,但在递归结束时对它们不执行任何操作。
第四,您没有正确处理两个子范围具有不同大小的情况(一个子范围可能比另一个子范围逐个元素大)。
以下是您应该如何修复代码(在GCC 4.7.2上测试):
template <class M>
void myMerge( M arr[], int lb, int mid, int ub )
{
int i, j;
int size1 = mid - lb + 1;
int size2 = ub - mid;
M* tmpArray1 = new M[size1];
M* tmpArray2 = new M[size2];
for( i=0; i<size1; i++ )
{
tmpArray1[i] = arr[lb + i]; // THIS NEEDED FIXING
}
for( j=0; j<size2; j++ )
{
tmpArray2[j] = arr[mid + 1 + j]; // THIS NEEDED FIXING AS WELL (add +1...)
}
i = 0;
j = i;
for( int k=lb; k<=ub; k++ )
{
if (i == size1) // HANDLES THE CASE WHEN FIRST RANGE IS SMALLER
{
arr[k] = tmpArray2[j];
j++;
}
else if (j == size2) // HANDLES THE CASE WHEN SECOND RANGE IS SMALLER
{
arr[k] = tmpArray1[i];
i++;
}
else if ( tmpArray1[i] < tmpArray2[j] )
{
arr[k] = tmpArray1[i];
i++;
}
else
{
arr[k] = tmpArray2[j];
j++;
}
}
delete[] tmpArray1; // IMPORTANT! DON'T FORGET TO RELEASE
delete[] tmpArray2; // THE MEMORY YOU ALLOCATE...
}
void mergeSort( int arr[], int lb, int ub )
{
if (ub - lb > 1)
{
int mid = (lb + ub) / 2;
mergeSort(arr, lb, mid);
mergeSort(arr, mid + 1, ub);
myMerge(arr, lb, mid, ub);
}
else // DON'T FORGET TO ADD YOUR BASE STEP! (sort a trivial range of 2 elements)
{
if (arr[ub] < arr[lb])
{
int tmp = arr[ub];
arr[ub] = arr[lb];
arr[lb] = tmp;
}
}
}
// SOME TESTING...
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
int main()
{
int numbers[] = { 8, 40, 1, 5, 0, 9, 6, 4, 3, -1, 5 };
mergeSort(numbers, 0, 10);
copy(begin(numbers), end(numbers), ostream_iterator<int>(cout, " "));
}
- 合并排序不排序自创建数组类 c++
- 数组为此合并排序函数提供了正确的输出,但向量给出了不正确的输出.出了什么问题?
- 我如何根据 c++ 中的行合并两个 2D 数组
- 使用基于数组的列表 c++ 合并 2 个数组
- 如何在 char 数组中合并两个数组以通过网络发送
- 合并数组的程序打印 0 而不是实际合并的数组
- 如果数组长度为 100000,则使用合并排序对反转进行计数会给出负数
- 合并两个数组后数组大小不正确
- 如何修复合并两个C++数组时'Invalid Pointer'
- 在OpenMP上的并行合并排序上的数组大小问题.如何将合并分类分类为更多任务
- C++全局常量数组:是否保证合并(优化)到一个副本中
- C - 为什么合并函数在递归调用后会逆转数组
- 合并排序 - 返回新数组,而不是将合并的数组复制到输入数组
- C MPI:STD ::在数组上合并
- 合并排序问题,在方法之间传递数组
- C 合并的数组输出错误
- 我如何在INT数组上实现合并排序
- 我们如何在 C++ 中合并数组的元素
- C++:合并排序合并数组
- 用于合并数组的重载运算符+失败