C ++:合并排序合并数组

时间:2013-01-22 23:21:07

标签: c++ arrays sorting merge

当我运行代码时,我会得到很多重复的数字和/或大的负数,当你把数据添加到数组中时,通常会出现这些数字。我相信问题是当我在进行合并时。

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

这可能像迭代问题一样愚蠢......任何想法?

3 个答案:

答案 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()