在堆中搜索元素后删除元素时出现分段错误

时间:2019-01-10 14:17:36

标签: c data-structures segmentation-fault

以下代码在堆中线性搜索元素x后,将其从堆中删除

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MaxSize 100001

struct minheap {
    long int a[MaxSize];
    int end;
};

void minHeapify(struct minheap *h, int i) {
    int largest;
    long int temp;
    int l=2*i+1;
    int r=2*i+2;
    largest=i;
    if(l<=(h->end) && (h->a[l])<(h->a[i]))
       largest=l;
    if(r<=(h->end) && (h->a[r])<(h->a[largest]))
       largest=r;
    if(largest!=i) {
       temp=h->a[i];
       h->a[i]=h->a[largest];
       h->a[largest]=temp;
       minHeapify(h,largest);
    }
}


int main() {
    long int x,i=0,temp=0;
    int N;
    int type;
    scanf("%d",&N);
    struct minheap h;
    h.end=-1;

    while(N--) {
        scanf("%d",&type);
        if(type==1) {
              scanf("%ld",&x);
              h.end=h.end+1;
              h.a[h.end]=x;
              i=h.end;
              while(i>0 && h.a[(i-1)/2]>h.a[i]) { //fix minheap on insertion
                  temp = h.a[(i-1)/2];
                  h.a[(i-1)/2]=h.a[i];
                  h.a[i]=temp;
                  i=(i-1)/2;
              }
        }
        else if(type==2) {
              scanf("%ld",&x);

              for(i=0;i<=h.end;i++) {
                  if(x == h.a[i])
                    break;
              }
              h.a[i]=h.a[h.end];
              h.end=h.end-1;
              if(i!=(h.end+1))
              minHeapify(&h,i);
        }

        else if(type==3) {
        printf("%ld\n",h.a[0]);
        }
    }
 return 0;
}

但是以下测试用例却给出了分段错误:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  main () at solution.c:59
59                    if(x == h.a[i])
#0  main () at solution.c:59

可以在此链接上找到整个测试用例:

https://hr-testcases-us-east-1.s3.amazonaws.com/15379/input04.txt?AWSAccessKeyId=AKIAJ4WZFDFQTZRGO3QA&Expires=1547134261&Signature=D%2B39%2BHr%2F4lRFV%2BetxFwnGWm1iac%3D&response-content-type=text%2Fplain

为什么会发生分段错误?

2 个答案:

答案 0 :(得分:0)

给出错误消息,

Option Explicit

Sub SetDateTime()
  Dim lngRow As Long
  For lngRow = 1 To 10
    Cells(lngRow, 20).Value = Now
  Next lngRow
End Sub

Sub ReformatDate()
  Dim lngRow As Long
  Dim datX As Date
  Dim strX As String

  For lngRow = 1 To 10
    strX = Cells(lngRow, 20).Value
    If IsDate(strX) Then
      datX = CDate(strX)
      Cells(lngRow, 20).NumberFormat = "@"
      Cells(lngRow, 20).Value = Format(datX, "mm/dd/yy")
    End If
  Next lngRow
End Sub

...表达式> Program terminated with signal SIGSEGV, Segmentation fault. > #0 main () at solution.c:59 59 if(x == h.a[i]) > #0 main () at solution.c:59 中的值i可能超出范围。这会导致 undefined behavior ,在某些情况下似乎可行,而其他情况可能会导致分段错误

查看此行可能的解决方案:

if(x == h.a[i])

调用该表达式时for(i=0;i<=h.a[h.end];i++) 的值是什么?

这里也存在潜在的问题:

a.end

表达式:while(i>0 && h.a[(i-1)/2]>h.a[i]) 是整数除法,将跳过值。

答案 1 :(得分:0)

我在您的代码中看到一些删除项目的问题:

          for(i=0;i<=h.end;i++) {
              if(x == h.a[i])
                break;
          }
          h.a[i]=h.a[h.end];
          h.end=h.end-1;
          if(i!=(h.end+1))
          minHeapify(&h,i);

首先,如果找不到具有您输入的值的项目,则将因为i > h.end而遇到麻烦。您最终要么从数组末尾索引,要么删除最后一项。

更重要的是,您不会处理替换项小于父项的情况。例如,考虑以下堆:

        1
    6       2
  7   8   3

如果您删除具有值7的节点,则值3将替换它:

        1
    6       2
  3   8

那不是有效的堆。您必须将3在堆中向上移动才能创建:

        1
    3       2
  6   8

这里的关键是,如果要替换的项目与堆中的最后一个项目不在同一子树中,则替换节点的大小可能小于替换节点的父节点。

因此您的代码必须这样做:

h.a[i] = h.a[h.end];
h.end = h.end-1;
// here you have to:
// if (h.a[i] < parentOf(h.a[i]))
//    move it up the heap
// else
//    minHeapify(&h, i);