【问题标题】:Segmentation fault:11 MergeSort分段错误:11 MergeSort
【发布时间】:2017-01-19 15:54:44
【问题描述】:

我尝试实现归并排序算法,但出现分段错误。为什么?错误似乎在 MergeSort 函数中。合并排序函数(在第 2 次调用时)应仅检查 4 个数字的数组(长度应为 4)显示长度 = 27。为什么? (在一个有 8 个元素的数组上测试)

#include<iostream>
using namespace std;

int n, A[1000];

void citire(int lungime) {
    for (int i = 0; i < lungime; i++) cin >> A[i];
}

void afisare(int lungime) {
    for (int i = 0; i < lungime; i++)
        cout << A[i] << " ";
    cout << '\n';
}

int lungime(int A[]) {
    int i = 0;
    while (A[i]) i++;
    return i;
}

void Merge(int L[], int R[], int A[]) {
    int nL = lungime(L);
    int nR = lungime(R);
    int i = 0, j = 0, k = 0;

    while (i < nL && j < nR) {
        if (L[i] <= R[j]) {
            A[k] = L[i];
            i++;
        }
        else {
            A[k] = R[j];
            j++;
        }
        k++;
    }

    while (i < nL) {
        A[k] = L[i];
        i++;
        k++;
    }

    while (j < nR) {
        A[k] = R[j];
        j++;
        k++;
    }
}


void MergeSort(int A[]) {
    int n1 = lungime(A);
    if (n1 < 2) return;
    else
    {
        int mid = (int)n1 / 2;
        int L[mid];
        int R[n - mid];

        for (int i = 0; i < mid; i++)
            L[i] = A[i];
        for (int i = mid; i < n; i++)
            R[i - mid] = A[i];
        MergeSort(L);
        MergeSort(R);
        Merge(L, R, A);
    }
}


int main() {
    cin >> n;
    citire(n);
    MergeSort(A);
    afisare(n);
    return 0;
}

【问题讨论】:

  • 听起来你可能需要学习如何使用调试器来单步调试你的代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。延伸阅读:How to debug small programs
  • 我知道,但我已更改为 OSx 开发环境,但我的调试器无法正常工作,我不知道为什么。我会设置它,但也许我会在我完成调试器设置之前在这里找到答案
  • “因为我是 OSx c++ 编译器的新手,无法调试代码”听起来像是学习的绝佳机会!
  • 好点在这里
  • while (A[i]) i++; 将溢出您的缓冲区 A 除非它以空值终止,但不能保证会这样。

标签: c++ algorithm segmentation-fault mergesort


【解决方案1】:

本示例中所做的更改。 A[]、L[]、R[] 使用 new 分配。 A[] 作为参数传递。 L[] 和 R[] 在 Merge() 中分配。大小和/或索引作为参数传递,而lunime() 不再用于获取大小。 cmets 中记录的其他更改。

#include<iostream>
using namespace std;

void citire(int A[], int lungime) {     // A is parameter
    for (int i = 0; i < lungime; i++) cin >> A[i];
}

void afisare(int A[], int lungime) {    // A is parameter
    for (int i = 0; i < lungime; i++)
        cout << A[i] << " ";
    cout << '\n';
}

// A, low, mid, end are parameters
// L and R allocated here
void Merge(int A[], int low, int mid, int end) {
    int sizeL = mid-low;
    int sizeR = end-mid;
    int *L = new int[sizeL];
    int *R = new int[sizeR];

    for(int i = 0; i < sizeL; i++)
        L[i] = A[low+i];                // A[low+i]
    for(int i = 0; i < sizeR; i++)
        R[i] = A[mid+i];                // A[mid+i]

    int i = 0, j = 0, k = low;          // k = low
    while (i < sizeL && j < sizeR) {
        if (L[i] <= R[j]) {
            A[k] = L[i];
            i++;
        }
        else {
            A[k] = R[j];
            j++;
        }
        k++;
    }

    while (i < sizeL) {
        A[k] = L[i];
        i++;
        k++;
    }

    while (j < sizeR) {
        A[k] = R[j];
        j++;
        k++;
    }
    delete[] R;
    delete[] L;
}

// A, low, end are parameters
void MergeSort(int A[], int low, int end) {
    int sizeA = end - low;
    if(sizeA < 2)
        return;
    int mid = low + (sizeA / 2);        // mid = low + ...
    MergeSort(A, low, mid);
    MergeSort(A, mid, end);
    Merge(A, low, mid, end);
}

int main() {
    int n;
    cin >> n;
    int *A = new int[n];                // A is allocated
    citire(A, n);                       // A, n are parameters
    MergeSort(A, 0, n);                 // A, 0, n are parameters
    afisare(A, n);                      // A, n are parameters
    delete[] A;
    return 0;
}

【讨论】:

    【解决方案2】:

    “lungime 函数是字符串的长度,这个函数效果很好。我已经在不同的数组上测试过了”。 好吧,这纯粹是偶然的;未初始化的内存可以包含零,并意外提供数组终止符。 如果您想保留当前的设计,您应该:

    • 将 A 初始化为零
    • 确保输入流中的元素不超过 999 个,
    • 没有元素的值为零,因为零是保留的,用作终止符,并且
    • 将 L 和 R(在 MergeSort 中)定义长一个元素,并将最后一个元素初始化为零。

    除非有压倒性的理由需要“自己动手”排序解决方案,否则您可以看看预制排序支持。 C++ 中的向量类正好提供了这一点。

    【讨论】:

    • 我知道 C++ 中的向量类提供了它,但我正在学习算法,我正在尝试自己实现它
    • 这是 ryo 的完美理由。在此设置中,您可能会尝试弄清楚递归 MergeSort 例程消耗了多少堆栈空间,以及这如何限制要排序的数组的大小。
    猜你喜欢
    • 2017-05-17
    • 1970-01-01
    • 2012-09-27
    • 1970-01-01
    • 1970-01-01
    • 2017-06-25
    • 2017-01-07
    相关资源
    最近更新 更多