在合并排序 C++ 中使用合并时的随机值
Random values when using merge in merge sort C++
对于一个小作业,我应该编写一个简单的合并函数,其原型如下所示:
void merge(int a[], int left_low, int left_high, int right_low, int right_high)
说明中说,为了简单起见,我们只接受一个数组,a[]
和 right_low = left_high + 1
。我们还将最终值存储在传入的原始数组 a[]
中。本质上,对于值为 a[] = {1,3,10,4,7,8}
的数组,它看起来像这样:
a = {1, 3, 10 , 4, 7, 8}
^ ^ ^ ^
left_low left_high right_low right_high
对于这项作业,我们必须通过一些测试。第一个是两个数组之间的简单合并。第二个是teachers own merge_sort函数,他在一些随机排序的数组上调用。这是我对 merge()
:
的实现
void merge(int a[], int left_low, int left_high,
int right_low, int right_high) {
int temp[right_high + 1]; // temporary array to store the result
int left_i = left_low, right_i = right_low, temp_i = 0;
// while the temporary array is not filled
while(temp_i != right_high + 1)
{
if(left_i == left_high + 1)
temp[temp_i++] = a[right_i++];
else if(right_i == right_high + 1)
temp[temp_i++] = a[left_i++];
else if(a[left_i] < a[right_i])
temp[temp_i++] = a[left_i++];
else
temp[temp_i++] = a[right_i++];
} // end while
for(int i = 0; i < temp_i; ++i)
a[i] = temp[i];
}
当他调用第一个测试时,他只是检查两个数组的合并,我的函数起作用了,现在对单个数组进行了排序。然而,当他调用他的 merge_sort 函数时,我最终得到了垃圾值。以下是他的测试函数:
template<class T>
void print (std::string label, T a[], int length, bool report_sorted) {
bool sorted = true;
std::cout << label;
for (int i=0; i<length; ++i) {
std::cout << a[i];
if (i == length-1)
std::cout << std::endl;
else {
std::cout << ", ";
if (a[i] > a[i+1])
sorted = false;
}
}
if (report_sorted)
std::cout << (sorted ? " Sorted" : " Not Sorted") << std::endl;
}
void shuffle(int values[], int length) {
std::vector<int> v_values;
for (int i=0; i<length; ++i)
v_values.push_back(values[i]);
std::random_shuffle(v_values.begin(),v_values.end());
for (int i=0; i<length; ++i)
values[i] = v_values[i];
}
//Recursive Merge Sort
template<class T>
void merge_sort(T a[], int low, int high) {
if (high - low < 1) //Base case: 0 or 1 value to sort -> sorted
return;
else {
int mid = (low + high)/2; //Split in 1/2
merge_sort(a, low, mid); //Recursively sort low to mid
merge_sort(a, mid+1, high); //Recursively sort mid+1 to high
merge(a, low,mid, mid+1,high); //Merge sorted parts of array
}
}
//Standard Merge Sort (calls a generalized one, with more parameters)
template<class T>
void merge_sort(T a[], int length) {
merge_sort(a, 0, length-1);
}
std::cout << "\n\nTesting merge in merge sort" << std::endl;
int test_merge_sort[10] = {1,2,3,4,5,6,7,8,9,10};
for (int i=0; i<5; i++) {
shuffle(test_merge_sort, 10);
print("\n Array before sort: ", test_merge_sort, 10, false);
merge_sort(test_merge_sort, 10);
print(" Array after sort: ", test_merge_sort, 10, true);
}
出于某种原因,我的输出最终看起来像这样:
Array before sort: 3, 9, 2, 5, 8, 4, 6, 10, 1, 7
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: 1995111146, 1975317641, 4, 0, -944749486, 5443192, 5443196, 5439488, 4, -944749486
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: -944749486, -944749486, 5443196, 4, 5439488, 1995111146, 5443192, 1975317641, 0, 4
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: 1975317641, -944749486, 4, 4, 5439488, 5443192, 5443196, -944749486, 0, 1995111146
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: -944749486, 5443192, 5443196, 1975317641, 4, 0, -944749486, 5439488, 1995111146, 4
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
我的合并代码出了什么问题可能会导致这种情况?
问题是您错误地计算了 temp
中的条目数:您的代码认为它是 right_high + 1
,但正确的公式是 right_high - left_low + 1
.
例如,当调用为您提供索引 10、15、16、26 时,您的代码尝试合并 27 个值,而它应该只合并 17 个(即索引 10 到 26,包括在内)。
当 left_low
为零时,这没有区别,因此您的测试用例运行良好。但是一旦 left_low
变为非零,例如当对数组的右半部分进行排序时,您的代码 "overshoots" 两个数组,将垃圾值放入 tmp
并覆盖数组 a
中的值。
最后一个 for
循环中的赋值也需要偏移 left_low
:
for(int i = 0; i < temp_i; ++i)
a[i+left_low] = temp[i];
对于一个小作业,我应该编写一个简单的合并函数,其原型如下所示:
void merge(int a[], int left_low, int left_high, int right_low, int right_high)
说明中说,为了简单起见,我们只接受一个数组,a[]
和 right_low = left_high + 1
。我们还将最终值存储在传入的原始数组 a[]
中。本质上,对于值为 a[] = {1,3,10,4,7,8}
的数组,它看起来像这样:
a = {1, 3, 10 , 4, 7, 8}
^ ^ ^ ^
left_low left_high right_low right_high
对于这项作业,我们必须通过一些测试。第一个是两个数组之间的简单合并。第二个是teachers own merge_sort函数,他在一些随机排序的数组上调用。这是我对 merge()
:
void merge(int a[], int left_low, int left_high,
int right_low, int right_high) {
int temp[right_high + 1]; // temporary array to store the result
int left_i = left_low, right_i = right_low, temp_i = 0;
// while the temporary array is not filled
while(temp_i != right_high + 1)
{
if(left_i == left_high + 1)
temp[temp_i++] = a[right_i++];
else if(right_i == right_high + 1)
temp[temp_i++] = a[left_i++];
else if(a[left_i] < a[right_i])
temp[temp_i++] = a[left_i++];
else
temp[temp_i++] = a[right_i++];
} // end while
for(int i = 0; i < temp_i; ++i)
a[i] = temp[i];
}
当他调用第一个测试时,他只是检查两个数组的合并,我的函数起作用了,现在对单个数组进行了排序。然而,当他调用他的 merge_sort 函数时,我最终得到了垃圾值。以下是他的测试函数:
template<class T>
void print (std::string label, T a[], int length, bool report_sorted) {
bool sorted = true;
std::cout << label;
for (int i=0; i<length; ++i) {
std::cout << a[i];
if (i == length-1)
std::cout << std::endl;
else {
std::cout << ", ";
if (a[i] > a[i+1])
sorted = false;
}
}
if (report_sorted)
std::cout << (sorted ? " Sorted" : " Not Sorted") << std::endl;
}
void shuffle(int values[], int length) {
std::vector<int> v_values;
for (int i=0; i<length; ++i)
v_values.push_back(values[i]);
std::random_shuffle(v_values.begin(),v_values.end());
for (int i=0; i<length; ++i)
values[i] = v_values[i];
}
//Recursive Merge Sort
template<class T>
void merge_sort(T a[], int low, int high) {
if (high - low < 1) //Base case: 0 or 1 value to sort -> sorted
return;
else {
int mid = (low + high)/2; //Split in 1/2
merge_sort(a, low, mid); //Recursively sort low to mid
merge_sort(a, mid+1, high); //Recursively sort mid+1 to high
merge(a, low,mid, mid+1,high); //Merge sorted parts of array
}
}
//Standard Merge Sort (calls a generalized one, with more parameters)
template<class T>
void merge_sort(T a[], int length) {
merge_sort(a, 0, length-1);
}
std::cout << "\n\nTesting merge in merge sort" << std::endl;
int test_merge_sort[10] = {1,2,3,4,5,6,7,8,9,10};
for (int i=0; i<5; i++) {
shuffle(test_merge_sort, 10);
print("\n Array before sort: ", test_merge_sort, 10, false);
merge_sort(test_merge_sort, 10);
print(" Array after sort: ", test_merge_sort, 10, true);
}
出于某种原因,我的输出最终看起来像这样:
Array before sort: 3, 9, 2, 5, 8, 4, 6, 10, 1, 7
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: 1995111146, 1975317641, 4, 0, -944749486, 5443192, 5443196, 5439488, 4, -944749486
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: -944749486, -944749486, 5443196, 4, 5439488, 1995111146, 5443192, 1975317641, 0, 4
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: 1975317641, -944749486, 4, 4, 5439488, 5443192, 5443196, -944749486, 0, 1995111146
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
Array before sort: -944749486, 5443192, 5443196, 1975317641, 4, 0, -944749486, 5439488, 1995111146, 4
Array after sort: -944749486, 4, 5439488, 0, 5443192, 5443196, 1975317641, -944749486, 4, 1995111146
Not Sorted
我的合并代码出了什么问题可能会导致这种情况?
问题是您错误地计算了 temp
中的条目数:您的代码认为它是 right_high + 1
,但正确的公式是 right_high - left_low + 1
.
例如,当调用为您提供索引 10、15、16、26 时,您的代码尝试合并 27 个值,而它应该只合并 17 个(即索引 10 到 26,包括在内)。
当 left_low
为零时,这没有区别,因此您的测试用例运行良好。但是一旦 left_low
变为非零,例如当对数组的右半部分进行排序时,您的代码 "overshoots" 两个数组,将垃圾值放入 tmp
并覆盖数组 a
中的值。
最后一个 for
循环中的赋值也需要偏移 left_low
:
for(int i = 0; i < temp_i; ++i)
a[i+left_low] = temp[i];