Итак, я пытаюсь создать алгоритм сортировки слиянием, но по некоторым причинам результат неверен. Я пробовал печатать высокие, низкие и средние значения, а также значения массива при каждом изменении, и я заметил, что количество некоторых значений не было даже правильным. Так, например, если я набрал 3, конечный результат будет состоять из нескольких 3-х. Но меня действительно смущает то, что этого не происходит, когда я вводил 4 значения или меньше, я заметил это только в пяти или более высоких входных значениях. Я не знаю, изменил ли это компьютер или компилятор некоторые из этих значений, или если это мой код, который является проблемой.
Вот мой код:
#include <iostream>
#include <array>
int num;
int * array = new int [num];
int * sub = new int [num];
void sort (int low, int mid, int high) {
std::cout << "Low, mid, high: " << low << ", " << mid << ", " << high << ".\n";
int a,b,c,d;
a = low;
b = low;
c = mid;
while ((a < mid) && (c < high)) {
if (array[a] < array[c]) {
sub[b] = array[a];
a++;
} else {
sub[b] = array[c];
c++;
}
b++;
}
while (a == mid && c < high) {
sub[b] = array[c];
c++;
b++;
}
while (c == high && a < mid) {
sub[b] = array[a];
a++;
b++;
}
for (d = low; d < high; d++) {
array[d] = sub[d];
for (int i = 0; i < num; i++) {
std::cout << array[i];
if (i != num - 1) {
std::cout << ", ";
} else {
std::cout << ".\n";
}
}
}
std::cout << "Done!\n";
}
void split (int low, int high) {
if (low < high - 1) {
int mid = (low + high) / 2;
split(low, mid);
split(mid, high);
sort(low, mid, high);
}
}
int main()
{
std::cout << "This is a program that sorts integers.\n";
std::cout << "How many numbers would you like to sort?\n";
std::cin >> num;
std::cout << "Please type in the numbers.\n";
for (int i = 0; i < num; i++) {
std::cin >> array[i];
}
split(0, num);
std::cout << "Your sorted numbers are: ";
for (int i = 0; i < num; i++) {
std::cout << array[i];
if (i != num - 1) {
std::cout << ", ";
} else {
std::cout << ".\n";
}
}
delete[] array;
delete[] sub;
return 0;
}
Я также попробовал свой код на своем исходном компиляторе и онлайн-оболочке, и казалось, что они дали два разных результата для одного и того же теста:
Оригинальный компилятор:
This is a program that sorts integers.
How many numbers would you like to sort?
9
Please type in the numbers.
5
9
2
0
6
4
3
1
8
Low, mid, high: 0, 1, 2.
5, 9, 2, 0, 5, 9, 3, 1, 8.
5, 9, 2, 0, 5, 9, 3, 1, 8.
Done!
Low, mid, high: 2, 3, 4.
5, 9, 0, 0, 5, 9, 0, 2, 8.
5, 9, 0, 2, 5, 9, 0, 2, 8.
Done!
Low, mid, high: 0, 2, 4.
0, 9, 0, 2, 0, 2, 5, 9, 8.
0, 2, 0, 2, 0, 2, 5, 9, 8.
0, 2, 5, 2, 0, 2, 5, 9, 8.
0, 2, 5, 9, 0, 2, 5, 9, 8.
Done!
Low, mid, high: 4, 5, 6.
0, 2, 5, 9, 0, 2, 5, 9, 0.
0, 2, 5, 9, 0, 2, 5, 9, 0.
Done!
Low, mid, high: 7, 8, 9.
0, 2, 5, 9, 0, 2, 5, 0, 0.
0, 2, 5, 9, 0, 2, 5, 0, 9.
Done!
Low, mid, high: 6, 7, 9.
0, 2, 5, 9, 0, 2, 0, 0, 9.
0, 2, 5, 9, 0, 2, 0, 5, 9.
0, 2, 5, 9, 0, 2, 0, 5, 9.
Done!
Low, mid, high: 4, 6, 9.
0, 2, 5, 9, 0, 2, 0, 5, 0.
0, 2, 5, 9, 0, 0, 0, 5, 0.
0, 2, 5, 9, 0, 0, 2, 5, 0.
0, 2, 5, 9, 0, 0, 2, 5, 0.
0, 2, 5, 9, 0, 0, 2, 5, 0.
Done!
Low, mid, high: 0, 4, 9.
0, 2, 5, 9, 0, 0, 0, 0, 0.
0, 0, 5, 9, 0, 0, 0, 0, 0.
0, 0, 0, 9, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 2, 0, 0.
0, 0, 0, 0, 0, 0, 2, 5, 0.
0, 0, 0, 0, 0, 0, 2, 5, 9.
Done!
Your sorted numbers are: 0, 0, 0, 0, 0, 0, 2, 5, 9.
Program ended with exit code: 0
Онлайн-оболочка:
This is a program that sorts integers.
How many numbers would you like to sort?
9
Please type in the numbers.
5
9
2
0
6
4
3
1
8
Low, mid, high: 0, 1, 2.
5, 9, 2, 0, 6, 4, 3, 1, 5.
5, 9, 2, 0, 6, 4, 3, 1, 5.
Done!
Low, mid, high: 2, 3, 4.
5, 9, 0, 0, 6, 4, 3, 1, 5.
5, 9, 0, 2, 6, 4, 3, 1, 5.
Done!
Low, mid, high: 0, 2, 4.
0, 9, 0, 2, 6, 4, 3, 1, 0.
0, 2, 0, 2, 6, 4, 3, 1, 0.
0, 2, 5, 2, 6, 4, 3, 1, 0.
0, 2, 5, 9, 6, 4, 3, 1, 0.
Done!
Low, mid, high: 4, 5, 6.
0, 2, 5, 9, 4, 4, 3, 1, 0.
0, 2, 5, 9, 4, 6, 3, 1, 0.
Done!
Low, mid, high: 7, 8, 9.
0, 2, 5, 9, 4, 6, 3, 0, 0.
0, 2, 5, 9, 4, 6, 3, 0, 1.
Done!
Low, mid, high: 6, 7, 9.
0, 2, 5, 9, 4, 6, 0, 0, 1.
0, 2, 5, 9, 4, 6, 0, 1, 1.
0, 2, 5, 9, 4, 6, 0, 1, 3.
Done!
Low, mid, high: 4, 6, 9.
0, 2, 5, 9, 0, 6, 0, 1, 3.
0, 2, 5, 9, 0, 1, 0, 1, 3.
0, 2, 5, 9, 0, 1, 3, 1, 3.
0, 2, 5, 9, 0, 1, 3, 4, 3.
0, 2, 5, 9, 0, 1, 3, 4, 6.
Done!
Low, mid, high: 0, 4, 9.
0, 2, 5, 9, 0, 1, 3, 4, 0.
0, 0, 5, 9, 0, 1, 3, 4, 0.
0, 0, 1, 9, 0, 1, 3, 4, 0.
0, 0, 1, 2, 0, 1, 3, 4, 0.
0, 0, 1, 2, 3, 1, 3, 4, 0.
0, 0, 1, 2, 3, 4, 3, 4, 0.
0, 0, 1, 2, 3, 4, 0, 4, 0.
0, 0, 1, 2, 3, 4, 0, 5, 0.
0, 0, 1, 2, 3, 4, 0, 5, 9.
Done!
Your sorted numbers are: 0, 0, 1, 2, 3, 4, 0, 5, 9.
Как вы можете видеть, я использовал точные номера и код, но получил два совершенно разных результата, поэтому я не знаю, ошибочен ли мой код или что-то еще. Спасибо за любую помощь заранее.
Поскольку num
не был определен, когда он был объявлен в начале кода, поскольку это была глобальная переменная num
автоматически присваивалась 0
. Тогда int * array = new int [num];
и int * sub = new int [num];
были объявлены с num
еще не определенным пользователем, создав два массива с 0
элементами. Попытка изменить эти массивы привела к неопределенному поведению, которое включало ложное внесение определенных случаев, и в этом случае, используя условия don't-care, чтобы изменить список номеров, созданных пользователем.
Чтобы исправить эту проблему, int * array
и int * sub
должны быть определены только после того, как num
определен пользователем. Это также означает, что функции split
и sort
должны включать указатели на массивы в качестве параметров.
Вот как выглядит код:
#include <iostream>
#include <array>
void sort (int *array, int *sub, int low, int mid, int high) {
int a = low;
int b = low;
int c = mid;
while ((a < mid) && (c < high)) {
if (array[a] < array[c]) {
sub[b] = array[a];
a++;
} else {
sub[b] = array[c];
c++;
}
b++;
}
while (a == mid && c < high) {
sub[b] = array[c];
c++;
b++;
}
while (c == high && a < mid) {
sub[b] = array[a];
a++;
b++;
}
for (int d = low; d < high; d++) {
array[d] = sub[d];
}
}
void split (int *array, int *sub, int low, int high) {
if (low < high - 1) {
int mid = (low + high) / 2;
split(array, sub, low, mid);
split(array, sub, mid, high);
sort(array, sub, low, mid, high);
}
}
int main()
{
std::cout << "This is a program that sorts integers.\n";
std::cout << "How many numbers would you like to sort?\n";
int num;
std::cin >> num;
int * array = new int [num];
int * sub = new int [num];
std::cout << "Please type in the numbers.\n";
for (int i = 0; i < num; i++) {
std::cin >> array[i];
}
split(array, sub, 0, num);
std::cout << "Your sorted numbers are: ";
for (int i = 0; i < num; i++) {
std::cout << array[i];
if (i != num - 1) {
std::cout << ", ";
} else {
std::cout << ".\n";
}
}
delete[] array;
delete[] sub;
return 0;
}
Вы можете использовать сортировку слияния снизу вверх. Примеры обоих:
вверх дном:
template <typename T>
T * BottomUpMergeSort(T a[], T b[], size_t n)
{
for(size_t s = 1; s < n; s += 2) // swap in place for 1st pass
if(a[s] < a[s-1])
std::swap(a[s], a[s-1]);
for(size_t s = 2; s < n; s <<= 1){ // s = run size
size_t ee = 0; // init end index
while(ee < n){ // merge pairs of runs
size_t ll = ee; // ll = start of left run
size_t rr = ll+s; // rr = start of right run
if(rr >= n){ // if only left run
rr = n;
BottomUpCopy(a, b, ll, rr); // copy left run
break; // end of pass
}
ee = rr+s; // ee = end of right run
if(ee > n)
ee = n;
BottomUpMerge(a, b, ll, rr, ee);
}
std::swap(a, b); // swap a and b
}
return a; // return sorted array
}
template <typename T>
void BottomUpCopy(T a[], T b[], size_t ll, size_t rr)
{
while(ll < rr){ // copy left run
b[ll] = a[ll];
ll++;
}
}
template <typename T>
void BottomUpMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee){ // else copy rest of right run
b[o++] = a[r++];
}
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr){ // else copy rest of left run
b[o++] = a[l++];
}
break; // and return
}
}
}
сверху вниз, позволяет избежать копирования данных после слияния, чередуя две рекурсивные функции:
template <typename T>
T * TopDownMergeSort(T a[], T b[], size_t n)
{
TopDownMergeSortAtoA(a, b, 0, n);
return a;
}
template <typename T>
void TopDownMergeSortAtoA(T a[], T b[], size_t ll, size_t ee)
{
if (ee - ll > 1) {
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownMergeSortAtoB(a, b, ll, rr);
TopDownMergeSortAtoB(a, b, rr, ee);
TopDownMerge(b, a, ll, rr, ee); // merge b to a
}
}
template <typename T>
void TopDownMergeSortAtoB(T a[], T b[], size_t ll, size_t ee)
{
if (ee - ll > 1) {
size_t rr = (ll + ee)>>1; //midpoint, start of right half
TopDownMergeSortAtoA(a, b, ll, rr);
TopDownMergeSortAtoA(a, b, rr, ee);
TopDownMerge(a, b, ll, rr, ee); // merge a to b
} else if ((ee - ll) == 1) {
b[ll] = a[ll];
}
}
template <typename T>
void TopDownMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee){ // else copy rest of right run
b[o++] = a[r++];
}
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr){ // else copy rest of left run
b[o++] = a[l++];
}
break; // and return
}
}
}
int num; int * array = new int [num]; int * sub = new int [num];
... Я уверен, что выделение двух массивов по 0 элементов в каждом - это не то, что вы хотите сделать.