Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - dynamische Listenelemente löschen


Bestzeller - Mi 08.04.09 14:04
Titel: dynamische Listenelemente löschen
Hi,
Ich hab eine Liste mit den Prozeduren Keller und Schlange erstellt und möchte nun ein beliebiges Listenelement löschen. Der Record enthält nur eine Integerzahl und die Prozedure dazu ist auch schon fast fertig. Jetzt muss ich nur noch bestimmte Fälle ausschließen, daher die Frage : Wie prüfe ich ob die gesuchte Zahl im ersten Listenelement ist?
Muss ich jetzt in der Suche einen Counter mitlaufen lassen oder geht es auch anders?


Logikmensch - Do 09.04.09 12:35

Für eine exakte Antwort ist die Frage zu ungenau. Was für ein Typ Liste ist es denn? Ein TList-Abkömmling, eine TStringList, oder ein dynamisches Array?


pigfacejoe - Do 09.04.09 13:02

Deine Liste sollte eine Zeigervariable pfirst oder pErstes (p für Pointer)besitzen. Mit dieser Zeigervariable prüfst du einfach, ob diese deinen Suchstring enthält.
Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function Tliste.loesche(x:string):boolean;
var erg:boolean;
begin
erg:=false;
if pfirst^.data=x then 
begin
if pfirst^.pnext<>nil then
begin
pfirst^.pnext^.pprev:=nil//Wenn du eine doppelt verkettete Liste hast
pfirst:=pfirst^.pnext;
end ;
dispose(pfirst);
erg:=true;
end
else 
....
end;


Ich weiß zwar nicht, ob ich dein Problem richtig gedeutet hab, aber ich hoffe das hilft dir. Falls nicht, zeig doch mal die Deklaration deiner Liste und beschreib mal genauer, was tun willst.
Gruß
Max
Gruß
Max


Bestzeller - Do 09.04.09 17:28

Das Objekt ist wie folgt deklariert:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
type

  Zeiger=^element;
  element=record
    z:integer;
    next:zeiger;
  end;

  Tliste=class(Tobject)
    Head,Tail,Fund,tmp:zeiger;
    check:boolean;
    suchzahl,anzahl:integer;
    Constructor init;
    procedure Keller(zahl:integer);
    procedure Schlange(zahl:integer);
    procedure Pop(var zahl:integer);
    procedure anzeigen(lb:tlistbox);
    procedure suchen(k:zeiger);
    procedure loeschen;
   end;


Und so sieht die Prozedur löschen bei mir aus:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure tliste.loeschen;

begin

 tmp:=Head ;

 suchen(Head);

// <If anzahl = 1 then pop>
// <IF Fund  = 1. Zahl then pop>
// <If Fund.next = nil then dispose Fund und tail eine höher setzen>
 While tmp^.next <> Fund do tmp:=tmp^.next;

 tmp^.next:=Fund^.next;

 dispose(Fund);

end;


Funktioniert im Moment nur bei einer Liste die mehr als 2 Elemente hat und wenn die Suchzahl sich im mittleren Teil befindet. Wenn jetzt aber die Suchzahl im ersten Element ist , muss ich den Kopf (Zeiger) eine heruntersetzen , aber wie überprüf ich den überhaupt ob es das erste Element ist? wenn es das letzte Element wär könnte man ja einfach mit if
abfragen, weil der Nächste auf Nil zeigt.


Mr_Emre_D - Fr 10.04.09 13:48

Warum verwendest du keine Doppelt-Verkettung?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
PElement = ^TElement;
TElement = record
  DataBlub: String;
  Previous, Next: PElement;
end;

//in der Klasse
  Liste, tmp: PElement;  // der erste Listeneintrag hat als Previous = NIL und der Letzte als Next = NIL

// Bsp: Deine Liste zeigt heirhin
//             |
// Element - Element - Element - Element - Element
// Wenn du es löschen willst musst du zuerst dem vorigen sagen, dass sein Nächster der Nächste vom aktuellen Datensatz ist und dem Nächsten(vom akutellen Datensatz) sagen, dass sein Voriger der Vorige vom akt. D. ist ...

Liste^.Previous^.Next := Liste^.Next;
Liste^.Next^.Previous := Liste^.Previous;

// Somit hättest du die Pointer verbogen
// Nun kannst du den Datensatz, den du mit New angelegt hast, Disposen:
tmp := Liste;
Liste := Liste^.Next // je nach dem (next, prev)...
Dispose( tmp );


MfG


Bestzeller - Fr 10.04.09 15:49

user profile iconMr_Emre_D hat folgendes geschrieben Zum zitierten Posting springen:
Warum verwendest du keine Doppelt-Verkettung?


Haben wir im Unterricht noch nicht gehabt. Aber Danke jetzt weiß ich eben mehr. :)

Ps: Frohe Ostern!^^


Flamefire - Fr 10.04.09 16:21

warum so umständlich?
machs rekursiv

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure tliste.loeschen(var list:zeiger);
var tmp:zeiger;
begin

if(list<>nilthen begin
  if(list^.z=suchzahl) then begin
  tmp:=list;
  list:=list^.next;
  dispose(tmp);
  end else loeschen(list^.next);
end;

end;


bei listen geht das bearbeiten rekursiv immer besser, weil eine liste rekursiv definiert ist.
ansonsten doppelt verkettete liste nehmen oder viel aufwand mit temporären variablem machen.

BTW:
du solltest deine typ-namen besser wählen:

Delphi-Quelltext
1:
2:
3:
4:
5:
  pZeiger=^Telement;
  Telement=record
    z:integer;
    next:pZeiger;
  end

alle typen mit großem T vorne versehen und pointer mit kleinem p vorne (nur ein auszug aus der namensgebung)
sonst passiert es schnell, dass du eine variable "element" nennst...


Mr_Emre_D - Fr 10.04.09 16:56

user profile iconFlamefire hat folgendes geschrieben Zum zitierten Posting springen:
warum so umständlich?
machs rekursiv

Warum den Stack auslasten wenn man ihn schonen kann? :P


Flamefire - Fr 10.04.09 17:04

sagen wir so: es ist für die schule wenn ich das richtig verstanden habe,
und da ist es sehr wahrscheinlich, dass es bonuspunkte für die rekursive variante gibt.
selbst an der uni wird (erstmal) die rekursive version gelehrt. also warum nicht benutzen?