To są zadania na kolejki i stosy.
Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__
Przyjmijmy następujące definicje, gdzie typ lista był zdefiniowany w Ćwiczeniach 2.
type stos = lista;
kolejka = record
pocz, kon : lista;
end;
Dla stosów dostępne są następujące funkcje i procedury:
procedure Init(var s:stos); //tworzy pusty stos s
procedure Push(var s:stos; w:integer); //wstawia w na wierzchołek stosu
procedure Pop(var s:stos); //zdejmuje wierzchni element stosu
function Top(s:stos): integer; //wyznacza wartość na wierzchołku stosu
function Empty(s:stos): boolean; //sprawdza czy stos jest pusty
procedure Destroy(s:stos); //niszczy stos (zwalnia pamięć)
Dla kolejek dostępne są następujące funkcje i procedury:
procedure Init(var k:kolejka); //tworzy pustą kolejkę k
procedure PutLast(var k:kolejka; w:integer); //wstawia w na koniec kolejki
procedure GetFirst(var k:kolejka; var w:integer); //usuwa pierwszy element kolejki i zapisuje na w
function Empty(k:kolejka): boolean; //sprawdza czy kolejka jest pusta
procedure Destroy(k:kolejka); //niszczy kolejkę (zwalnia pamięć)
Zadanie 1 (Poprawność wyrażeń nawiasowych)
Napisz funkcję sprawdzającą czy zadane wyrażenie nawiasowe składające się z nawiasów okrągłych i kwadratowych jest poprawne. Zakładamy, że dana jest funkcja DajZnak:integer, która przyjmuje następujące wartości: -1 dla (, 1 dla ), -2 dla [, 2 dla ] i 0 na oznaczenie końca wyrażenia nawiasowego.
Rozwiązanie
function PoprawneNawiasy: boolean;
//Sprawdzamy czy wyrażenie nawiasowe otrzymane przez kolejne wartości funkcji DajZnak jest poprawne
var s: stos;
ok: boolean;
begin
Init(s);
ok:=true;
repeat
z:=DajZnak;
case z of
-1: Push(s, -1);
-2: Push(s, -2);
1: if not Empty(s) then
if Top(s) = -1 then Pop(s)
else ok:=false
else ok:=false;
2: if not Empty(s) then
if Top(s) = -2 then Pop(s)
else ok:=false
else ok:=false;
0: if not Empty(s) then ok:=false;
end {case}
until (z = 0) or (not ok)
PoprawneNawiasy:=ok;
Destroy(s);
end;
Koszt czasowy: liniowy ze względu na długość wyrażenia nawiasowego
Koszt pamięciowy: liniowy ze względu na długość wyrażenia nawiasowego
Ćwiczenie 1
Czy dodanie następnych typów nawiasów istotnie zmieniłoby rozwiązanie ?
Ćwiczenie 2
Jak wygląda optymalne rozwiązanie dla jednego typu nawiasów ?
Zadanie 2 (Maksymalnie odległy porządek)
Napisz funkcję która dla danej tablicy A typu array[1..N] of integer obliczy maksymalne k, takie że k=j-i, 1 ≤ i ≤ j ≤ N, A[j] ≥ A[i].
Wskazówka 1
Jeśli po elemencie i indeksie j pojawi się element większy o indeksie j' większym od j, to element o indeksie j nie ma szans być rekordowym. Takim elementem nie ma się co przejmować, jako końcem potencjalnego rekordowego skoku.
Wskazówka 2
Przeglądając tablicę od tyłu wkładamy na stos kandydatów na bycie najlepszym j. Potem przeglądając tablicę od przodu wyliczamy k, zdejmując zużytych kandydatów na j ze stosu.
Rozwiązanie
function MaksOdległość(N:integer; A:array[1..N] of integer): integer;
//Obliczamy maksymalne k, takie że k=j-i, 1 <= i <= j <= N, A[j] >= A[i]
var s: stos;
i,j,maks: integer;
begin
Init(s);
Push(s, A[N]);
j:=N-1;
while j >= 1 do
begin //wkładamy kandydatów na j na stos
if A[j] > Top(s) then
Push(s, A[j]);
j:=j-1
end;
i:=1;
maks:=0;
while (i <= N) and (not Empty(s)) do //dla każdego i szukamy najlepszego j; uaktualniamy maks
if Top(s) >= A[i] then begin
maks:=max(maks, Top(s)-i);
Pop(s);
end
else
i:=i+1;
MaksOdległość:=maks;
Destroy(s);
end;
Koszt czasowy: liniowy ze względu na długość tablicy
Koszt pamięciowy: liniowy ze względu na długość tablicy
Zadanie 3 (Najpłytszy liść w drzewie)
Napisz funkcję która dla danego drzewa (definicja typu w MP Ćwiczenia2) obliczy głębokość najpłytszego (najbliższego korzeniowi) liścia. Dla drzewa pustego wynikiem powinno być zero, a dla jednoelementowego jeden.
Wskazówka
Trzeba użyć przeszukiwania wszerz i kolejki w której trzymane będą pary składające się ze wskaźnika do węzła i głębokości węzła.
Rozwiązanie
type para = record
drz: drzewo;
poz: integer;
end;
Typ kolejkaPar odpowiada kolejce w której trzymane są wartości typu para; poniżej jest on używany bez uprzedniej definicji.
function NajpłytszyLiść(d:drzewo): integer;
//Obliczamy głębokość najpłytszego liścia w drzewie d
var k:kolejkaPar;
liść: integer;
e,w: para;
begin
if d = nil then NajpłytszyLiść:=0
else begin
Init(k);
e.drz:=d;
e.poz:=1;
PutLast(k, e);
liść:=0;
while (liść = 0) do begin //dopóki nie znaleźliśmy liścia kolejka nie może byc pusta
GetFirst(k, w);
l:=w.drz^.lsyn;
p:=w.drz^.psyn;
if l = nil and p = nil then liść:=w.poz
else begin
if l <> nil then begin //wstawiamy lewego syna do kolejki
e.drz:=l
e.poz:=w.poz+1;
PutLast(k, e);
end;
if p <> nil then begin //wstawiamy prawego syna do kolejki
e.drz:=p
e.poz:=w.poz+1;
PutLast(k, e);
end;
end;
NajpłytszyLiść:=liść;
Destroy(k);
end;
end;
Koszt czasowy: liniowy ze względu na N
Koszt pamięciowy: liniowy ze względu na N
Zadanie 4 (Sortowanie liczb k-cyfrowych)
Zaimplementuj algorytm sortowania tablicy A typu array[1..N] of liczba dziesiętnych liczb k-cyfrowych przy użyciu tablicy dziesięciu kolejek. Typ liczba to array[1..k] of integer, najbardziej znaczący bit jest pod indeksem 1.
Wskazówka 1
{{{3}}}
Rozwiązanie 1
{{{3}}}