Integer Real
Transkript
Integer máme definovány operace: *,div,mod,+,(na záporných číslech by měla být lichá funkce, ale překladače se chovají různě ⇒ problém) výsledek dělení (/) je vždy real relační operátory: =,<>,<,>,<=,>= priorita operátorů stand. fce: ABS(x) SQR(x) standartní predikát ODD(x) .... x je liché správná hodnota aritmetických funkcí je zaručena pouze tehdy, když jsou argumenty i všechny mezivýsledky zobrazitelné příklad: kdyby maxint=1000 (600+500)-400 - není definováno 600+(500-400) je 700 je dobré (alespoň na ladění) nastavit si v překladači kontrolu přetečení v tomto smyslu není sčítaní integerů asociativní těch integerů je několik (integer,shortint, longint) a jsou i celá čísla bez zaménka (byte, word) Real slouží k zobrazení reálných čísel zobrazuje se nepřesně, a chyba se nasčítává čísla se ukládají v normalizovaném tvaru - 0,(nenulový bit)(ostatní číslice) ⇒ je jasné, že číslo začíná 0,1 - takže se ty první dva bity neukládají důsledek: nejde zobrazit 0 - řeší se to jinak aritmetické operace *,+,-,/ 1 exp(x) počítá e^x var N,i:integer; suma,ntina:real; begin N:=1;suma:=1; while suma=1 do begin ntina:=1/n suma:=0;i=1 while i<=N do begin suma:=suma+ntina; i:=i+1 end n:=n+1 end write(n) testovat real na rovnost nemusí mít dobrý smysl - je lepší testovat absolutní hodnotu rozdílu stand. fce.: abs(x) sqr(x) (funkce je napsána tak, že ji nemůžeme napsat - může mít prametr buď integer, nebo real) sin(x) cos(x) exp(x) ln(x) sqrt(x) arctan(x) funkce pro konverci trunc(-3,645)=-3 round(x) - nejližší celé číslo (může se lišit pdle překladače) Složitost algoritmů Slovník obsahuje 72 000 slov (normální). dokážu prohlédnout 10 slov za min. Bude mi to trvat 7200 sekund=2 hodniy. Kamarád čte 1sl/10s, ale hledá metodou půlení intervalu - přečte 17slov a bude mu to trvat <=3 min. -chceme měřit čas a spotřebu paměti 2 -dá se měřit - v sekundách (různě rychlé počítače), v počtu provedených příkazů (příkazy trvají různě rychle) hlavní co nás zajímá je, co kdyby se data (oběm) zdvojnásobila složitost=funkce(velikost úlohy) já - n → n kamarád - n → log2n je N prvočíslo? read(N); d:=2; while (d<N) and (N mod d<>0) do d:=d+1; if d>=n then writeln(’JE’) else write(’NENI’); složitost - funkci, která nám vyjde zkusíme shora odhadnout - asymptotická složitost f = O(g) ⇔ ∃n0 ∈ N ; ∃C ∈ R; ∀n > n0; f (n) ≤ C .g(n) složitost se udává dvou druhů - nejhorší a průměrný případ složitost zkracujeme jen na ten nejsložitější člen příklad: algoritmus vlny - složitost je n4 (horní odhad) pro očíslování šachovnice a n2 pro cestu zpátky paměťová složitost - n2 (musím napsat do paměti celou šachovnici) Příklad: spočítání hodnoty polynomu v bodě f = 27x5 read(x);read(n); suma:=0; while N>=0 do begin {přičti další člen mnohočlenu} (*) N:=N-1 end (*) read(k); xnantou:=1 i:=1; while i>=N do begin xnantou:=xnantou*x; i:=i+1 end suma:=suma+k*xnantou O(n(n+1))=O(n^2) 3 hornerovo schéma (postupně se to povytýká) read(x);read(n);suma:=0; while N>=0 do begin read(k); suma:=suma*x+k; N:=N-1 end; O(N ) hornerovo schéma se používá i pro čtení čísel v nějaké soustavě (není to nic jiného, než polynom) aN - můžu spočítat cyklem - O(N ) x678 678=101010010 x678 = x512 x128 x32 x4x2 stačí mi pouze 13 násobení - O(log N ) read(x);read(n); V:=1; while N>0 do begin if N mod 2 =1 then V:=V*x; N:=N div 2; x:=x*x; end; 051019 Borland pascal textový soubor -> překldač zjistí, že je to napsáno v pascalu ->přeloží program->program IDE - všechno najednou (překladač, textový editor, zvýrazňovač syntaxe, spouštěč) {vypocet mocniny x^a} var a:integer; V,x:real; begin readln(x,a); V:=1; while a<>0 do begin if a mod 2 =1 then V:=V*x; a:=a div 2; x:=x*x end; write(V); readln 4 end. krokování: step over trace into (leze do podprogramů) text o IDE Borland pascalu na stránkách TH složitost - na konstantně taky záleží rychlost programu nezáleží jen na složitosti podmínky co je podmínka? je to hodnota typu boolean (pouze true/false) dá se provonávat true>false (a<3)<=(b>6) not .... ? and .... = or.... xor ... <> v TBP je or,and,xor i pro integer (po bitech) je nutné výrazy uzávorkovat if P=true then ... ⇔ if P then... if Q=false then ... ⇔ if not Q priority: 1. negace 2. konjukce 3. disjunkce 5 př.: rozhodněte, jak byla posloupnost monotónní var rostla,kleslastejná:boolean; rostla:=false;klesla:=false; stejna:=false; read(minx,x); while x<>0 do begin *porovnání minx:=x; read(x) end; *rozhodnutí end. *porovnání: if x>minx then rostla:=true else if x<minx then klesla:=true else stejna:=true; ( ⇔ rostla:=(x>minx) or rostla) *rozhodnutí if rostla then if klesla then write(’není monotónní’) else write(’rostoucí’) else {nerostla} if klesla then if stejna then write(’nerostoucí’) else write (’klesající’) else {neklesala} if stejna then write (’konstantní’) else write (’jen 1 prvek’) zkrácené vyhodnocování výrazů P or Q -> když platí P už nemusíme zkoumat Q R and S -> když neplatí S nemusíme zkoumat S dovolí nám to zapsat podmínky, které by se nám zapisovaly ztuha Příklad 1. posloupnost 1,5,-3,2,4,63,-3,3,-5 podmínka (ln(x)>s) and (ln(x)*sqrt(x)<7 jde to zapsat jen díky zkrácenému vyhodnocování zvláštní typ komentáře - {$B+} pro zkrácené vyhodnocování výrazů mají přednost před nastavením kompilátoru dají se nastavit několikrát v průběhu programu 6 typ char slouží k ukládání znaků konstanty: ’@’ tisk apostrofu - ” ” kód znaku v ASCII ord(c) char->integer chr(x) integer->char char(-5) =char(250) bez ohledu na nastavení kontrol přetečení norma požaduje ’0’,’1’,...,’9’ v tomto pořadí a pezprostředně za sebou ’a’,’b’,...,’z’ v tomto pořadí ’A’,’B’,...,’Z’ v tomto pořadí jak jde testova číslice: (z>=’0’)and (z<=’9’) n=ord(’n’)-ord(’0’) - hodnota znaku selekce čísla z řetězce var c:char; x:integer; begin {preskocit ne-cislice:} c:=’?’ while not((c>=’0’) and (c<=’9’) do read(c); {tedy už mám číslici} while (c>=’0’) and (c<=’9’) do begin x:=x*10+ord(c)-ord(’0’); read(c); end end. read s parametrem char čte postupně z řádky to, zo jsem napsal (čte postupně jednotlivé znaky) vstup a výstup čteme z textového souboru standartní vstup zapisujeme do textového souboru standartní výstup textový soubor - malinko (konci řádků) strukturovaný 7 read - čte znaky postupně readln - čte znak a přeskočí na další řádku podle normy do char nepatří znaky konce řádku a konce souboru ve windows se na přechod na další řádek používají dva znaky - CR LF eof - vrací true, když jsme na konci souboru eoln - vrací true, když jsme na konci řádky co můžeme číst ze souboru? coar, integer, real prázdné řádky s mezerami se přeskakují podle normy čtení čísla končí prvním znakem nekončícím číslem - v praxi to tak není - pascal požaduje mezeru nebo konec řádky je dobré si zaškrtnout autosave presměrování vstupu: a< data 051027 write, writeln - píší do textového souboru (defaultně do souboru output) formátování výstupu 1. výraz:délka (doplní se zleva mezerami na délka, pokud je delší, tak se to vytiskne delší) 2. hodnoty real se vypisují v normalizovaném tvaru (s exponenty) write(pi:5:2) => _3.14 zápis do ostatních souborů 1. definuje proměnou text (textový soubor) 2. přiřazení souboru té proměnné - assign(f,jméno); 3. otevření souboru příkazem a. reset (pro čtení) b. rewrite (pro zápis, pokud soubor existuje, tak ho přepíše) c. append - přidání na konec 8 (operační systém ten soubor načte, a načte určité množství dat do paměti 4. první parametr read/write je proměnná typu text 5. zavření souboru přkazem close var f,h:text; c:char; begin assign(f,’c:/boot.ini’); reset(f); assign(g,’vystup.txt’) rewrite(g); while not eof(f) do begin read(f,c); write(g,c); write(c) end; close(f); close(g) end. když se nedá po zápisu do souboru příkaz close, tak se nezapíše celý buffer z paměti->soubor bude nekompletní datové typy ordinální pokud je hodnot konečný počet, hodnoty jsou uspořádány, ke každému číslu najdeme následníka funkce ord vrací číslo hodnoty ord(false) =0 ord(true)=1 ord(číslo)=číslo ord(znak)=číslo znaku pred - předchůdce succ - následník kraje by měli hlásit chybu, ale nejde na to spoléhat var zn:char; begin zn:=’A’; repeat writeln(’znak’,zn,’má číslo’,ord(zn); 9 zn:=succ(zn) until zn>’Z’ end. pokud jsou čísla v kódování znaků bezprostředně po sobě je splněta podmínka ord(’z’)-ord(’a’)=25 výčtové typy type identifikátor=popis typu type dev_v_tydnu=(pondeli,uteri,streda,ctvrtek,patek,sobota,nedele) zvrhlost: type integer=longint; interval: male_cislo=0..255; cislice=’0’..’9’; pracovni_dny=pondeli..patek; cisla_od_m_do_n=m..n; den:=ctvrtek je přehlednější, než den:=3 taky to hlídá meze - pokud je to nastavené interval ⊆ hostitelský typ příkaz cyklu for for ordinalni_typ:=pocatecni_vyraz to/downto koncovy_vyraz do prikaz; var i:integer; begin for i:=1 to 10 do write(’a’); end. var i:integer; begin for i:=10 to 1 do write(’a’); {nevytiskne to žádné áčko} 10 end. var i:integer; begin for i:=1 to 10 do begin write(’i’,’ ’); if (i mod 7)=0 then i:=i+1 end. {podle normy se to nesmí} změna proměnné (velmi pravděpodobně) nemá vliv na mez; ale to jak se vyhodnocuje konc cyklu je různé na zvyšování řídící proměnné cyklu se kontroly přetečení nevztahují předčasné ukončení cyklu - break - pokračuje to prvním příkazem za cyklem, ze dvou cyklů zároveň continue - pokračování v cyklu dál paskal nedovoluje u cyklu for krok - musí se to násobit strukturování dat: pole array[ordinalni_typ] of dilci_promena(typ může být i interval) (dilci_promena je taky typ a může být i pole) výcerozměrné pole je pole polí ([typ,typ1]=[typ] of array [typ1] C[4,2]=C[4][2] const PrvniPismeno=’A’; var a:array[PrvniPismeno..’z’] of integer; c:char; f:text; begin for c:=prvniPismen to ‘z‘ do a[c]:=0; assign(f,’c:/boot.ini’); reset(f); while not eof(f) do begin read(f,c); _________________________________________ while not eof(f) do; a[c]:=0; 11 assign(f,’c:/boot.ini’); reset(f); například překódování znaků se dá dělat velmi dobře přes pole proměnné jsou stejného typu, pokud se deklarují jménem, nebo pokud se deklarují společně pomocí dosazení můžu přiřadit i celé pole i jednotlivé řádky, pokud jsou stejného typu vyhledávání v neuspořádaném poli - for cyklem od začátku do konce (musím mít dva testy) -while (i<=kon) and (p[I]<>hledany) do I:=I+1; (musí se vyhodnocovat zkráceně) (taky 2 testy) -přes zarážku - while P[i]<>hledany do i:=i+1; if i=kon+1 then ... hodnota cyklovací proměnné je po skončení for cyklu nedefinovaná konstanty const prvnipismeno=’A’; hodí se to, když něco upravuju na více místech 051003 Erastothenovo síto hledání prvočísel až do nějakého čísla pole booleanů důkaz: konečnost: N − i ≥ 0 a znenšuje se o 1 v každém kroku korektnost: a)že nevyloučíme prvočíslo - vylučují se pouze násobky -> vyloučené číslé má dělitele b) že zůstanou pouze prvočísla - a)=>nevynechali jsme žádné prvočíslo a každé vyloučilo násobky složitost: i − 2..N ; druhý cyklus i ∗ 2..N po krocích i složitost < n P n i určitě je < n2 i=2 ukládání polí v paměti dva typy deklarace (podle normy): 12 =array[..] =packed array[..] z hlediska funkčnosti nemá význam v array se mohou vynechávat kusy paměti kvůli tomu že procesor čte na po čtveřicích - u packed array se některé prvky pole musí přečíst dvakrát v turbo pascalu je option v kompilátoru “word align data”, v Delphi je zase packed array ukládání řetězců 1) ukončovací znak 2) zapamatování délky nevýhoda 1) - řetězec nemůže obsahovat ukončovací znak, musíme projít pole na zjištění délky nevýhoda 2) - zabírá paměť, omezuje délku řetězce v pascalu je pro řetězec typ string - pole znaků indexované od 0 - v nultém prvku je znak určující délku, další jsou znaky; dá se deklarovat string [10]; - můžu omezit délku v Delphách - je řetězec odkaz do paměti co se se stringem dá dělat: s:=’abcdef’+’xyz’; s:=s+’.’; write(s); read(s); length(s) ≈ ord(s[0]) copy(řetězec,odkud, kolik) - vrací podřetězec copy (’abcd’,2,2)->’bc’ copy (’abcd’,3,50)->’cd’ copy(’abc’,50,9)->’’ pos(podřetězec,řetězec) - vrací pozici prvního výskytu podřetězce; když není, vrací 0 pos(’a’,’dabc’) ->2 výměna částí před a za pomlčkou: var s:string; q:byte; begin readln(s); q:=pos(’-’,s); if q<>0 then writeln(copy(s,q+1,255);) +’-’ +copy(s,1,q-1); else writlen(s) end. příklad: var s:string; c:char; 13 i:byte; begin i:=0; while not eof do begin read(c); i:=i+1; s[i]:=c end; writlen(s); readln end. problém je v tom, že se nemění délka řetězce - je pořád 0 je nutné to dělat: s:=s+c; typ záznam slučuje několik proměných různého typu type adf= record x,y:integer; c:char end; adf.x:=234; adf.y:=432; adf.c:=54; zvyk - názvy typů začínají T Variantní záznam: record Jmeno:.. Vaha:.. DatumNarozeni:.. case druh:TDruh of Slon:(PocetNohou:integer,delkaChobotu:real); Chobotnice:(PocetChapadel:byte); end; v praxi to jde trochu hůř - problémy: nic se nehlídá; ty další hodnoty se překrývají - znamená to jen, že se mi ty hodnoty přepíší, když tam budu psát. =>nemá příliš cenu to používat (jen u obrovských oběmů dat) podprogramy var nasobitel:integer; begin RadnaX; Nadpis; 14 RadkaX; for nasobitel:=1 to 10 do Nasobky(nasobitel); {nasobitel je skutečný parametr} RadkaX; end. procedure RadkaX; begin writeln(’XXXXXX...X); end; precedure Nadpis; var i:integer; begin write(’X X’); for i:=1 to 10 do write(i:3); write(’ X’) end; procedure Nasobky(x:integer); {x je formální parametr} var i:integer; begin write(’X’,x:2,’X’); for i:=1 to 10 do write(i*x:3); writeln(’ X’); end; definice podprogramů mají být před var BLOK má tvar: const type var deklarace procedur a funkcí tělo program, procedura, funkce mají tvar bloku (můžu definovat proceduru v proceduře) toto pořadí má význam, že to můsím postupně deklarovat; ale v TPC pořadí není nutné dodržet lokální symboly: proměnné atd. které jsou deklarované jen lokálně - mají pouze lokální platnost když mám globální proměnnou stejnou jako lokální, používá se to v té nejbližší části - to lokální var A:array[1..max] of record x,y:integer end; A[1].x:=A[1].x+1; ⇔ with A[1] do x:=x+1+z; 15 with jakoby odmaskuje tu hlavní proměnno ->může to znepřehlednít program DÚ program, který vytiskne svůj vlastní zdrojový kód subj:sam sebe 051110 návratová hodnota funkce funkce nemůže vracet string, rocord ... - jen jednodušší typy function Min(P:TPole):real; var m:real; i:integer; begin m:=P[1] for i:=2 to N do if P[i]<m then m:=P[i]; Min:=m end. příčiny vracení pokaždé jiných hodnot - neinicializovaná proměnná/nevracení pormněnné z procedur nebo funkcí předávání více parametrů z procedur/funkcí parametry předávané • hodnotou • odkazem procedure MinMax(P:TPole;var Min,Max:real); (var platí až do ’:’) procedure P({var} A,B,C:real); begin A:=B+C; B:=A*C; C:=A-B writeln(A,B,C) end; var x,y,z begin X:=5;Y:=5;Z:=5; P(X,Y,Z);{(X,X,X)} - to je chyba, která se špatně hledá write(X); end. výstupy: 10 50 -40 5 10 50 -40 0 16 10 100 0 0 0 0 0 0 volba způsobu předávání: pokud chceme výstup, musíme předávat odkazem má-li to být parametr/vstupní data (jednoduchá) - je vhodné hodnotou velké proměnné se předávají odkazem (nevytváří se dvakrát) - ale můžeme si přepsat data => => předávání konstantním parametrem: procedure P(const P:TPole); rekurze function fakt(N:integer):integer; begin if N<=1 then fakt:=1; else fakt:=N*Fakt(N-1) end; zásobník - standartně 16KB výhody a nevýhody rekurze: + plno věcí se dá napsat snadno - o něco náročnější na čas a paměť odstrašující případ function fib(I:integer):integer; begin if i<=1 then fib:=1 else fib:=fib(i-1)+fib(i-2) end; !má to exponenciální složitost! v TPC je ’Call stack’ - zobrazuje ty rekurze hanojské věže procedure Prendej(odkud, kam:integer); begin writeln(ODKUD,’->>’,kam) end; procedure Presun (Kolik,odkud,kam,pom:integer); begin if Kolik=1 then Prendej(odkud,kam) else begin 17 Presun(kolik-1,odkud,pom,kam); Prendej/odku,kamú; Presun/kolik-1,pom,kam,odkud) end; var N:integer; begin readln(N); presun(N); problém dvou loupežníků N předmětů s hodnotamy a1, , an můžeme rozdělit do dvou skupin tak, že oba mají stejně? dokážeme vyrobit součet S? const A:TPole=(1,2,34,5,6,76,44); function lze (kolik:integer;od:integer):boolean; begin if Kolik=0 then Lze:=true else if kolik<0 then lze:=false else if od>N then lze:=false else if Lze(kolik,od+1) then lze:=true else if lze(kolik-A[od],od+1) then lze:=true else lze:=false; end; {$B-} function lze0 (kolik:integer;od:integer):boolean; begin Lze:= (kolik=0) or ((kolik>=0) and (od<=N) {potřebuji zkrácené vyhodnocování výrazů} and Lze(kolik,od+1) or lze(kolik-A[od],od+1)) end; definice typovaných konstant x:array[1..10] of integer =(1,2,3,4,5,...); k:TKomplex=(im:6.4;re:4.3); 18 datová struktura fronta/zásobník FIFO - fronta LIFO - zásobník obecný algoritmus prohledávání stavů 1. seznam (neprozkoumaných stavů) := {počáteční stav} 2. dokud není konec opakuj: a. když seznam je prázdný =>konec řešení neexistuje b. vyber stav S ∈ seznam a odstraň ho ze seznamu c. prozkoumej S: d. =pro každý S’ takový, že S -> (1 krok) S’ je-li S’ cílový stav => konec, řešení nalezeno jinak přidej S’ do seznamu pokud je seznam fronta => prohledávání do šířky - vlna zásobník=> prohledávání do hloubky - rekurze procedure Tiskni(Kolik:integer); {zavolá ’’Kolik’’ vnořených for cyklů) var i:intger; begin for i:=0 to 1 do if Kolik=0 then write(’.’) else Tiskni(Kolik-1) end; 051124 vyhodnocení aritmetickéhoo výrazu 5+7*9-(9*(3-x))*5 function Vyraz:integer; var V:integer begin V:=člen; if (input^=’+’) or (input^=’-’) then begin read(c) if c=’+’ then V:=V+Člen else V:=V-Člen end; Vyraz:=V 19 end; function Člen:integer; var X:integer; C:char; X:=Faktor; while(input^=’*’) or (input^=’/’) do {input^ znamená podívej se na vstup funguje jen v c} begin read(c); if c=’*’ then x:=x*faktor else x:=x div faktor end; Člen:=X end; function Faktor:integer; var c:char; begin if (input^>=’0’) and (input^<=’9’) then faktor:=číslo {hornerovo schéma} else begin read(c); if c=’-’ then faktor:=-faktor {unární mínus} if c=’S’ then begin {další funkce (například sinus)} read(c);if c<>’(’ then chyba; Faktor:=FunkceS(Vyraz);read(c);if c<>’)’ then chyba; end; if c=’x’ then faktor:=ProměnnáX else if c=’(’ then begin faktor:=výraz; read(c); if c<>’)’ then chyba end end else chyba end; V jakém pořadí se to má zapsat? - jedno řešení - vnořit funkce do sebe - Výraz[Člen[Faktor]] nebo Výraz [Faktor;Člen] - další řešení - předběžná deklarace: function Vyraz:integer;forward; potom už stačí psát jenom function vyraz; ale je blbost to dělat když to nadeklaruju dvakrát jinak tak mi to vyhlásí chybu - je to dobře protože jí snadno zjistím další způsob vyhodnocování výrazů: 5+3*7-2*(7+14)*2-6*2 20 1 2 1 2 11 2 1 2 (poznačím si prioritu) metodou rozděl a panuj - Divide & Impera const nic=maxint; deset=10; function H(s:string):integer; var min,kde,z:integer; begin min:=nic; {je lepší tam ukládat první prvek} Z:=0; for i:=1 to length(s) do if s[i]=’(’ then z:=z+deset; if s[i]=’)’ then z:=z-deset; if (s[i]=’+’) of (s[i]=’-’) then if z+1<=min then begin min:=z+1; kde:=i end if (s[i]=’*’) or (s[i]=’/’) then if z+2<=min then begin min:=z+2; kde:=i end; if min=nic then H:=Cislo {pozor na (((5)))} else ku:= min div deset; s:=copy(s,ku+1,length(s)-2*ku); zde:=kde-ku; if s[kde]=’+’ then H:=H(copy(s,1,kde-1))+H(copy(s,kde+1,length(s)-kde)) else if s[kde]=’-’ then Rozděl a panuj QuickSort V průměrném případě nejrychlejší třídící algoritmus 5 3 8 29 17 4 1 2 7 15 3 procedure QS(zac,kon:integer); var i,j:integer; pom,p:typ; begin i:=zac;j:=kon; p:=.... while A[i]<p do i:=i+1; while A[j]>p do j:=j-1; if i<=j then begin pom:=A[i];A[i]:=A[j]; A[j]:=pom; i:=i+1;j:=j-1 end; 21 until i>j; if j>zac then QS(zac,j); if i<kon then QS(i,kon) end; složitost: v nejhorším případě n*log n v průměrném případě n2 Jak najít hodnotu pivota? - první, poslední - průměr z nich Jak omezit nebo odstranit rekurzi 1) nahradit iterací procedure P(X:integer); begin ........ ........ ........ ........ if x>7 then P(X-5); end; je to samé, jako když procedure P(X:integer); begin repeat begin ........ ........ ........ ........ X:=X-5 end until x<=2; end; 2) Vlastní zásobník např. v Quicksortu si budu do zásobníku ukládat ty meze 3) Omezit počet volání ukládáním výsledků 051201 iterace místo jednoho volání paměťová složitost Quicksortu? 22 pokud to dělám špatně, tak v nejhorším případě O(n) pokud to budu dělat částečně iterací a budu do zásobníku ukládat delší část, tak maximálně O(log n) Fronta, Zásobník var Z:array[1..Max] of Typ; Počet: integer; Ins: if Počet>=Max then ... Inc(Počet); Z[Počet]:=w; Del: if Počet<=0 then ... x:=Z[Počet]; Dec(Počet); var F:array[1..Max]of typ; Počet:integer; Ins: stejně jako zásobník Del: Posun prvků: for i:=1 to Počet-1 do F[i]:=F[i+1]; Dec(Počet); Lepší řešení: var První, Poslední:integer; init: První:=1; Poslední:=0; ins: if Poslední >= Max then ... Inc(Poslední); F[Poslední]:=x; Del: if První>Poslední then ... x:=F[První]; inc(první); kruhová (cyklická) fronta: var První, Poslední:integer; init: První:=1; Poslední:=0; Počet:=0 ins: if Počet>=max then ... Posední:=(Poslední+1) mod Max; F[Poslední]:=x*inc(Počet); Del: if počet<=0 then ... (pokud mám indexovat od 1: x:=x mod max +1) 23 x:=F[První]; první:=první mod max+1; Počet:=Počet-1; Do šířky nebo do hloubky? “Nejkratší cesta” - do šířky, pokud to jde var S: array[1..8,1..8] of integer; procedure Konec(x,y,cx,cy,krok:integer); begin writeln(’Nejkratsi cesta na [’,cx,’,’,cy,’] je dlouha ’,krok); readln; halt(0); end; procedure Hledej(x,y,cx,cy,krok:integer); begin writeln(x,y); if (x<1) or (x>8) of (y<1) or (y>8) then exit; if (x=cx) and (y=cy) then Konec (x,y,cx,cy,krok); if S[x,y]<>0 then exit; S[x,y]:=krok; Hledej(x-1,y-1,cx,cy,krok+1); Hledej(x,y-1,cx,cy,krok+1); Hledej(x+1,y-1,cx,cy,krok+1); Hledej(x+1,y,cx,cy,krok+1); Hledej(x-1,y,cx,cy,krok+1); Hledej(x-1,y+1,cx,cy,krok+1); Hledej(x,y+1,cx,cy,krok+1); Hledej(x+1,y+1,cx,cy,krok+1); end; var begin for i:=1 to 8 do for j:=1 to 8 do tohle není dobrý nápad kompromis - prohledávání do omezené hloubky Umisťování dam 3. Verze: V každém řádku právě jednadáma 24 V každém sloupci právě jedna dáma Na každé ůhlopříčce právě jedna dáma 051208 programování her Definice 2. Prohrávající pozice Buď už je konec hry a hra je prohraná, nebo taková pozice, kdy všechny tahy vedou do vyhrávajících pozic. Definice 3. Vyhrávající pozice Taková pozice, kdy existuje tah vedoucí do prohrávající pozice strom hry - hra musí být konečná; a musí to být hra s úplnou informací Teorém 4. Shanon V konečné hře s úplnou informací alespoň pro jednoho hráče existuje neprohrávající strategie. Minimax když jdeme od spodu ohodnoceného stromu, a pro každého hráče vybíráme jeho nejvýhodnější tah - na konci dostaneme tah, který je nejlepší zaručený function Max(P:TPozice: Ohodnocení; begin if UzJeKonecHry(P) then Max:=HOdnota(Pozice) else {najdi maximum z ohodnocení pozic, do kterých se můžeš dostat:} begin m:=-MocMaleCislo; for ...VsechnyMozneTahy(Pozice) do begin x:=Min(ProvedTah(Pozice,tah),-Kdo) {Min, protože si bude vybirat soupeř} if x>m then begin m:=x; nejlepsitah:=tah end end; Max:=m end; function Min(P:TPozice: Ohodnocení; begin if UzJeKonecHry(P) then Max:=HOdnota(Pozice) else 25 {najdi maximum z ohodnocení pozic, do kterých se můžeš dostat:} begin m:=-MocVelkeCislo; for ...VsechnyMozneTahy(Pozice) do begin x:=Max(ProvedTah(Pozice,tah),-Kdo) {Max, protože si bude vybirat soupeř} if x<m then begin m:=x; nejlepsitah:=tah end end; Max:=m end; jednou funkcí: (NegaMax) function NegaMax(P:TPozice): Ohodnocení; begin if UzJeKonecHry(P) then Max:=HOdnota(Pozice) else {najdi maximum z ohodnocení pozic, do kterých se můžeš dostat:} begin m:=-MocMaleCislo; for ...VsechnyMozneTahy(Pozice) do begin x:=-NegaMax(ProvedTah(Pozice,tah),-Kdo) {Min, protože si bude vybirat soupeř} if x>m then begin m:=x; nejlepsitah:=tah end end; Max:=m end; vyvolání chyby: RunError(77) statická ohodnocovací fce: u šachů nelze spočítat do matu - musíme spočítat jen kousek a ohodnotit nějak jinak optimalizace minimaxu 1. α − β prořezávání: můžeme zahazovat některé větve, o kterých je jasné, že už nic neovlivní (α je dolní mez a β je horní mez) Poznámka 5. u šachů je branching faktor 36 -> pomocí α − β prořezávání to jde snížit na 6 26 2. občas jde ukládat výsledky 3. používá se cache - pamatuje si jen několik posledních tahů. 4. procházení do různých hloubek (postupně se zvětšující) 5. Metoda okénka - odhadnu se α a β a tím minimalizuji některé tahy - když mi nic nevyjde, tak aspoň mám nový odhad pro β (můžu začínat na nekonečnech) 6. Heuristika - rada; tip; něco, co dává obvykle dobré výsledky dva významy - ”nic nemůžu zkazit”; ”náhradní, přibližné řešení” 051215 Rekursivní data type výraz=record op: operátor; opd1, opd2: term end; term=record if t then (id:alfa) else (podvýraz:výraz) end; tohle se v pascalu zapsat nedá dají se tím zaznamenat např. aritmetické výrazy nebo rodokmen musí obsahovat větvení rekursivní data se zapisují pomocí pointerů -konstanta NIL - nikam neukazuje type Pinteger=^integer; var p,q:^rod; new(p); - vytvoří novou dynamickou proměnnou daného typu v Haldě a přidělí se adresa do p p^:=17; new(q); q^:=p^; - q^ je teď 17 q:=p; - teď stratím bývalé q^ a už se na ní nikdy nedostanu dispose(q); - zahodí tu proměnnou, !do q !ne!dosadí NIL! teď kdybych zapsal do p, tak bude problém 3 části paměti Statická - globální proměnné 27 Zásobník - lokální proměnné podprogramů Halda - dynamycké proměnné (obhospodařuje jí správce haldy) Halda správce si pamatuje - začátek, konec haldy, vrchol haldy a seznam děr (píše si to do těch děr kvůli tomu přiděluje minimálně 8 bytů) MemAvail - kolik paměti zbývá na haldě MaxAvail - jak velký je největší spojitý kus Mark(pointer) - do pointer dosadí aktuální vrchol haldy Release(pointer) - uvolní všechno, co je v haldě nad pointer nikdy nepoužívat dispose a mark+release dohromady - díra může začít odkazovat na plné místo pointer má 4 bajty NIL má hodnotu samých nul na adrese NIL leží vektor přerušení - když tam zapíšu, tak se to sekne (nebo, v lepším případě, to shodí proces) každých 18 ms se zapíná časovač - přerušení var m,FCL:^rod; new(FCL); FCL^.Jmeno:=’Ted’; vew(FCL^.otec); FCL.otec^.Jmeno:=’Fred’; FCL^.otec^.otec:=NIL; FCL^.otec^.matka:=NIL; new(FCL^.matka); . . . m:=FCL^.matka m^.Jmeno:=’Mary’; FCL a m jsou globální, ostatní jsou na haldě Lineární spojový seznam type PPrvek=^TPrvek; TPrvek=record x:typ; 28 Další:PPrvek end; var zac:PPrvek; vyjímka - můžu deklarovat ukazatele na typy, které ještě nejsou deklarované (ale musí být v tom samém bloku type) var p:PPrvek; p:=zac; while p<>NIL do begin write(p^.x); p:=p^.Další end přidání nového prvku na začátek new(n); n^.x:=... n^.Další:=Zac; Zac:=n přidávání na konec: n^.Další:=NIL; if Zac=NIL then Zac:=n else begin p:=Zac; (tady pozor, jestli p^ není NIL) while p^.Další<>NIL do p:=p^.Další; p^.Další:=n; mazání ze začátku: if Zac=NIL then chyba p:=Zac; Zac:=Zac^.Další; dispose(p); mazání od konce: if Zac=NIL then chyba if Zac^.Další=NIL then begin dispose(Zac);Zac:=NIL end else begin p:=Zac; while p^.Další^.Další<>NIL do p:=p^.Další; dispole(p^.Další) p^.Další:=NIL end; přidání: na začátek - konstantí na konec - lineární (když si pamatuji konec, tak i konstantní) mazání 29 ze začátku - k z konce - lineární zásobník - přídávání na začátek, odebírání ze začátku fronta - přidávání na konec, odebírání ze začátku mazání prvku s ukazatelem Zac,m:PPrvek; if m^.Další<>NIL then begin g:=m^.Další; m^:=g^; nebo m^.x:=g^.x;m^.Další:=g^.Další; dispose(g) můžeme si na konec seznamu dát zarážku - není to práce navíc - stačí si deklarovat NYL Funkce,která docela pomůže: function Prvek(x:integer;a:PPrvek):PPrvek; var p:PPrvek; begin new(p); p^.x:=x; p^.Další:=a; Prvek:=p; end; Zac:=Prvek(10, Prvek(20, Prvek(30, Prvek(40, Prvek(50,NIL))))); 051222 fragmentace haldy - pokud používáme dva spojové seznamy s různě velkými prvky pomoc - svépomocné dispose - budeme ty prvky recyklovat ve spojovém seznamu se nedokážem dostat na předchůdce - řešením je obousměrný seznam seznam, který není nikdy prázdý - má hlavu - nemusíme ošetřovat některé zvláštní případy cyklický seznam - nemá konec - taky nemusíme ošetřovat zvláštní případy p:=Zac; Zac^.x:=MAX; new(n); n^.x:=H; while p^.další^.x<n^.x do p:=p^.další; n^.další:=p^.další; p^.další:=n; 30 prioritní fronta - má cenu až od víc než pár kategorií (tam stačí víc front) samoorganizující se seznam - když hledám, tak si to dám na začátek - když ho budu hledat znova, tak to bude rychlejší spojové seznamy - obezřetně obejití nemožnosti udělat pole s proměnlivým počtem prvků type TPole=array[1..65535] of char; var A:^TPole; var i:integer; begin read(N); GetMem(A,N); for i:=1 to 100 do A^[i]:=1 end. nemáme žádnou kontrolu přetečení indexů SizeOf(typ) - velikost integeru GetMem - zaalokuje určitý počet bytů FreeMem - Dlouhá čísla vlastní reprezentace čísel nezáporná x i záporná znaménko x doplňkový kód celá x desetinná v plovoucí čárce x v pevné čárce jaké (kolik) budou prvky/části čísla pole x spojový seznam které operace úloha: spočtěte číslo e na 1000 desetinných míst e= ∞ P 1 i! i=0 nezáporná, desetinná, pevná, pole potřebuju 4 místa navíc 31 i ≥ 10 ⇒ i! ≥ 10(i − 1)! nebudeme sčítat víc než 1000 členů - chyba vlastně jen 3 místa 1 1 = (i −i 1)! i! operace +, /integerem, test<>0, dosazení jedničky const MAX:=1010; type TCislo=array[0..MAX] of 0..9; Procedure Dosaď1(var Kam:TCislo); var i:integer; begin Kam[0]:=1; for i:=1 to MAX do Kam[i]:=0 end; Procedure Přičti(const Co:TCislo,var Kam:TCislo); var i,p,x:integer; begin p:=0; for i:=MAX downto 0 do begin x:=Co[i]+Kam[i]+p; Kam[i]:=x mod 10; p:=x div 10; end; if p<>0 then chyba end; Procedure Vydel(var Co:TCislo,čím:integer); var i,z:integer; begin z:=0; for i:=0 to MAX do begin z:=10*z+Co[i]; Co[i]:=z div čím; z:=z mod čím end end; var Součet, Prvek:TCislo; i:integer; begin Dosaď1(prvek); Součet:=Prvek; {1/0!} while while PNC<=MAX do begin Přičti(Prvek,Součet); Inc(i); vyděl(Prvek,i); end; write(Součet([0],’,’); for i:=1 to 1000 do write(Součet[i]); end. 32 v některých jazycích - assert - vyhlásí běhovou chybu pokud je podmínka false (při finálním překladu to u nich to jde vyházet) - jednoduchá kontrola - můžeme si jí udělat sami vylepšování Vydel: Procedure Vydel(var Co:TCislo,čím:integer); var i,z:integer; begin z:=0; while (PNC<=Max) and(Co[PNC]=0) do inc(PNC); for i:=PNC to MAX do begin z:=10*z+Co[i]; Co[i]:=z div čím; z:=z mod čím end end; PNC (PrvníNenulováČíslice) je globální - musíme jí inicializovat odečítání: převod doplňkového kodu: -256 odečítat -> 743+1 = 744 a tohle číslo sčítám s tím od kterého chci násobení: jako normálně, akorát ty sčítance jde přičítat rovnou k výsledku 060105 Třídění Třídění pole - vnitřní třídění Třídění pásek - vnější třídění Třídění přímým výběrem složitost: počet porovnání - O(N 2) počet přesunů - O(N 2) Třídění přímým vkládáním porovnání - O(N 2) přesuny - O(N 2) Třídění binárním vkládáním porovnání - O(N log N ) přesuny 33 Bublinkové třídění Třídění přetřásáním bublinkové třídění akorát se střídá třídění zprava a zleva Halda procedure VytvořHaldu(L,R:integer); var i,j:integer; x:hodnota; begin i:=L;x:=A[i];j:=2*i; while j<=R do begin if j+1<=R then if A[j+1]<A[j] then if x<=A[j] then break; A[i]:=A[j]; i:=j;j:=2*i; end; A[i]:=x; end; L:=N div 2+1; while L>1 do begin Dec(L); Vytvoř Haldu(L,N) end Shellovo třídění pole se rozdělí s určitým kroken na několik částí a ty se setřídí zvášť Složitost úlohy složitost nejlepšího algoritmu, který tuto úlohu řeší >= , ale i <= Teorém 6. Složitost úlohy vnitřního třídění založeného na porovnávání dvou prvků je rovna N log N historie výpočtu 060112 Přihrádkové třídění (RADIX-sort) a1, , an ∈ H; H = {p(1), , p(m)} 34 1. krok - vynulování pole 2. krok for i:=1 to n do inc(P[A[i]]); 3. krok - výpis hodnot for i:=1 to m do for j:=1 to P[i] do write(i); složitost - m + n + (m + n) - O(n + m) nemusíme ukládat do pole, ale může to být reprezentováno ukazately na ta čísla modifikace - řazení po skupinkách hodnot odzadu (pokud jsou stejné hodnoty, musím zachovávat √ pořadí) - složitost je k(n + k m ) kde k je počet rozdělení čísla příkaz case case výrazOrdinálníhoTypu of ’A’ c:=’B’; ’x’ halt(1); ’?’ writeln(’Help’); end; provede se jen jedna větev, a tím to končí; v turbopascalu může být podmínkou i interval a může tam být else typ množina type SoC = set of char; typ musí mít nejvýše 255 hodnot (musí být v intervalu 0..255) - to výrazně omezuje použitelnost tohoto typu operace s množinami: + sjednocení - rozdíl * průnik = rovno <> nerovno <= podmnožina >= nadmnožina in je prvek const Pismena= [’a’..’z’,’A’..’Z’]; 35 function NactiSlovo:string; var c:char; s:string; begin read(c); while not eof and not (c in Pismena) do read (c); s:=’’; while not eof and (c in Pismena) do begin s:=s+c; read(c) end; NactiSlovo:=s end begin while not eof do NactiSlovo end. modulární programování modul -rozhraní (intervace) - co dělá -implementace - jak to dělá v pascalu (v původním nic není)- unit - je dobré je pojmenovávat jménem začínajícím podtržítkem unit _A; interface ....... tady jsou konstanty, typy, procedury a funkce (jenom hlavičky) implementation ....... těla funkcí, procedur; pokud není uvedeno v interface, tak to není vidět z venku begin ..... tady se napíše to, co se má provést ještě před spuštěním programu end. použití unity v programu: uses _A, _b,..... výsledek překládání unit - .tpu výhoda unit - nemusí se překládat všechno najednou - takže se zkrátí doba překladu - ostatní nemusí vidět zdrojový kód compile - přeloží pouze to, co mám v aktuálním oknu make - překládá to, co je potřeba - může být zdrojem chyb (např když počítač ztratí pojem o čase) build - překládá všechno 36 když unita nemá inicializační část, tak stačí napsat jen end. uses v unitě jde psát buď za interface nebo za implementation circular unit reference - chyba - řeší se to: dá se uses až do implementation - pokud to nejde, tak jde vytvořit třetí unitu - když nejde ani to, tak smůla smart linking - z unit se dává do výsledného kódu jen to co je potřeba primary file - zdroj chyb - překládá se tento soubor je dobré si vyrobit prográmek, který pouze testuje unitu také je dobré si udělat proceduru test, která pouze testuje tu unitu (tu proceduru je lepší napsat předem - a pak mám cíl ten, že mi projde test) pokud chceme použít identifikátor z uniti, můžeme napsat _A.TDlouhe (plný název) každý program používá unitu “system” - můžu napsat system.integer faktorová množina - ? A,B jsou ve stejné třídě (souvislost) - !sjednoť dvě třídy (A,B) polem reprezentuji stejné třídy ekvivalence postupně procházím seznam hran, a zjišťuji, jestli jsou oba vrcholy ve stejné komponeně, když ne, tak je sjednotím složitost - počet hran * počet vrcholů standartní unity system - standartní unita, kterou používají všechny programy crt graph dos turbo3 - pro kompatibilitu s verzí 3 graph3 - -||- overlay 37 proměnná DirectVideo ( standartně false), jakmile se použije crt, tak se změní na true - sice rychlejší výstup, ale nepíše se na standartní výstup proměnná Mem zpřístupňuje paměť sound, delay, NoSound, keypressed, readkey, random, randomize random - náhodná čísla jsou pokaždé stejná - je to dobře pro ladění random seed - pole náhodných čísel aby se bylo možné na stejná data dívat různým způsobem: var a integer absolute a; namapování obrazovky: var c:array [1..,1..] of char record znak:char; attr:byte end absolute type TFunkceJedneProměnné= function(x:real):real; function JeVNuleRovnaJedne(f:TFunkceJedneProměnné):boolean begin JeVnuleRovnaJedne:=f(0)=1; end; function Ctverec(x:real):real; begin Ctverec:=x*x end; function XPlusJedna(x:real):real; begin XPlusJedna:=x+1; end; begin writeln(JeVNuleRovnaJedne(Ctverec)); writeln(JeVnuleRovnaJedne(XPlusJedna)); end; musí být vynucena vzdálená volání 38 pomocí tohe lze taky obsluhovat chyby v unitách: type TChybovaProcedura=procedure(s:string); var cy 39
Podobné dokumenty
Dokumentace správce
Nainstalujte prosím balíček (ev. sadu balíčků) serveru MySQL určený pro Vaši distribuci linuxu. Tyto balíčky
najdete pravděpodobně na stránkách Vaší distribuce či na stránkách MySQL http://www.mysq...
Základy algoritmizace
Toto skriptum je určeno posluchačům prvnı́ho ročnı́ku FJFI ČVUT se softwarovým zaměřenı́m. Navazuje na
přednášku Základy algoritmizace.
Algoritmy jsou nerozlučně spjaty s datovými st...
Ročníkový projekt DYNAMICKÉ HTML Programátorská
parsován, nebo na konci vstupního souboru. Základním stavem je stav 0, který značí že parser nezpracovává žádný tag. Pokud parser v tomto stavu nalezne na vstupu znak ¡, přesouvá se do stavu 1, a
z...
Jiná verze vypracování, od kolegy z PZA
4.6 blokové schéma operačního systému vzhledem k ovladačům
Depeche Mode Friends
oblíbené. Už si nejsem příliš jistý, ale bylo tam něco od Presleyho, Leonarda Cohena,
ABBA. Záleží na tvé náladě ? Jaké jsi mě dojmy z vystoupení v Moskvě ?
Písně, které zpívám v barovém hotelu jso...