16. príklady


Posledná zmena: 1.11.2002

Banner Text zásobník, aritmetické výrazy

Zásobník znakov

metóda top:

medzi metódy na prácu so zásobníkom pridáme novú funkciu top, ktorá vráti hodnotu na vrchu zásobníka, pričom v zásobníku ju ponechá

type
  TPrvok = char;
  TStack = class
    st:array of TPrvok;
    constructor Create;
    procedure push(p:TPrvok);
    procedure pop(var p:TPrvok);
    function top:TPrvok;
    function empty:boolean;
  end;
...
function stack.top:TPrvok;
begin
  if empty then chyba('Prázdny zásobník');
  Result:=st[High(st)];
end;
  • v nasledujúcich úlohách predpokladáme, že máme k dispozícii jednu znakovú premennú, jeden znakový zásobník a čítame jeden riadok textového súboru (ukončený napr. znakom #13). Úlohou je napísať funkciu, ktorá zistí, či vstupný riadok súboru je nejakého konkrétneho tvaru

najprv len a, potom rovnaký počet len b:

anbn, 0<=n

function test(var t:TextFile):boolean;
var
  s:TStack;
  c:char;
begin
  s:=TStack.Create;
  read(t,c);
  while c='a' do begin
    s.push(c); read(t,c);
  end;
  while (c='b') and not s.empty do begin
    s.pop(c); read(t,c);
  end;
  Result:=(c=#13) and s.empty;
  s.Free;
end;

najprv len a, potom rovnaký alebo väčší počet b:

anbm, 0<=n<=m

function test(var t:TextFile):boolean;
var
  s:TStack;
  c:char;
begin
  s:=TStack.Create;
  read(t,c);
  while c='a' do begin
    s.push(c); read(t,c);
  end;
  while c='b' do begin
    if not s.empty then s.pop(c);
    read(t,c);
  end;
  Result:=(c=#13) and s.empty;
  s.Free;
end;

je palindrom:

wcwr

kde w je z abecedy {a,b}

wr je zrkadlový obraz slova w

function test(var t:TextFile):boolean;
var
  s:TStack;
  c:char;
begin
  s:=TStack.Create;
  read(t,c);
  while c in ['a','b'] do begin
    s.push(c); read(t,c);
  end;
  if c='c' then begin
    read(t,c);
    while not s.empty and (c=s.top) do begin
      s.pop(c); read(t,c);
    end;
    Result:=(c=#13) and s.empty;
  end
  else Result:=false;
  s.Free;
end;

rovnaký počet a a b:

#a = #b, rovnaký počet a-čok aj b-čok

function test(var t:TextFile):boolean;
var
  s:TStack;
  c:char;
begin
  s:=TStack.Create;
  read(t,c);
  while c in ['a','b'] do begin
    if s.empty or (c=s.top) then s.push(c)
    else s.pop(c);
    read(t,c);
  end;
  Result:=(c=#13) and s.empty;
  s.Free;
end;

rovnaký počet a, b a c:

logická funkciu abc, ktorá vráti true, ak je vo vstupnom riadku rovnaký počet a-čok, b-čok a c-čok

využite dve inštancie TStack

okrem dvoch zásobníkov môžete použiť už len jednu znakovú pomocnú premennú

function abc(var t:TextFile):boolean;
var
  s1,s2:TStack;
  c:char;
begin
  s1:=TStack.Create; s2:=TStack.Create;
  read(t,c);
  while c in ['a','b','c'] do begin
    case c of
     'a':
       begin
        if s1.empty or ('a'=s1.top) then s1.push('a')
        else s1.pop(c);
        if s2.empty or ('a'=s2.top) then s2.push('a')
        else s2.pop(c);
       end;
     'b':
       if s1.empty or ('b'=s1.top) then s1.push('b')
       else s1.pop(c);
     'c':
       if s2.empty or ('c'=s2.top) then s2.push('c')
       else s2.pop(c);
    end;
    read(t,c);
  end;
  Result:=(c=#13) and s1.empty and s2.empty;
  s1.Free; s2.Free;
end;

Ďalšie úlohy

  • anbicabs(n-i)
  • vyriešte úlohu abc len pomocou jedného zásobníka - ak pritom využijete rekurziu, tak ste vlastne použili druhý zásobník
    • môžete vyskúšať použitie jedného zásobníka a rekurzie

Zásobník celých čísel

  • máme definovaný zásobník celých čísel, t.j. TPrvok = integer;

vyhoď všetky nulové prvky:

pomocou pomocného zásobníka spracujte čísla v zásobníku tak, že vyhádžete všetky nulové prvky

procedure vyhod0(s:TStack);
var
  p:TStack;
  i:integer;
begin
  p:=TStack.Create;
  while not s.empty do begin
    s.pop(i);
    if i<>0 then p.push(i);
  end;
  while not p.empty do begin
    p.pop(i); s.push(i);
  end;
  p.Free;
end;

nulové prvky zásobníka na spodok:

pomocou pomocného zásobníka spracujte čísla v zásobníku tak, že všetky nulové prvky premiestnite na spodok zásobníka

procedure presun0(s:TStack);
var
  p:TStack;
  i,j:integer;
begin
  p:=TStack.Create; j:=0;
  while not s.empty do begin
    s.pop(i);
    if i<>0 then p.push(i)
    else inc(j);
  end;
  while j>0 do begin
    s.push(0); dec(j);
  end;
  while not p.empty do begin
    p.pop(i); s.push(i);
  end;
  p.Free;
end;

Ďalšie úlohy

  • naprogramujte takéto triedenie, ktoré využije dva zásobníky:
    • na začiatku máme čísla v prvom zásobníku
    • vyberieme prvé dve čísla, porovnáme ich - menšie z nich vložíme do druhého zásobníka
    • vyberieme ďalšie číslo z prvého zásobníka - porovnáme ho s číslom, ktoré nám ostalo pri predchádzajúcom porovnávaní - menšie číslo vložíme do druhého zásobníka
    • opakujeme, až kým prvý zásobník nie je prázdny (pri tomto presýpaní, sme mohli spočítať počet triedených čísel)
    • teraz máme v druhom zásobníku všetky čísla, pritom na vrchu je najväčšie z nich
    • podobne presypeme čísla z druhého zásobníka do prvého, ale teraz vkladáme do prvého zásobníka väčšie z porovnávaných čísel
    • po dostatočnom opakovaní tohto algoritmu budú čísla v zásobníku utriedené

Aritmetické výrazy

postfixový zápis:

7 4 * 9 2 4 - * 6 / +

  • vyhodnoťte
  • prepíšte do infixu a prefixu
7 4 * 9 2 4 - * 6 / +
(7 4 *) 9 (2 4 -) * 6 / +
(7 4 *) (9 (2 4 -) *) 6 / +
(7 4 *) ((9 (2 4 -) *) 6 /) +
(7 * 4) + ((9 * (2 - 4)) / 6) = 25   ... infix
+ (* 7 4) (/ (* 9 (- 2 4)) 6)
+ * 7 4 / * 9 - 2 4 6 ... prefix

prefixový tvar:

+ * - + 1 2 3 4 * 5 - 6 + 7 8

  • prepíšte do infixu a postfixu
  • vyhodnoťte
+ * - + 1 2 3 4 * 5 - 6 + 7 8
+ (* (- (+ 1 2) 3) 4) (* 5 (- 6 (+ 7 8)))
(((1 + 2) - 3) * 4) + (5 * (6 - (7 + 8)))
(((1 2 +) 3 -) 4 *) (5 (6 (7 8 +) -) *) +
1 2 + 3 - 4 * 5 6 7 8 + - * +
= 45

infixový zápis:

3*(4+5)-6*7/(8+6)

  • prepíšte do prefixu a postfixu
3*(4+5)-6*7/(8+6)

(3 * (4 + 5)) - ((6 * 7) / (8 + 6))
- (* 3 (+ 4 5)) (/ (* 6 7) (+ 8 6))
- * 3 + 4 5 / * 6 7 + 8 6
(3 (4 5 +) *) ((6 7 *) (8 6 +) /) -
3 4 5 + * 6 7 * 8 6 + / -

Ďalšie úlohy

  • navrhnite algoritmus na vyhodnocovanie výrazov v prefixovom tvare (asi sa použije jeden alebo aj viac zásobníkov)
  • navrhnite algoritmus na vyhodnocovanie výrazu v tvare úplne uzátvorkovaného infixu (napr. nájdeme prvú pravú zátvorku, potom hľadáme ku nej prislúchajúcu ľavú, vyhodnotíme podvýraz medzi zátvorkami a nahradíme ho výsledkom)
  • navrhnite algoritmus na prepis aritmetického výrazu z prefixového tvaru do postfixového tvaru


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