【问题标题】:Heapsort program does not return the result堆排序程序不返回结果
【发布时间】:2020-02-12 03:59:13
【问题描述】:

我正在用 C 语言实现 Heapsort 程序,它使用二叉树进行排序。当我运行这个程序时,直到它遇到程序中的heapsort函数是可以的。我也尝试对此进行调试,但在遇到heapsort 函数时仍然出错。

参考网上的一些算法,发现和我的源代码很像,但运行正常,所以我很难找出源代码中的错误

#include <stdio.h>
#define MAX 2100
void downheap(int a[], int n, int k)
{
    int i=0;
    int temp = a[0];
    while (k <= n/2)
    {
        i = k + k;
        if(i<n && a[i] <= a[i+1]) i++;
        if(temp < a[i]) break;
        a[k] = a[i]; k = i;
    }
    a[k] = temp;
}
void heapsort(int a[], int n)
{
    int i, j;
    for(i=0; i<=n; i++) downheap(a, n, i);
    while(n>=0)
    {
        j = a[0]; a[0] = a[n]; a[n] = j;
        downheap(a, --n, 0);
    }
}

int main()
{
    int n, a[MAX], i;
    printf("Enter your number of elements: ");
    scanf("%d", &n);
    for(i=0; i<n; i++) printf("%d: ", i), scanf("%d", &a[i]);
    heapsort(a, n-1);
    for(i=0; i<n; i++) printf("%d ", a[i]);
    return 0;
}

【问题讨论】:

    标签: c algorithm sorting segmentation-fault


    【解决方案1】:

    我在下面列出的代码中存在多个问题:

    您应该坚持 n 是元素数的通用约定。在您的代码中,元素的数量减去 1 是不方便的。在这种情况下,您可以致电 heapsort(a, n)

    heapsort 函数中,for(i=0; i&lt;=n; i++) downheap(a, n, i) 应该是for(i=n/2-1; i&gt;=0; i--) downheap(a, n, i)

    接下来,由于 n 是 a 中元素的数量,循环应该是while(--n &gt; 0)。 n=0 的迭代是没有意义的,因为它会将 a[0] 与 a[0] 交换。最后你打电话给downheap(a, n, 0)

    函数downheap 是您遇到最大问题的地方。该函数应将索引 i 处的元素与其两个子元素进行比较,并将树的最大值存储在索引 i 处。如果发生与孩子的交换,请与该孩子一起恢复 donwheap。你的功能是完全错误的。这是一个正确的实现。

    void downheap(int *a, int n, int k){
        int l = 2*k+1, r = 2*k+2, max = k;
        if (l < n && a[l] > a[max])
            max = l;
        if (r < n &d a[r] > a[max])
            max = r;
        if (max != k) {
            int j = a[k]; a[k] = a[max]; a[max] = j;
            downheap(a, n, max);
        }
    }
    

    如您所见,此代码与您的代码完全不同,这是完全错误的。

    为方便起见,这里是heapsort 函数的代码。该代码没有那么糟糕,但仍然不正确。

    void heapsort(int *a, int n){
        int i, j;
        for(i=n/2-1; i>=0; i--)
            downheap(a, n, i);
        while(--n > 0){
            j = a[0]; a[0] = a[n]; a[n] = j;
            downheap(a, n, 0);
        }
    }
    

    编辑

    downheap 的非递归实现:

    void downheap(int *a, int n, int k){
        while (1) {
            int l = 2*k+1, r = 2*k+2, max = k;
            if (l < n && a[l] > a[max])
                max = l;
            if (r < n &d a[r] > a[max])
                max = r;
            if (max == k)
                break;
            int j = a[k]; a[k] = a[max]; a[max] = j;
            k = max;
        }
    }
    

    【讨论】:

    • 我不同意您的 downheap 功能,原因有两个。首先,二叉树表明第 k 个节点有第 (2k) 个和第 (2k+1) 个节点是完全错误的。在您的程序中,它显示它具有 (2k+1) 和 (2k+2) 个节点。其次,你的源代码没有像我的那样优化,因为我使用的变量更少,我仍然得到相同的结果(你可以调试这个函数来看看)
    • @HoangNam 很抱歉,您对索引有误。该数组的索引为 0,1,2,3,4,5,6。 3 是 1 的左孩子,4 是 1 的右孩子。3 = 2*1+1, 4 = 2*1+2。 5 是 2 的左孩子,6 是 2 的右孩子。5=2*2+1 和 6 = 2*2+2。您的 downheap 不会交换任何值,也不会将 downheap 调用传播给已交换的子节点。您的 downheap 函数没有像通常调用的那样正确实现 heapify 函数。您不应该依赖调试来验证代码的正确性,因为调试通常是在一个特定的用例上执行的。
    • 好吧,对不起,因为我只知道索引从 1 到 N,而不是从 0。
    • @HoangNam 在 C 数组中的索引从 0 开始。填充数组时,将其从 0 填充到 n-1。
    • 我知道,但是,对于 Heapsort,我读的书说我们应该从 1 填充到 N-1,因为有时,我们需要 a[0] 来存储甚至高于a[1] 在某些方面对 Heapsort 的 insert 功能很有帮助
    猜你喜欢
    • 2019-10-05
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 2020-04-22
    • 1970-01-01
    相关资源
    最近更新 更多