我在使用Merge Sort功能时遇到了一些麻烦,因为我的教授给出了我的规范。一直在盯着VS和谷歌寻找这个家伙的永恒。
算法提供:
arrayFunctions.h
template<class T>
void printArray(T arr[], int numElements)
{
cout << "(";
for (int i = 0; i < numElements; i++)
{
cout << arr[i];
if (i < numElements - 1)
cout << ", ";
}
cout << ")" << "\n\n";
}
template <class T>
void setArray(T to[], T from[], int size)
{
for (int i = 0; i < size; i++)
to[i] = from[i];
}
template <class T>
void setArray(T to[], T from[], int size1, int size2)
{
int size = size1;
if (size2 < size1) size = size2;
setArray(to, from, size);
}
主
const int NUM = 5;
int originalArray[NUM] = { 4, 2, 5, 3, 1 };
int newArray[NUM];
cout << "Original:\n";
printArray(originalArray, NUM); //prints an array with formatting
// Merge Sort
setArray(newArray, originalArray, NUM); //set's newArray to the same values of originalArray
mergeSort(newArray, 0, NUM - 1);
cout << "Merge Sort:\n";
printArray(newArray, NUM);
pause();
运行main时的输出是:
原件: (4,2,5,3,1)
合并排序: (0,0,0,-33686019,1)
合并:
template <class T>
void merge(T L[], int lowerBound, int mid, int upperBound)
{
// Get size for new arrays
int size1 = mid - lowerBound;
int size2 = upperBound - mid;
// Create Temporary Arrays
T * tmp1 = new T[size1 + 1]();
T * tmp2 = new T[size2 + 1]();
// Populate both arrays from original
for (int i = 0; i < size1; i++)
tmp1[i] = L[lowerBound + i];
for (int j = 0; j < size2; j++)
tmp2[j] = L[mid + j];
tmp1[size1] = numeric_limits<T>::max();
tmp2[size2] = numeric_limits<T>::max();
int i = 0;
int j = i;
for (int k = lowerBound; k < upperBound; k++)
{
if (tmp1[i] <= tmp2[j])
{
L[k] = tmp1[i];
i++;
}
else
{
L[k] = tmp2[j];
j++;
}
}
delete[] tmp1;
delete[] tmp2;
}
归并:
template<class T>
void mergeSort(T L[], int lowerBound, int upperBound)
{
if (lowerBound < upperBound)
{
int mid = (lowerBound + upperBound) / 2;
mergeSort(L, lowerBound, mid);
mergeSort(L, mid + 1, upperBound);
merge(L, lowerBound, mid, upperBound);
}
}
那么......我做错了什么?正确方向的碰撞将非常受欢迎。
答案 0 :(得分:3)
这是一个简单的错误。
T * tmp1 = new T[size1 + 1]();
...
tmp1[size1 + 1] = numeric_limits<T>::max();
^^^
数组索引从0
转到n-1
,而不是n
。
答案 1 :(得分:2)
// tmp1[size1 + 1] = (infinity?)
// tmp2[size2 + 1] = (infinity?)
这是破坏你的合并的代码的一部分,想想如果你有两个列表,然后他们应该有两个列表会发生什么,请参阅:
// Create Temporary Arrays
T * tmp1 = new T[size1 + 1]();
T * tmp2 = new T[size2 + 1]();
这意味着他们可能看起来像这样的2个值
foo = [1,2,?]
bar = [3,4,?]
问号将是一些数字,但你无法知道什么,如果你然后在循环内运行几次比较你会得到让我们说 i = 2,j == 0 为简单起见,现在您尝试进行比较:
if (foo[2] <= bar[0])
和
相同if (? <= 3)
意味着你有一个未定义的行为,更糟糕的是你可能会去 i = 3 并开始查看随机内存。 总而言之,(无穷大?)以某种聪明的方式。
答案 2 :(得分:1)
在C ++合并函数中,L []的右半部分以mid + 1开头,因此第二个填充循环应为:
for (int j = 0; j < size2; j++)
tmp2[j] = L[mid + j + 1];
在提供的算法中,索引从1到n,因此第一个填充循环是TMP1 [i]←L [lowerBound + i - 1]。使用C ++,索引从0到n-1,因此C ++首先填充循环:tmp1 [i] = L [lowerBound + i];是正确的,但第二个循环需要改为tmp2 [j] = L [mid + j + 1];
答案 3 :(得分:1)
很抱歉忘记回复近两周:/
这是一个错误,但我跟踪它们并使其正常工作。 感谢所有帮助过的人。
更改
int size1 = mid - lowerBound;
int size2 = upperBound - mid;
到
int size1 = mid - lowerBound + 1;
int size2 = upperBound - mid;
更改
for (int j = 0; j < size2; j++)
tmp2[j] = L[mid + j];
到
for (int j = 0; j < size2; j++)
tmp2[j] = L[mid + j + 1];
更改
for (int k = lowerBound; k < upperBound; k++)
{
if (tmp1[i] <= tmp2[j])
{
L[k] = tmp1[i];
i++;
}
else
{
L[k] = tmp2[j];
j++;
}
}
到
for (int k = lowerBound; k <= upperBound; k++)
{
if (tmp1[i] <= tmp2[j])
{
L[k] = tmp1[i];
i++;
}
else
{
L[k] = tmp2[j];
j++;
}
}
答案 4 :(得分:0)
infinity
是其中一个问题。
// tmp1[size1] = (infinity?)
// tmp2[size2] = (infinity?)
它被用作哨兵,所以当你到达tmp1
(或tmp2
)的最后一个位置时,它会确保你复制另一个数组中的所有其他元素,{{ 1}}(或tmp2
)。您可以使用tmp1
在此处代表inf
。
@Petter很好地描述了这个问题发生的原因。
在合并数组之前,您的其他问题似乎是在初始化中:
std::numeric_limits<T>::max()
伪代码是从int i = 1;
int j = i;
建立索引,而它应该从1
开始。
正如@MarkRansom所指出的,索引范围应该从0
到0
,而不是size1
。
size1 + 1