Integer Real

Transkript

Integer Real
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

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...

Více

Základy algoritmizace

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...

Více

Ročníkový projekt DYNAMICKÉ HTML Programátorská

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...

Více

Jiná verze vypracování, od kolegy z PZA

Jiná verze vypracování, od kolegy z PZA 4.6 blokové schéma operačního systému vzhledem k ovladačům

Více

Depeche Mode Friends

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...

Více