Newsgroup: it.comp.lang.delphi
Titolo: Liste e Puntatori

Qualcuno ha un esempio per capire l'uso delle liste puntate di questo
tipo:
  TRDatiRec = record
    Data  : arr;
    Len   : integer;
    next  : pointer;
  end;
  TDatiRec = ^TRDatiRec;
  XRec     : TDatiRec;
Dopo l'allocazione NEW(XRec) scrivo i dati e va bene, ma come faccio a
posizionarmi sull'ennesimo nodo, leggerlo e cancellarlo?
Grazie 1000 a chi mi aiuterą



Prima di tutto inizia a fare questa modifica;
 PDatiRec = ^TRDatiRec;
 TRDatiRec = record
    Data  : arr;
    Len   : integer;
    next  : PDatiRec
  end;
  XRec     : PDatiRec;
prendiamo ora una situazione banale (e mal scritta):
var
  Root: PDatiRec; //per poter sempre risalire al primo elemento
  P1, P2: PDatiRec;
New(P1);
Root := P1;
with P1^ do
begin
  Data := ....
  Len := x;
  Next := nil; // č l'ultimo elemento e non punta a nulla
end;
New(P2);
with P2^ do
begin
  Data := ....
  Len := x;
  Next := nil; // č l'ultimo elemento e non punta a nulla
end;
P1.Next := P2; //il primo elemento ora punta al secondo.
Ora per iterare sulla lista č facile
P1 := Root;
while P1.Next <> nil 
  P1 := P1.Next;
Cancellarlo diventa leggermente piů complesso in quanto devi cambiare
il puntatore ^next del record precedente e il tuo record punta solo al
successivo (*), mentre se avessi una struttura del tipo
TRDatiRec = record
    Data  : arr;
    Len   : integer;
    next, prev  : PDatiRec
  end;
sarebbe piu facile:
P1.Prev.Next := P1.Next;
P1.Next.Prev := P1.Prev;
Dispose(P1);
(*)
Devi salvare l'ultimo puntatore all'incirca cosi'
P1 := root;
P2 := nil;
while P1.Next <> nil do begin //o fino a quando soddisfi la tua
ricerca
  P2 := P1;
  P1 := P1.Next;
  if č il mio puntatore then
  begin
      P2.Next := P1.Next;
      Dispose(P1);
  end;
end;
Spero di non aver scritto troppe cavolate, ho resumato ricordi di 15
anni fa e ho riletto di fretta  ;-)
Ciao.
-- 
Ore 18.30: premo invio.

Sono veramente in difficoltà, ho provato e riprovato, riesco a leggere
e scrivere ma non a cancellare quello che voglio, non è che potresti
darmi un esempio più reale anche modificato in modo da poter navigare
la lista?
Gianluca



Queste sono le basi, sicuramente il codice si può migliorare visto che
l'ho buttato giù di getto, ma è già qualcosa ;-)
Come giò dicevo, usare una lista con 2 puntatori o un albero sarebbe
meglio, questa comunque è una lista monodirezionale, il che significa
che per cercare l'ennesimo item devi sempre partire dal primo.
type
  PUser = ^TUser;
  TUser = record
    Nome: string;
    Anno: Integer;
    NextPtr: PUser;
  end;
var
  Root: PUser; //globale o comunque con uno scope sufficiente
procedure Generica;
var
  I: Integer;
begin
  Root := nil;
  AddUser('Paolo', 23); //aggiunge un utente
  AddUser('Marco', 44);
  AddUser('Mario', 33);
  AddUser('Genoveffa', 28);
  AddUser('Teresa', 33);
  I := GetUserAge('Genoveffa'); //torna l'eta dell'utente
  MessageDlg(InttoStr(I), mtInformation, [mbOk], 0);
  DeleteUser('Mario'); //cancella l'utente
  ClearList;  //cancella tutta la lista
end;
//e le procedure particolari sono queste, buon divertimento :-)
//non le commento, se hai dei dubbi chiedi pure
procedure AddUser(User: string; Year: Integer);
var
  P1, P2: PUser;
begin
  P1 := New(PUser);
  with P1^ do
  begin
    Nome := user;
    Anno := Year;
  end;
  P1.NextPtr := nil;
  if Root = nil then
    Root := P1
  else begin
    P2 := Root;
    while P2.NextPtr <> nil do
      P2 := P2.NextPtr;
    P2.NextPtr := P1;
  end;
end;
function GetUserAge(User: string): Integer;
var
  P1: PUser;
begin
  Result := 0;
  P1 := Root;
  while P1 <> nil do
  begin
    if P1.Nome = user then
    begin
      Result := P1.Anno;
      Break;
    end;
    P1 := P1.NextPtr;
  end;
end;
function DeleteUser(User: string): Boolean;
var
  P1, PrevPtr: PUser;
begin
  Result := False;
  P1 := Root;
  PrevPtr := nil;
  repeat
    if P1.Nome = User then
    begin
      if P1 = Root then
        Root := P1.NextPtr
      else if PrevPtr <> nil then
        PrevPtr.NextPtr := P1.NextPtr;
      Dispose(P1);
      Result := True;
      Break;
    end else
    begin
      PrevPtr := P1;
      P1 := P1.NextPtr;
    end;
  until P1 = nil;
end;
procedure ClearList;
var
  P1, P2: PUser;
begin
  P1 := Root;
  while P1 <> nil do
  begin
    P2 := P1.NextPtr;
    Dispose(P1);
    P1 := P2;
  end;
end;
ciao.
