C ++ - 合并排序 - 无法识别出错了什么

时间:2014-09-09 03:28:10

标签: c++ mergesort

所以,我一直在尝试创建合并排序算法,但由于某些原因,结果不正确。我已经尝试打印高,低和中值,以及每次更改时的数组值,我注意到某些值的数量甚至都不正确。因此,例如,如果我输入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;
}

我还在原始编译器和在线shell上尝试了我的代码,似乎他们为同一个测试产生了两个不同的结果:

原始编译器:

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

在线shell:

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.

正如您所看到的,我使用了完全相同的数字和代码,但得到了两个完全不同的结果,因此我不知道我的代码是错误还是其他内容。感谢您提前提供任何帮助。

2 个答案:

答案 0 :(得分:0)

由于num在代码开头声明时未定义,因为它是全局变量num自动分配给0。然后int * array = new int [num];int * sub = new int [num];声明了num尚未由用户定义,创建了两个带有0元素的数组。尝试更改这些数组会导致未定义的行为,其中包括错误地使某些案例看起来是正确的,并且在这种情况下,使用无关紧要的术语来更改用户创建的数字列表。

要解决此问题,只能在用户定义int * array后定义int * subnum。这也意味着函数splitsort必须包含指向数组的指针作为参数。

以下是代码的样子:

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

答案 1 :(得分: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
        }
    }
}