【问题标题】:SIGSEV in custom QuickSort implementation自定义 QuickSort 实现中的 SIGSEGV
【发布时间】:2014-06-21 10:05:59
【问题描述】:

我对问题 Quicksort drama 的答案睡了一觉,想从头开始重新编码,用引用调用 var 实现您的提示。再说一遍:我再也找不到任何失败了。我将代码与您的程序一一比较,但找不到问题。以下代码在编译/运行期间产生异常(External:SIGSEV at address 11602)

program quicksort;

var
  iArray : array[0..8] of integer;

procedure fillArray(var iArray : array of integer);
begin;
  iArray[0] := 3;
  iArray[1] := 1;
  iArray[2] := 8;
  iArray[3] := 4;
  iArray[4] := 9;
  iArray[5] := 0;
  iArray[6] := 8;
  iArray[7] := 2;
  iArray[8] := 5;
end;

procedure writeArray(iArray : array of integer);
var i:integer;
begin
  for i:=low(iArray) to high(iArray) do begin
    write(iArray[i]);
  end;
  writeln('');
end;

procedure quickSort(var iArray : array of integer; links : integer; rechts:integer);
var
  l,r,pivot, temp: integer;
begin
  if (rechts > links) then begin
    l := links;
    r := rechts;
    pivot := iArray[(rechts+links) div 2];

    while (l<r) do begin
      while (iArray[l] < pivot) do l:=l+1;
      while (iArray[r] > pivot) do r:=r-1;
      if (l<=r) then begin
       temp := iArray[l];
       iArray[l] := iArray[r];
       iArray[r] := temp;
      end;
    end;
    if (links < r) then quickSort(iArray, links, r);
    if (l < rechts) then quickSort(iArray, l, rechts);
  end;
end;

begin
  fillArray(iArray);
  quickSort(iArray,low(iArray),high(iArray));
  writeArray(iArray);
end.

【问题讨论】:

  • 这是 Stack Overflow 的边界题外话,它不是调试代码会话的站点(一旦有一个“过于本地化”的密切原因,这将是恰当的)。为了增加它对站点的未来访问者有用的机会,您应该编辑它以具有有意义的标题(遇到相同问题的人可以搜索的东西),格式正确的代码并且没有德语参数名称。
  • 能否请您开始养成正确缩进的习惯?

标签: delphi pascal quicksort


【解决方案1】:

交换完成的代码块也需要增加l并减少r

if (l <= r) then
begin
  temp := iArray[l];
  iArray[l] := iArray[r];
  iArray[r] := temp;
  inc(l); // <-- this was missing
  dec(r); // <-- as was this
end;

完整的程序,还有一些其他的小整理:

program quicksort24340509;

var
  iArray: array [0 .. 8] of integer;

Procedure fillArray(var iArray: array of integer);
begin;

  iArray[0] := 3;
  iArray[1] := 1;
  iArray[2] := 8;
  iArray[3] := 4;
  iArray[4] := 9;
  iArray[5] := 0;
  iArray[6] := 8;
  iArray[7] := 2;
  iArray[8] := 5;
end;

Procedure writeArray(const iArray: array of integer);
var
  i: integer;
begin
  for i := low(iArray) to high(iArray) do
  begin
    write(iArray[i], ' ');
  end;
  writeln;
end;

Procedure quickSort(var iArray: array of integer; links, rechts: integer);
var
  l, r, pivot, temp: integer;
begin
  if (rechts > links) then
  begin
    l := links;
    r := rechts;
    pivot := iArray[(rechts + links) div 2];

    while l < r do
    begin
      while iArray[l] < pivot do inc(l);
      while iArray[r] > pivot do dec(r);
      if l <= r then
      begin
        temp := iArray[l];
        iArray[l] := iArray[r];
        iArray[r] := temp;
        inc(l);
        dec(r);
      end;
    end;
    if links < r then
      quickSort(iArray, links, r);
    if l < rechts then
      quickSort(iArray, l, rechts);
  end;
end;

begin
  fillArray(iArray);
  quickSort(iArray, low(iArray), high(iArray));
  writeArray(iArray);
  readln;
end.

输出

0 1 2 3 4 5 8 8 9

您的版本失败的原因是对quickSort 的递归调用在错误的范围内运行。

例如,鉴于您的输入

3 1 8 4 9 0 8 2 5

分区步骤以9 为中心并导致

3 1 8 4 5 0 8 2 9

现在,递归步骤应该是对枢轴左侧的所有值和右侧的所有值进行排序。我们不考虑枢轴,因为分区确保它处于最终位置。

轴的右侧没有值,因此我们应该对范围 0 到 7 进行递归调用。但是,如果您检查代码发生了什么,您会发现它没有。相反,它对范围 0 到 8 进行递归调用。这本身有点良性,但是一旦范围变小,在停止条件下,情况就不同了。尝试让您的程序对这些值进行排序:

1 2

代码以1 为中心。在分区结束时,我们有:

links = 0
rechts = 1
l = 0
r = 0

所以我们递归调用quickSort 传递lrechts 作为范围。但这与我们最初的调用完全相同。因此会导致堆栈溢出。

所以关键是我们必须确保当我们在一个主元上进行分区时,我们将该主元从所有未来对quickSort 的递归调用中排除。如果我们不这样做,我们就不会细分问题,并且递归不会终止。

【讨论】:

  • 谢谢。不递增/递减有什么问题?交换了值,并且 l 仍然小于 r,while 循环应该继续进行。
  • 嗯,这是一种不同的算法。一种根本不起作用。您会注意到您的原始版本有所不同。
  • 是的,但为什么不起作用?我的示例输入 3 1 8 4 9 0 8 2 5 Pivot: 9 在第一轮之后,l 将是 4(9) 并且 r 是 8(5):它们被交换。所以数组是: 3 1 8 4 5 0 8 2 9 为什么我必须加/减?如果我不这样做,下一轮 l 将由两个内部 while 循环增加而 r 将被 dec 反正
  • 您使用什么作为源文本?有无数种不同的方式来实现分区。很容易看出您的代码无法分区。为什么您将代码从以前的有效版本更改为无效的版本?您的源文本是否告诉您这样做?
  • 我添加了一些分析来说明为什么会出现堆栈溢出
猜你喜欢
  • 1970-01-01
  • 2020-04-12
  • 2013-03-16
  • 2011-06-15
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多