自定义QuickSort实现中的SIGSEGV

时间:2014-06-21 10:05:59

标签: delphi pascal quicksort

我睡过了问题Quicksort drama的答案,并希望从头开始重新编码,使用call-by-reference var实现你的提示。再说一遍:我再也找不到任何失败。我将代码逐一与您的程序进行比较,但我找不到问题。以下代码在编译/运行期间生成异常(外部:地址为11602的SIGSEV)

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.

1 个答案:

答案 0 :(得分:4)

交换的代码块,交换完成后也需要递增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中排除。如果我们不这样做,我们不会细分问题,并且递归不会终止。