Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Frage zu Pointern auf Array in einer Function.


Jerk - Mi 22.10.08 17:14
Titel: Frage zu Pointern auf Array in einer Function.
Hallo allerseits, ich habe mir gedacht das ich aus spaß mal den Quicksort Algoprythmus optimiere, da ja die Standard Version mit while arbeitet und ich gehört hab das Rekursion schneller ist.

Also der Standard Quicksort:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
// Quelle http://www.stefan-baur.de/cs.algo.quicksort.html
procedure QuickSort(var A: array of Integer);

  procedure QSort(LoIndex, HiIndex: Integer);
  var
    Lo, Hi: Integer;
    Pivot: Integer;
    Swap: Integer;
  begin
    // Wähle stets das mittlere Element als Pivotelement.
    Pivot := A[(LoIndex + HiIndex) div 2];

    // Stelle die Ordnung bzgl. des Pivotelements her.
    Lo := LoIndex;
    Hi := HiIndex;
    repeat
      while A[Lo] < Pivot do Inc(Lo);
      while A[Hi] > Pivot do Dec(Hi)
;
      if Lo <= Hi then
      begin
        Swap := A[Lo];
        A[Lo] := A[Hi];
        A[Hi] := Swap;
        Inc(Lo);
        Dec(Hi);
      end;
    until Lo > Hi;

    // Gegebenenfalls linke Teilliste sortieren.
    if LoIndex < Hi then QSort(LoIndex, Hi);

    // Gegebenenfalls rechte Teilliste sortieren.
    if Lo < HiIndex then QSort(Lo, HiIndex);
  end;


Den Markierten Teil wollte ich wiegesagt durch Funktionen ersetzen die Rekursiv das gleiche machen.
Da dazu allerdings das Array übergeben werden muss, dachte ich löse ich das ganze mit Pointern.
Nur leider funktioniert das nicht:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
type
  TNums = Array[0..1000] of Integer;
  pArray = ^TNums;
  pPivot = ^Integer;

...

procedure TForm1.QuickSort(A: array of Integer; iLo, iHi: Integer) ;
var
  Lo, Hi, Pivot, T: Integer;
begin
  Lo := iLo;
  Hi := iHi;
  Pivot := A[(Lo + Hi) div 2];
  repeat
    Lo := SortLeft(@A,@Pivot,iLo);
    Hi := SortLeft(@A,@Pivot,iHi);

    if Lo <= Hi then
    begin
      T := A[Lo];
      A[Lo] := A[Hi];   
      A[Hi] := T;
      Inc(Lo) ;
      Dec(Hi) ;
    end;
  until Lo > Hi;
  if Hi > iLo then QuickSort(A, iLo, Hi) ;
  if Lo < iHi then QuickSort(A, Lo, iHi) ;
end;

Function TForm1.SortLeft(  ar : pArray;  Pivot :pPivot; Pos : Integer) : Integer;
var va,vb : Integer;
begin
  va := ar[Pos];
  vb := Pivot^;
 if va < vb then SortLeft(ar,Pivot,Pos+1)
 else
  Result:= Pos;
end;

Function TForm1.SortRight(ar : pArray; Pivot :pPivot; Pos : Integer) : Integer;
var va,vb : Integer;
begin
  va := ar[Pos];
  vb := Pivot^;
 if va > vb then SortLeft(ar,Pivot,Pos-1)
 else
  Result:= Pos;
end;


Ich bekomme leider immer nen Stack Overflow, nur wieso?


jaenicke - Mi 22.10.08 20:38

Ein Stackoverflow bedeutet meistens, dass irgendein rekursiver Aufruf nicht abgebrochen wird. (Oder etwas anderes den Stack gefüllt hat, aber Rekursionen sind meistens die Ursache.)

Ohne es mir jetzt ganz genau angeschaut zu haben würde ich beim Überfliegen sagen, dass er von SortLeft nach SortRight immer hin- und herspringt ohne abzubrechen oder ähnliches.

Debug das doch einfach und schau was passiert. Haltepunkt setzen und mit F7 bzw. F8 schrittweise durch gehen und die Werte deiner Variablen beobachten (ggf. mit markieren und Strg + F7 auswerten).


Jerk - Mi 22.10.08 20:58

:autsch: Da hab ich mich so auf die Pointer fixiert und nen Simplen fehler übersehen, das der Funktionswert unbestimmt sein kann :oops:

Danke für die Hilfe.


Logikmensch - Do 23.10.08 09:48

Ich hab auch gerade gesehen, dass der Funktionswert bei SortLeft nicht gesetzt wird.

Darüberhinaus frage ich mich, wozu die zusätzliche Rekursion? Die Lo-/Hi-Eingrenzung des zu sortierenden Bereiches gehört doch nur zum Verkleinern desselben. Die Routine arbeitet doch bereits rekursiv... Das SortLeft belastet m.E. nach nur den Stack, sonst nix.