我试图在C ++ 14中实现合并排序。我已经编写了完整的代码,并针对逻辑错误多次对其进行了校对,但找不到任何内容。但是代码输出的数组排序错误,有时甚至包含重复的元素和/或从来没有输入到数组中的元素。
这是我的代码:
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
using std::vector;
void merge_sort(vector<int>&, int, int);
void print_vector(vector<int>&);
void merge(vector<int>&, int, int, int);
int main() {
int arr_len = 0;
cout << "Enter the length of the array to be sorted: " << endl;
cin >> arr_len;
vector<int> arr(arr_len);
cout << "Enter the elements of the array: " << endl;
for (int i = 0; i < arr_len; i++) {
int buff;
cin >> buff;
arr[i] = buff;
}
cout << "The elements entered in the unsorted vector are: " << endl;
print_vector(arr);
merge_sort(arr, 0, arr_len - 1);
cout << "After Merge sorting, the elements in the vector are: " << endl;
print_vector(arr);
return 0;
}
void print_vector(vector<int>& arr) {
for (auto itr = arr.begin(); itr != arr.end(); ++itr) {
cout << *itr << " ";
}
cout << endl;
}
void merge_sort(vector<int>& arr, int low, int high) {
if (low < high) {
int mid = low + (high - low) / 2; // used this instead of (low + high) / 2 to avoid overflow problems
merge_sort(arr, low, mid); // recursive call to merge_sort with high = mid's updated value
merge_sort(arr, mid + 1, high);
merge(arr, low, mid, high); // call to merge to sort and merge the fragmented arrays.
}
}
void merge(vector<int>& arr, int low, int mid, int high) {
int l_arr_len = mid - low + 1;
int r_arr_len = high - mid;
vector<int> l_arr(l_arr_len);
vector<int> r_arr(r_arr_len);
for (int i = 0; i < l_arr_len; i++) { // initialise elements of temp_arr1 (l_arr) to 0.
l_arr[i] = 0;
}
for (int i = 0; i < r_arr_len; i++) { // initialise elements of temp_arr2 (r_arr) to 0.
r_arr[i] = 0;
}
for (int i = 0; i < l_arr_len; i++) { // transfer elements from arr to l_arr, upto length of the fragmented l_arr.
l_arr[i] = arr[low + i];
}
for (int i = 0; i < r_arr_len; i++) { // transfer remaining elements from arr to r_arr, upto length of the fragmented r_arr.
r_arr[i] = arr[mid + 1 + i];
}
int i = 0, j = 0, k = 0;
while (i < l_arr_len && j < r_arr_len) { // compare and replace elements in the mother array arr
if (l_arr[i] <= r_arr[j]) { // smallest element goes first
arr[k++] = l_arr[i++];
} else {
arr[k++] = r_arr[j++];
}
}
while (i < l_arr_len) { // write remaining elements in the left_arr fragment to mother array arr
arr[k++] = l_arr[i++];
}
while (j < r_arr_len) { // write remaining elements in the left_arr fragment to mother array arr
arr[k++] = r_arr[j++];
}
}
对于元素[2, 9, 4, 5, 7]
的输入数组,正确的排序结果应为:[2, 4, 5, 7, 9]
。
但是我的实现输出:[5, 5, 7, 7, 9]
。我不知道重复元素来自何处以及为什么它们替换了原始元素。为了尽量方便SO社区的访问,我尝试在几乎要添加的注释中添加注释,但是其中一些可能是多余的。
由于我不明智,请帮助我更正我的代码。您可以指出哪里出了问题,如果方便的话,在哪里。
提前谢谢! :)
答案 0 :(得分:1)
在合并功能中,将k初始化为低值,而不是零:
int i = 0, j = 0, k = low;
我刚刚注意到肯尼·奥斯特罗姆(Kenny Ostrom)的评论可能与进行此更改有关。
答案 1 :(得分:1)
其他人发现了主要问题,k
必须初始化为low
而不是0
。
还有更多问题您应该看看:
数组索引值和大小的正确类型是size_t
,而不是int
,它的范围可能小得多。
传递最后一个元素的索引而不是排除的上限会产生繁琐的代码,需要进行索引调整。
不需要初始化临时向量,您应该复制内容,或者更好地从数组切片构造它们。
print_vector
应该引用const
。
此处是修改版本:
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
using std::vector;
void merge_sort(vector<int>&, size_t, size_t);
void merge(vector<int>&, size_t, size_t, size_t);
void print_vector(const vector<int>&);
int main() {
size_t arr_len = 0;
cout << "Enter the length of the array to be sorted: " << endl;
cin >> arr_len;
vector<int> arr(arr_len);
cout << "Enter the elements of the array: " << endl;
for (size_t i = 0; i < arr_len; i++) {
cin >> arr[i];
}
cout << "The elements entered in the unsorted vector are: " << endl;
print_vector(arr);
merge_sort(arr, 0, arr_len);
cout << "After Merge sorting, the elements in the vector are: " << endl;
print_vector(arr);
return 0;
}
void print_vector(const vector<int>& arr) {
for (auto itr = arr.begin(); itr != arr.end(); ++itr) {
cout << *itr << " ";
}
cout << endl;
}
void merge_sort(vector<int>& arr, size_t low, size_t high) {
if (high - low > 1) {
size_t mid = low + (high - low) / 2; // used this instead of (low + high) / 2 to avoid overflow problems
merge_sort(arr, low, mid); // recursive call to merge_sort with high = mid's updated value
merge_sort(arr, mid, high);
merge(arr, low, mid, high); // call to merge to sort and merge the fragmented arrays.
}
}
void merge(vector<int>& arr, size_t low, size_t mid, size_t high) {
size_t l_arr_len = mid - low;
size_t r_arr_len = high - mid;
vector<int> l_arr(l_arr_len);
vector<int> r_arr(r_arr_len);
for (size_t i = 0; i < l_arr_len; i++) { // transfer elements from arr to l_arr, upto length of the fragmented l_arr.
l_arr[i] = arr[low + i];
}
for (size_t i = 0; i < r_arr_len; i++) { // transfer remaining elements from arr to r_arr, upto length of the fragmented r_arr.
r_arr[i] = arr[mid + i];
}
size_t i = 0, j = 0, k = low;
while (i < l_arr_len && j < r_arr_len) { // compare and replace elements in the mother array arr
if (l_arr[i] <= r_arr[j]) { // smallest element goes first
arr[k++] = l_arr[i++];
} else {
arr[k++] = r_arr[j++];
}
}
while (i < l_arr_len) { // write remaining elements in the left_arr fragment to mother array arr
arr[k++] = l_arr[i++];
}
while (j < r_arr_len) { // write remaining elements in the left_arr fragment to mother array arr
arr[k++] = r_arr[j++];
}
}
答案 2 :(得分:0)
在我的代码中,特别是在void merge(...)
函数中,我将变量k
初始化为0
。该变量k
应该根据其值来跟踪已排序元素在母数组arr
中的放置位置。
导致的结果是,无论是母数组arr
的哪个片段,当将不同数组片段中的元素排序和合并在一起时,k
都被硬编码为{{1 }},0
的第一个(已排序)元素被满足条件的任何数组片段中的下一个元素替换。因此,数组最终将被填满,程序将正确退出,但是在将部分排序的数组中注入重复项之前不会退出,这些重复项来自arr
元素被以下两个数组片段之一替换:{{ 1}}或arr[k++]
。当然,根据合并排序的原理,这是错误的,因为要保持阵列元素的合并模式。可能很难将其形象化,因此这是“合并排序”的表示形式,以供参考:
因此,这里是解决方法:l_arr
应该初始化为r_arr
,而不是 k
。这样,就可以保持合并排序的模式,将适当片段中的适当元素递归组合在一起,以形成排序后的数组。
Kenny Ostrom和rcgldr建议使用此修复程序。非常感谢他们俩!