当我运行代码时,我会得到很多重复的数字和/或大的负数,当你把数据添加到数组中时,通常会出现这些数字。我相信问题是当我在进行合并时。
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++;
}
}
}
这可能像迭代问题一样愚蠢......任何想法?
答案 0 :(得分:2)
在这一行:
tmpArray1[i] = list[lb + i - 1];
当然你的意思是:
tmpArray1[i] = list[lb + i];
否则,您从给定的合并边界外部获取一个值,这将解释重复的数字。回写到列表时,不要使用该逻辑。
答案 1 :(得分:2)
我假设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
。
使用sentinel值来标记数组的结尾是不合理的,你应该使用索引来检测它。
答案 2 :(得分:1)
您的算法存在一些问题。
首先,它会导致内存泄漏,因为它会分配从不删除的数组。需要一些delete[]
指令来解决问题。
其次,索引错误:某些索引变为否定,您肯定不想要(例如,当您执行tmpArray1[i] = list[lb + i - 1];
时,因为lb
和{{1可以是0)。
第三,你缺少基本步骤:你永远不会交换两个元素的值。您的递归步骤看起来很好,但递归必须结束并在某个时刻执行某些具体操作(即,当您的范围仅跨越2个元素时)。你的i
函数会拆分范围,只是递归调用第一个和第二个子范围的自身,但是当递归结束时它们不会对它们做任何事情。
第四,你没有正确处理两个子范围不同尺寸的情况(一个子范围可能比另一个子范围大一个)。
以下是修复代码的方法(在GCC 4.7.2上测试):
mergeSort()