27. príklady


Posledná zmena: 19.2.2003

Banner Text spájané zoznamy I.

Spájané zoznamy

Máme zadefinované triedy pre prácu so spájaným zoznamom:

ich metódy môžeme využiť pri definovaní ďalších metód

 

 

 

 

 

 

 

 

 

postupne dodefinujte metódy:

type
  prvok = integer;
  TVrchol = class
    info:prvok;
    next:TVrchol;
    constructor Create(i:prvok; n:TVrchol);
    function vypis:string; virtual;
  end;

  TZoznam = class
  private
    z:TVrchol;    // začiatok zoznamu
    k:TVrchol;    // koniec zoznamu
  public
    constructor Create;
    destructor Destroy; override;
    function vypis:string;
    procedure pridajZ(i:prvok); overload;
    procedure pridajZ(p:TVrchol); overload;
    procedure pridajK(i:prvok); overload;
    procedure pridajK(i:TVrchol); overload;
    procedure vsun(pred:integer; i:prvok);

    property zaciatok:TVrchol read z;
    property koniec:TVrchol read k;
  end;

constructor Create(n:integer);

  • vytvorí n-prvkový celočíslený zoznam s číslami 1..n
constructor TZoznam.Create(n:integer);
begin
  z:=nil; k:=nil;          // alebo Create;
  while n>0 do begin
    z:=TVrchol.Create(n,z);
    if k=nil then k:=z;
    dec(n);
  end;
end;

alebo inak:

 

constructor TZoznam.Create(n:integer);
begin
  z:=nil; k:=nil;
  while n>0 do begin
    pridajZ(n);
    dec(n);
  end;
end;

constructor Create(p:array of prvok);

  • vytvorí zoznam podľa hodnôt v otvorenom poli
constructor TZoznam.Create(p:array of prvok);
var
  i:integer;
begin
  Create;
  for i:=high(p) downto 0 do
    pridajZ(p[i]);
end;

function pocet:integer;

  • vráti počet prvkov zoznamu
function TZoznam.pocet:integer;
var
  p:TVrchol;
begin
  Result:=0; p:=z;
  while p<>nil do begin
    inc(Result);
    p:=p.next;
  end;
end;

procedure zrusZ;

  • zruší prvý vrchol
procedure TZoznam.zrusZ;
var
  p:TVrchol;
begin
  if z<>nil then begin
    p:=z; z:=z.next; p.Free;
    if z=nil then k:=nil;
  end;
end;

procedure zrusK;

  • zruší posledný vrchol
procedure TZoznam.zrusK;
var
  p:TVrchol;
begin
  if z=nil then exit;
  if z=k then begin
    z.Free; z:=nil; k:=nil;
  end
  else begin
              // nájde predposledný
    p:=z; while p.next<>k do p:=p.next;
    k.Free; k:=p; k.next:=nil;
  end;
end;

procedure zrus(p:vrchol);

  • zruší vrchol p -
  • pozor, ak p v zozname neexistuje
procedure TZoznam.zrus(p:vrchol);
var
  q:TVrchol;
begin
  if z=nil then exit;
  if p=z then ZrusZ
  else begin
    q:=z; while (q<>nil) and (q.next<>p) do q:=q.next;
    if q<>nil then begin
      q.next:=p.next;
      if q.next=nil then k:=q;
      p.Free;
    end;
  end;
end;

procedure prevrat;

  • prevráti poradie vrcholov v zozname
procedure TZoznam.prevrat;
var
  p,q:TVrchol;
begin
    // zoznam je prázdny alebo jednoprvkový

  if z=k then exit;
  k:=z; p:=z;
  while p<>nil do begin
    q:=p.next;
    p.next:=z;
    z:=p;
    p:=q;
  end
  k.next:=nil;
end;

constructor kopia(p:TZoznam);

  • urobí postupne kópiu všetkých vrcholov
  • pozor na to, že pre p sú premenné z a k privátne (nevadí v metóde TZoznamu)
  • urobiť kopia aj ako obyčajnú metódu (najprv musí uvoľniť pôvodný obsah svojho zoznamu)
constructor TZoznam.kopia(p:TZoznam);
var
  q:TVrchol;
begin
  Create;    // z:=nil; k:=nil;

  q:=p.z;
  while q<>nil do begin
    pridajK(q.info);
    q:=q.next;
  end;
end;

procedure zarad(i:prvok);

  • predpokladáme, že zoznam je vzostupne utriedený podľa info
  • zaradí na správne miesto
procedure TZoznam.zarad(i:prvok);
var
  p:TVrchol;
begin
  if (z=nil) or (z.info>i) then PridajZ(i)
  else begin
    p:=z;
    while (p.next<>nil) and (p.next.info<i) do
      p:=p.next;
    if p.next=nil then PridajK(i)
    else p.next:=TVrchol.Create(i,p.next);
  end;
end;

procedure utried;

  • nájde minimum, dá ho na začiatok, znovu nájde minimum zo zvyšku, dá ho za minimum, atď.
procedure Tzoznam.utried;
var
  p,q,min:TVrchol;
  pom:prvok;
begin
  if z<>k then begin
    p:=z;
    while p.next<>nil do begin
      min:=p;
      q:=p.next;
      while q<>nil do begin
        if q.info<min.info then min:=q;
        q:=q.next;
      end;
      pom:=min.info; min.info:=p.info; p.info:=pom;
      p:=p.next;
    end;
  end;
end;

procedure vyhodDupl;

  • vyhodí všetky prvky s rovnakou hodnotou, nechá len jeden - prvý výskyt
procedure TZoznam.vyhodDupl;
var
  p,q,r:TVrchol;
begin
  p:=z;
  while p<>nil do begin
    q:=p;
    if q<>nil then
      while q.next<>nil do begin
        if p.info=q.next.info then begin
          r:=q.next.next; q.next.Free; q.next:=r;
          if r=nil then k:=q;
        end
        else
          q:=q.next;
      end;
    p:=p.next;
  end;
end;

function najdi(i:prvok):integer;

  • zistí index prvku i
function TZoznam.najdi(i:prvok):integer;
var
  p:TVrchol;
begin
  Result:=0;
  if z<>nil then begin
    p:=z;
    while (p<>nil)and(p.info<>i) do begin
      p:=p.next; inc(Result);
    end;
    if p<>nil then inc(Result)
    else Result:=0
  end;
end;

procedure vyhod(od,kolko:integer);

  • zo zoznamu vyhodí od od-teho prvku kolko prvkov
  • (podobne ako delete pre reťazce)
procedure TZoznam.vyhod(od,kolko:integer);
var
  p,q:TVrchol;
  i:integer;
begin
  if od<2 then
    while (z<>nil) and (kolko>0) do begin
      p:=z.next; z.Free; z:=p; dec(kolko);
      if z=nil then k:=nil;
    end
  else begin
    p:=z;         // hľadá predchodcu
    while (od>2) and (p<>nil) do begin
      p:=p.next; dec(od);
    end;
    if p<>nil then begin
      while (p.next<>nil) and (kolko>0) do begin
        q:=p.next; p.next:=q.next; q.Free; dec(kolko);
      end;
      if p.next=nil then k:=p;
    end;
  end;
end;

procedure vyhodK(kolko:integer);

  • zo zoznamu vyhodí kolko prvkov od konca zoznamu
  • spôsob: kolko-krát vyhodí posledný prvok zoznamu
procedure TZoznam.vyhodK(kolko:integer);
begin
  while (z<>nil) and (kolko>0) do begin
    zrusK;
    dec(kolko);
  end;
end;

procedure vyhodK inak;

  • zo zoznamu vyhodí kolko prvkov od konca zoznamu
  • použije metódu vyhod(od,kolko)
procedure TZoznam.vyhodK(kolko:integer);
begin
  vyhod(pocet-kolko+1,kolko);
end;

Ďalšie úlohy

  • Vytvorte najprv binárny súbor (TStream) slovengl.dat, v ktorom sú dvojice slov uložené takto: bajt (dĺžka 1. slova), za ním nasleduje slovo (príslušný počet bajtov), bajt (dĺžka 2. slova) a za ním druhé slovo - najprv slovenské slovo a za ním anglický ekvivalent.
  • Napíšte program, ktorý vytvorí nový binárny súbor englslov.dat, v ktorom budú dvojice slov lexikograficky usporiadané podľa druhého slova z dvojice. Použite spájaný zoznam, ktorý budete udržiavať utriedený. Každý vrchol zoznamu bude obsahovať dva stringy a smerník next. Do triedy slovnik (spájaný zoznam) dodefinujte metódy na načítanie zo streamu a tiež na zápis do streamu, napr. LoadFromStream, SaveToStream, slová do zoznamu pridávajte metódou zarad, ktorá zaradí dvojicu slov na správne miesto do slovníka, aby bol stále usporiadaný podľa anglického slova.


© 2003 AB, KVI
blaho@fmph.uniba.sk