繁体   English   中英

合并排序中的堆栈溢出

[英]Stack overflow in merge sort

我有家庭作业,通过递归在C ++中实现合并排序。 我不是很擅长递归,接下来是我实现的代码,但它给出了stackoverflow错误。 请告诉我我做错了什么。 编辑版

    #include<iostream>
using namespace std;
void divide(int A[], int n);
void sort();
int main(){
    int A[4]={2,3,0,5};
    divide(A, 4);
    for(int i =0 ;i<4;i++)
        cout<<A[i]<<endl;
    getchar();
}
void divide(int A[], int n){
    if(n<=2 && n>=1){
        for(int i=0; i<n; i++)
                if(A[i]>A[i+1]){

                int temp=A[i];
                A[i]= A[i+1];
                A[i+1]=temp;

                }
    }
    else{
    divide(A, n/2);
    divide(A,(n/2)+1 );
    }

}

在上面的代码中, n是要排序的元素的数量, A是我正在排序的数组。

用以下代码调用以下代码

divide(A, 1);

应该说明问题

void divide(int A[], int n){
    if(n==2){ // first time n==1 so no, further calls are n==0 so also no.
        for(int i=0; i<2; i++)
            if(A[i]>A[i+1]){
                int temp=A[i];
                A[i]= A[i+1];
            }
    } else{
        divide(A, n/2); // for both n==1 and n== 0 => n==0, calls divide(A, 0)
        divide(A,(n/2)+1 ); // calls divide(A, 1) always 
    }
}

所以程序将永远调用除(A,0),直到你的内存不足为止。

要停止这种永恒的递归,你需要一个正确的停止条件

if (n<=2) {
    // correct code for swapping 1 or 2 elements
}  else

您还可以检查n的错误值,即0,负数和大于A的长度。


假设你有A [] = {1,2,3},所以你打电话

divide(A, 3);

现在在程序的else部分,你需要将A分成部分,N / 2个元素和其余部分。

divide(A, n/2);

在我们的例子中,这给出了n / 2 = 3/2 = 1

除(A,1);

并在第n / 2个元素之后的元素中开始

divide(A+(n/2), n-(n/2));

第一个元素是A [0],所以剩余的开始于A [1]并且包含n-(n / 2)= 3-(3/2)= 3-1 = 2个元素。

现在第一个if ,它看起来像一个冒泡排序,但失败了,因为它解决了超出数组末尾的元素。

if(n<=2 && n>=1){
    for(int i=0; i<n; i++)
        if(A[i]>A[i+1]) { 

对于i = 1且n = 2,a [i + 1]超出数组的末尾,地址A [0]和A [1]的n = 2 => 2个元素,因此A [i + 1] = A [ 2]不是长度为2的阵列A的一部分。

    for(int i=0; i<n-1; i++)

解决了这个问题并且还处理了n = 1的情况,这意味着该数组只包含一个元素,根据定义,该元素已经被排序。

现在,如果算法被称为divide-sort,那么你将完成,但你仍然缺少合并部分。

你还在错过合并。 合并将需要第二个临时数组,我将其称为T并假设它从main传递:

void divide(int A[], int T[], int n){
    if(n < 2)
        return;
    if(n==2){
        // ... swap A[0], A[1] if needed (the existing code is ok)
        return;
    }
    divide(A, T, n/2);                   // recursively divide "left" half
    divide(A+(n/2), T+(n/2), n-(n/2));   // recursively divide "right" half
    merge(A, T, n/2, n)                  // merge the two halves
}

假设分区0或1元素已经排序可能更简单。 因此,足以作为停止条件

if (n < 2)
  return;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM