Wykład 7 - Dynamiczne struktury danych -nieuporządkowane(część I) 1. Pojęcie rekurencyjnych typów danych
2. Klasyfikacja struktur danych
3. Podstawowe nieuporządkowane rodzaje dynamicznych struktur danych 4. Stos
5. Kolejka
6. Lista jednokierunkowa 7. Lista dwukierunkowa
1. Pojęcie rekurencyjnych typów danych
Przykład (Wirth N. “Algorytmy + Struktury Danych = Programy”, WNT 1989) a) deklaracja modelu drzewa dziedziczenia:
type osoba = record
if znany then (imię : alfa;
ojciec, matka: osoba)
b) opis reprezentacji zmiennej rodowód typu osoba: end;
jeśli znany = False, to istnieje tylko pole znacznikowe znany równe False (F) jeśli znany = True, to istnieją jeszcze trzy pola (imię, ojciec, matka)
c) przypadek danych: rodowód = (T, Jan, (T, Marek, (T, Adam, (F), (F)), (F)), (T, Maria, (F), (T, Ewa, (F), (F))))
T
Maria
T Ewa T
Marek
T
Adam T
Jan
F F F
F F F
F
wartość False (F) pola znacznikowego określa
skończoność struktury danych, co wynika z braku informacji na pewnym poziomie drzewa genealogicznego
2. Klasyfikacja struktur danych Struktury danych można podzielić na:
1) typy o stałych rozmiarach - realizowane jako tablice lub rekordy z bezpośrednim dostępem do każdego elementu tych struktur za pomocą operatorów indeksowania “[ ]” lub wyboru: “^.” oraz “.”
2) typy z możliwością zmiany rozmiarów, - rekurencyjne typy danych realizowane jako dynamiczne struktury danych z pośrednim dostępem do ich elementów, przez:
3) użycie rekordów,
4) użycie wskaźników do deklaracji składowych tych rekordów, 5) dynamiczny przydział pamięci dla tych składowych,
6) algorytm dostępu do poszczególnych elementów tego rekordu określa programista dzięki jawnemu użyciu wskaźników.
· Dynamiczne przydzielanie pamięci zmiennej p^.
P
P^
· Wskaźnikowy model rekurencyjnych typów danych:
Przykład Wskaźnikowy model rodowodu a) deklaracja typu
POsoba = ^Osoba;
Osoba = record
Imie : string[10];
Ojciec, Matka : POsoba;
end;
b) wskaźnikowa struktura rodowodu
Jan Marek
Adam Ewa
Maria
nil nil nil
nil
nil nil
Poczatek
3. Abstrakcyjne typy danych
3.1.Główne cechy typów danych stosowanych w programach:
3.1.1. muszą być dopasowane do rozwiązywanego problemu 3.1.2. muszą zawierać dwa rodzaje informacji:
· zbiór własności
· zbiór działań.
Np. typ integer
własności: reprezentuje liczby całkowite o wartościach od -32768 do +32767 zakodowanych w kodzie dwójkowym na dwóch bajtach
działania: zmiana znaku, dodawanie, mnożenie, dzielenie, modulo...
3.2. Trzy etapy procesu definiowania typów przez programistę [wg Stephen Prata - Szkoła programowania, Język C]:
1) Przygotowanie opisu ADT (abstrakcyjnego typu danych).
“Przygotowania abstrakcyjnego opisu własności typu i operacji, jakie można na nim wykonać. Opis ten nie powinien być związany z żadną konkretną implementacją i językiem programowania. Taka formalna charakterystyka nosi nazwę abstrakcyjnego typu danych ADT.
2) Opracowanie interfejsu programistycznego realizującego ADT -
wskazanie sposobu przechowywania danych i opisanie zbioru funkcji wykonujących potrzebne operacje. W języku C etap ten może polegać na utworzeniu definicji struktury i prototypów funkcji przetwarzających. Funkcje te pełnią dla nowego typu tę samą rolę, co operatory w przypadku podstawowych typów języka C. Utworzony w ten sposób interfejs będzie stosowany przez osoby, chcące skorzystać z nowego typu danych
3) Pisanie kodu implementującego interfejs
Ten krok jest kluczowy, ale należy zauważyć, że programista korzystający z interfejsu nie musi orientować się w szczegółach implementacji”
Wniosek: Utworzony typ danych, definiowany przez programistę stanowi pewien kompletny element języka, który może być używany wielokrotnie w programach. Jedyny właściwy sposób wykorzystania nowego typu odbywa się za pośrednictwem funkcji z interfejsu typu. Nie należy bezpośrednio odwoływać się do zmiennych reprezentujących daną zdefiniowanego typu.
4. Podstawowe nieuporządkowane dynamiczne struktury danych
Decyzja o zastosowaniu rekurencyjnych struktur danych jest podejmowana przy projektowaniu interfejsu nowego typu
Algorytm dostępu do poszczególnych elementów tej struktury określa programista dzięki jawnemu użyciu wskaźników.
Algorytm dostępu jest podstawą do klasyfikacji dynamicznych struktur danych.
4.1. Stos
Etap 1 - Opis ADT
Nazwa typu - Stos elementów
Własności typu: Potrafi przechować ciąg elementów Dostępne działania:
Inicjalizacja stosu
Określenie, czy stos jest pusty Dodanie elementu do stosu,
Wyszukanie elementu na szczycie stosu Usuwanie ze stosu,
Przejście przez stos i przetwarzanie każdego elementu
Wyszukanie elementu ze szczytu stosu i przetwarzanie tego elementu Usunięcie stosu
Etap 2 - Budowa interfejsu
procedure Inicjalizacja( var Poczatek :PElement);
{ działanie: inicjuje stos
warunki wstępne: Poczatek wskazuje na pierwszy element warunki końcowe: stos zostaje zainicjowany jako pusty}
function Pusty(Poczatek: PElement) : Boolean;
{ działanie: określa, czy stos jest pusty
warunki wstępne: Poczatek jest zainicjowanym stosem,
warunki końcowe: funkcja zwraca True, jeśli stos pusty, w przeciwnym przypadku False }
function Szukaj(Poczatek: PElement) : Boolean;
{ działanie: szuka elementu ze szczytu stosu
warunki początkowe: Poczatek wskazuje na zainicjowany stos,
warunki końcowe: funkcja zwraca True, gdy znaleziono element na szczycie stosu, natomiast zwraca False, jeśli stos jest pusty }
function Wstaw(var Poczatek: PElement; Pozycja: Osoba): Boolean;
{działanie: dodaje element na początek ciągu, zwany szczytem stosu
warunki początkowe: Pozycja jest daną do wstawienia na szczyt zainicjowanego stosu
warunki końcowe: jeśli to możliwe, funkcja dodaje daną Pozycja na szczyt stosu i zwraca wartosć True, w przeciwnym wypadku False }
function Usun(var Poczatek: PElement): Boolean;
{działanie: usuwa element na początku ciągu wstawionego do stosu warunki początkowe: Poczatek jest zainicjowanym stosem
warunki końcowe: jeśli jest to możliwe, funkcja usuwa element na szczycie stosu i zwraca True, w przeciwnym przypadku False }
procedure Usun_pamiec(var Poczatek: PElement);
{ działanie: usuwa elementy ze stosu i inicjuje stos jako pusty warunki początkowe: Poczatek jest zainicjowanym stosem warunki końcowe: liczba elementów na stosie jest równa 0*/
function Dla_kazdego(Poczatek: PElement, funkcja: zrob): Boolean;
{działanie: wykonuje funkcje na każdym wstawionym elemencie do stosu
warunki początkowe: Poczatek jest zainicjowanym stosem, zrob jest typem funkcji, która pobiera element stosu i nie zwraca wartości
warunki końcowe: jeśli jest to możliwe, funkcja typu zrób jest wykonywana tylko raz dla każdego elementu wstawionego do stosu i funkcja zwraca True, w przeciwnym przypadku False }
function Dla_jednego(Poczatek: PElement; funkcja: zrob): Boolean;
{ działanie: wykonuje funkcja na elemencie ze szczytu stosu
warunki początkowe: Poczatek jest zainicjowanym stosem, zrob jest typem funkcji, która pobiera element ze stosu i nie zwraca wartości
warunki końcowe: funkcja typu zrób jest wykonywana tylko raz dla elementu ze stosu Poczatek , jeśli istnieje i funkcja zwraca True, w przeciwnym przypadku False }
Etap 3. Implementacja stosu -
Osoba = record
Nazwisko: string[10];
end;
PElement = ^Element;
Element = record
Dane : Osoba;
Nastepny : PElement;
end;
· wstawianie elementów zawsze na początek struktury
Początek „A” „B” nil
Nowy „Z” „A”
Początek
„B” nil
Nowy „Z” nil
function Wstaw(var Poczatek: PElement; Pozycja: Osoba):
Boolean;
var Nowy: PElement;
begin
Nowy:= Nowy_element(Pozycja);
Wstaw:= Nowy<> nil;
if Nowy = nil then Exit; {nie można wstawić, za mało miejsca w pamięci}
Nowy^.Nastepny := Poczatek;
Poczatek := Nowy;
end;
· usuwanie elementów zawsze na początku struktury
Początek „Z” „A” „B” nil
Początek „Z” „A” „B” nil
Pom
Pom
function Usun(var Poczatek: PElement): Boolean;
var Pom:Pelement;
begin
Usun:= Poczatek <> nil;
if Poczatek = nil then Exit;
Pom := Poczatek; {zapamiętanie pierwszego elementu do usunięcia}
Poczatek := Poczatek^.Nastepny; {odłączenie pierwszego elementu od listy}
Dispose(Pom); {usunięcie pierwszego elementu z pamięci}
end;
{typ proceduralny do obsługi elementu struktury}
type zrob = procedure (Ktory: Osoba);
function Dla_kazdego(Poczatek: PElement, funkcja: zrob): Boolean;
begin
Dla_kazdego:= Poczatel <> nil;
while Poczatek <> nil do begin
funkcja(Poczatek^.Dane);
Poczatek:= Poczatek^.Nastepny;
end;
end;
function Dla_jednego(Poczatek: PElement; funkcja: zrob): Boolean;
begin
Dla_jednego:= Poczatek <> nil;
if Poczatek <> nil then funkcja(Poczatek^.Dane);
end;
4.2. Kolejka
Etap 1 - Opis ADT
Nazwa typu - Kolejka elementów
Własności typu: Potrafi przechować ciąg elementów Dostępne działania: Inicjalizacja kolejki
Określenie, czy kolejka jest pusta Dodanie elementu do kolejki,
Szukanie elementu na szczycie kolejki, Usuwanie z kolejki,
Przejście przez kolejkę i przetwarzanie każdego elementu
Wyszukanie elementu ze szczytu kolejki i przetwarzanie tego elementu Usunięcie kolejki
Etap 2 - Budowa interfejsu
procedure Inicjalizacja( var Poczatek, Koniec : PElement);
{ działanie: inicjuje kolejkę
warunki wstępne: Poczatek i Koniec wskazują na pustą kolejkę warunki końcowe: kolejka zostaje zainicjowana jako pusta}
function Pusty(Poczatek: PElement) : Boolean;
{ działanie: określa, czy kolejka jest pusta
warunki wstępne: Poczatek jest zainicjowaną kolejką,
warunki końcowe: funkcja zwraca True, jeśli kolejka pusta, w przeciwnym przypadku False }
function Szukaj(Poczatek: PElement) : Boolean;
{ działanie: szuka elementu na szczycie kolejki
warunki początkowe: Poczatek wskazuje na zainicjowaną kolejkę,
warunki końcowe: funkcja zwraca True, gdy znaleziono element na szczycie kolejki, natomiast zwraca False, jeśli kolejka jest pusta }
function Wstaw(var Poczatek,Koniec:PElement;
Pozycja:Osoba):Boolean;
{ działanie: dodaje element na koniec ciągu, zwany końcem kolejki
warunki początkowe: Pozycja jest daną do wstawienia na koniec zainicjowanej kolejki wskazanym przez Koniec
warunki końcowe: jeśli jest to możliwe, funkcja dodaje daną Pozycja na koniec kolejki i zwraca True, w przeciwnym przypadku False }
function Usun(var Poczatek, Koniec: PElement): Boolean;
{ działanie: usuwa element na początku ciągu wstawionego do kolejki warunki początkowe: Poczatek jest zainicjowaną kolejką
warunki końcowe: jeśli jest to możliwe, funkcja usuwa element na szczycie kolejki i zwraca True, w przeciwnym przypadku False.
Koniec jest równy Poczatek, gdy kolejka jest pusta } procedure Usun_pamiec(var Poczatek, Koniec: PElement);
{ działanie: usuwa elementy z kolejki i inicjuje kolejkę jako pustą warunki początkowe: Poczatek jest zainicjowaną kolejką
warunki końcowe: liczba elementów na stosie jest równa 0, Poczatek jest pustą kolejką i jest równy Koniec }
function Dla_kazdego(Poczatek: PElement, funkcja: zrob): Boolean;
{ tak jak dla stosu}
function Dla_jednego(Poczatek: PElement; funkcja: zrob): Boolean;
{ tak jak dla stosu}
Etap 3. Implementacja kolejki - definicja elementów kolejki jak dla stosu
· wstawianie elementów zawsze na końcu struktury
Początek „A” „B” nil
Nowy „Z”
Początek „A” „B”
Nowy „Z”
nil
Koniec
Koniec
nil
function Wstaw(var Poczatek,Koniec:PElement; Pozycja:
Osoba): Boolean;
var Nowy: PElement;
begin
Nowy:= Nowy_element(Pozycja);
Wstaw:= Nowy <> nil;
if Nowy = nil then Exit; {nie można wstawić, za mało miejsca w pamięci}
if Poczatek := nil then Poczatek := Nowy
else Koniec^.Nastepny := Nowy;
Koniec := Nowy;
end;
· usuwanie elementów zawsze na początku struktury (jak w przypadku stosu).
W przypadku, gdy po usunięciu stos staje się pusty - Koniec jest równy Poczatek:
if Poczatek = nil then Koniec = nil;
· 4.3. Lista nieuporządkowana Etap 1 - Opis ADT
Nazwa typu - Lista elementów
Własności typu: Potrafi przechować ciąg elementów Dostępne działania: Inicjalizacja listy
Określenie, czy lista jest pusta Dodanie elementu do listy,
Wyszukanie elementu na wskazanym miejscu na liście, Usuwanie z listy,
Przejście przez listę i przetwarzanie każdego elementu Wyszukanie elementu z listy i przetwarzanie tego elementu Usunięcie listy
Etap 2 - Budowa interfejsu
procedure Inicjalizacja( var Poczatek : PElement);
{ działanie: inicjuje listę
warunki wstępne: Poczatek wskazują na pustą listę warunki końcowe: lista zostaje zainicjowana jako pusta}
function Pusty(Poczatek: PElement) : Boolean;
{ działanie: określa, czy lista jest pusta
warunki wstępne: Poczatek jest zainicjowaną listą,
warunki końcowe: funkcja zwraca True, jeśli lista pusta, w przeciwnym przypadku False }
function Szukaj(Po czatek:
PElement;
Miejsce:
word; var Gdzie:
PElement) : Boolean;
{ działanie: szuka elementu na liście
warunki początkowe: Poczatek wskazuje na zainicjowaną listę, warunki końcowe: funkcja zwraca wskazanie Gdzie na element wskazujący na element o numerze Miejsce, gdy znaleziono go na liście lub wskazanie puste, gdy element jest na początku listy lub Gdzie wskazuje na koniec listy i zwraca True, w przeciwnym wypadku False }
function Wstaw(v
ar
Poczatek :PEleme nt;Pozycj a:Osoba;
Gdzie:PE lement):
Boolean;
{ działanie: dodaje element w dowolne miejsce ciągu umieszczonego na liście warunki początkowe: Pozycja jest daną do wstawienia na miejscu pośrednio wskazywanym przez Gdzie zainicjowanej listy Poczatek.
warunki końcowe: funkcja dodaje daną Pozycja na miejscu określonym przez funkcję Szukaj lub do pustej listy i zwraca True, w przeciwnym wypadku zwraca False}
function Usun(var Poczatek: PElement; Gdzie: PElement):
Boolean;
{ działanie: usuwa element na dowolnym miejscu w ciągu wstawionym do listy
warunki początkowe: Poczatek jest zainicjowaną listą, Gdzie jest pośrednim wskazaniem na element usuwany określony przez funkcję Szukaj
warunki końcowe: funkcja usuwa z listy element określony przez funkcję Szukaj, lecz pomija przypadek wskazania przez Gdzie ostatniego elementu listy i zwraca True, w przeciwnym wypadku False}
procedure Usun_pamiec(var Poczatek, Koniec: PElement);
{ tak jak dla stosu}
function Dla_kazdego(Poczatek: PElement, funkcja: zrob): Boolean;
{ tak jak dla stosu}
functio n
Dla_jed nego(Po czatek, Gdzie:
PEleme nt;
funkcja:
zrob):
Boolean
;
{ działanie: szuka elementu na liście i wykonuje na nim czynność
warunki początkowe: Poczatek wskazuje na zainicjowaną listę, warunki końcowe: funkcja wykonuje czynność funkcja na elemencie wskazanym pośrednio przez Gdzie określonym przez funkcję Szukaj z wyłączeniem przypadku, gdy Gdzie wskazuje na ostatni element listy i zwraca True, w przeciwnym wypadku False }
Etap 3 - implementacja jako lista jednokierunkowa- element listy jak dla stosu
· szukanie w dowolnym miejscu
Początek „A” „D” nil
Nowy „Z”
Początek „A” „B”
Nowy „Z”
nil
Miejsce =3
Gdzie
„B”
„D” nil Nast Gdzie
function Szukaj(Pocz atek:PEleme nt; Miejsce:
word; var Gdzie:PEle ment):
Boolean;
var Numer : integer; Nast : PElement;
begin
Gdzie:= nil; Szukaj:= False;
if Poczatek = nil then Exit; {nie wstawiono, za mało miejsca w pamięci}
Numer := 1; Nast := Poczatek;
while (Nast^.Nastepny <> nil) and (Miejsce <> Numer) do begin
Gdzie := Nast; Nast := Nast^.Nastepny; inc(Numer);
end;
Szukaj:= (Miejsce = Numer) or (Miejsce = Numer+1);
if Miejsce = Numer + 1 then Gdzie:= Nast;
end;
· wstawianie elementu na dowolne miejsce na liście lub jako pierwszy na pustej
function Wstaw(v ar
Poczatek :PEleme nt;Pozycj a:Osoba,
Gdzie:PE lement):
Boolean;
var Nowy: PElement;
begin
Nowy:= Nowy_element(Pozycja);
Wstaw:= Nowy <> nil;
if Nowy = nil then Exit;
if Gdzie = nil then begin {wstaw na początku listy lub zakładanie listy}
Nowy^. Nastepny := Poczatek; Poczatek := Nowy;
end
else begin {wstaw wewnątrz listy lub na jej końcu}
Nowy^.Nastepny := Gdzie^.Nastepny; Gdzie^.Nastepny := Nowy;
end;
end;
· usuwanie elementu w dowolnym miejscu niepustej listy
Poczatek „B” „Z”
Miejsce = 2
Gdzie
„D” nil
Poczatek „B” „Z” „D” nil
Gdzie
Poczatek „B” „Z” „D” nil
function Usun(var Poczatek: PElement; Gdzie: PElement):
Boolean;
var Pom : PElement begin
Usun:= False;
if Gdzie= nil then begin
Pom:= Poczatek; Poczatek:=
Poczatek^.Nastepny;
end else begin
if Gdzie^.Nastepny = nil then Exit;
Pom:= Gdzie^.Nastepny; Gdzie^.Nastepny:=
Pom^.Nastepny;
end;
Dispose (Pom);
Usun:= True;
end;
functio n
Dla_jed nego(P oczate k, Gdzie:
PElem ent;
funkcja : zrob):
Boolea n;
begin Dla_jednego:= False;
if Gdzie= nil then Gdzie:= Poczatek else
if Gdzie^.Nastepny <> nil then Gdzie:= Gdzie^.Nastepny else Exit;
funkcja(Gdzie^.Dane);
Dla_jednego:=True;
end;
· Etap 3. Implementacja w postaci listy dwukierunkowej nieuporządkowanej
Realizacja typu lista nieuporządkowana w postaci listy dwukierunkowej: nie zmieniły się algorytmy: Usun_Pamiec, Dla_każdego, Dla_jednego, Inicjalizacja, Pusty.
Osoba = record
Nazwisko: string[10];
end;
PElementD = ^OsobaD;
OsobaD = record
Poprzedni : PElementD;
Dane : Osoba;
Nastepny : PElementD;
end;
· wyszukiwanie w dowolnym miejscu listy
nil nil
„D”
nil Poczatek „B” nil
Nowy
Miejsce = 2
„Z”
nil „D” nil
Poczatek „B”
Gdzie
Nowy „Z”
function Szukaj(P oczatek:
PElement D;
Miejsce:w ord; var Gdzie:
PElement D):
Boolean;
var Numer : integer; {algorytm ten sam, w liście można przechodzić w obu kierunkach}
begin
Gdzie:= Poczatek; Szukaj:= False;
if Poczatek= nil then Exit;
Numer:= 1;
while (Gdzie^.Nastepny <> nil) and (Miejsce <> Numer) do begin
Gdzie := Gdzie^.Nastepny; inc(Numer);
end;
Szukaj:=(Miejsce = Numer) or (Miejsce=Numer+1);
{Gdzie wskazuje na element wskazujący na Miejsce}
if (Miejsce = Numer) then Gdzie:= Gdzie^.Poprzedni;
end;
· wstawianie w dowolnym miejscu listy niepustej oraz jako pierwszy na pustej
function Wstaw(var
Poczatek:PElementD;Pozycja:O soba;Gdzie: PElementD):
Boolean;
var Nowy: PElementD;
begin
Nowy:= Nowy_elementD(Pozycja);
Wstaw:= Nowy <> nil;
if Nowy = nil then Exit; {nie wstawiono, za mało miejsca w pamięci}
if Gdzie= nil then {wstaw na początku listy}
begin
Nowy^.Nastepny := Poczatek; {podłącz z prawej na początku}
if Poczatek <> nil then
Poczatek^.Poprzedni := Nowy; {podłącz z prawej na początku}
Poczatek := Nowy; {podłącz z lewej na początku}
end else
begin {wstaw wewnątrz listy lub na końcu}
Nowy ^. Nastepny:= Gdzie^.Nastepny; {podłącz z prawej w środku lub na końcu}
if Gdzie^.Nastepny <> nil then
Gdzie ^.Nastepny ^.Poprzedni := Nowy; {podłącz z prawej w środku}
Gdzie^.Nastepny := Nowy; {podłącz z lewej w środku lub na końcu}
end;
Nowy^.Poprzedni:= Gdzie; {podłącz z lewej w obu przypadkach}
end;
· usuwanie elementu w dowolnym miejscu listy niepustej
nil „Z”
Poczatek
„B”
Miejsce = 2
Gdzie (Usun)
„D” nil
nil „Z”
Poczatek
„B” „D” nil
nil „Z”
Poczatek
„B” „D” nil
Gdzie (Szukaj)
Gdzie (po Usun)
function Usun(var Poczatek: PElement; Gdzie: PElement): Boolean;
begin
Usun:= False;
if Gdzie = nil then Gdzie := Poczatek {korekcja wskaźnika Gdzie}
else
if Gdzie^.Nastepny <> nil then Gdzie := Gdzie^.Nastepny
else Exit; {wyjście, gdy wskazano miejsce za ostatnim elementem}
if Gdzie^.Poprzedni <> nil then {odłącz na lewo}
Gdzie^.Poprzedni^.Nastepny := Gdzie^.Nastepny; {odłącz w środku na lewo}
else Poczatek := Gdzie^.Nastepny; {odłącz na początku na lewo}
if Gdzie^.Nastepny <> nil then {odłącz w środku na prawo}
Gdzie^.Nastepny^.Poprzedni:= Gdzie^.Poprzedni;
Dispose(Gdzie);
Usun:= True;
end;
Przykład zastosowania interfejsu listy dwukierukowej nieuporządkowanej
program Lista_nieuporzadkowana_dwukierunkowa;
uses Crt, Rozne, Modul, MListDLN;
const Tab_menu : Lancuchy =
('1 : Zakladanie listy nieuporzadkowanej dwukierunkowej', '2 : Usuwanie z listy nieporzadkowanej dwukierunkowej',+
'3 : Wydruk listy nieuporzadkowanej dwukierunkowej', '4 : Usun liste nieupoprzadkowana dwukierunkowa', 'K/k - Koniec programu','','','','','','');
procedure Podaj_miejsce(var Miejsce:word); {...}
procedure Wstaw_do_listy(var Poczatek: PElementD);
var Gdzie : PElementD; Dana : Osoba; Miejsce: word; Z: char;
begin
Podaj_dane(Dana); Podaj_miejsce(Miejsce);
if Szukaj(Poczatek,Miejsce, Gdzie) or Pusty(Poczatek) then begin
Wstaw(Poczatek,Dana,Gdzie);
Dla_jednego(Poczatek,Gdzie,Wydruk_danych); Pauza(Z, False);
end;
end;
procedure Usun_z_listy(var Poczatek: PElementD);
var Gdzie : PElementD; Miejsce: word; Z: char;
begin
Podaj_miejsce(Miejsce);
if Szukaj(Poczatek,Miejsce,Gdzie) then Writeln(Usun(Poczatek, Gdzie));
Pauza(Z,False);
end;
var Wybor, Z : char; Poczatek_DLN : PElementD;
begin
ClrScr; Randomize;
Inicjalizacja(Poczatek_DLN);
repeat
Menu(Tab_menu, 5, Wybor);
case Wybor of
'1' : Wstaw_do_listy(Poczatek_DLN);
'2' : Usun_z_listy(Poczatek_DLN);
'3' : begin
Writeln(Dla_kazdego(Poczatek_DLN, Wydruk_danych)); Pauza(Z,False);
end;
'4' : Usun_Pamiec(Poczatek_DLN);
end;
until Wybor = 'K';
end.