* totuustaulut
* pöytätesti
* muuttujat
* taulukot
* osoittimet Vaikka jatkossa keskitymmekin oliopohjaiseen ohjelmointiin, tarvitaan yksittäisen olion metodin toteutuksessa algoritmeja. Riippumatta käytettävästä ohjelmointikielestä, tarvitaan algoritmeissa aina tiettyjä samantyyppisiä rakenteita.
Käsittelemme seuraavassa tyypilliset rakenteet nopeasti lävitse. Tarvitsisimme asioille enemmänkin aikaa, mutta otamme asiat tarkemmin esille käyttämämme ohjelmointikielen opiskelun yhteydessä. Lukijan on kuitenkin asioita tarkennettaessa syytä muistaa, ettei rakenteet ole mitenkään sidottu ohjelmointikieleen. Vaikka ne näyttäisivät kielestä täysin puuttuvankin (esim. assembler), voidaan ne kuitenkin lähes aina toteuttaa.
Jos kello yli puolenyön ota taksi muuten mene linja- autollaEhtolauseita voi ehtoon tulla useampiakin ja tällöin on syytä olla tarkkana sen kanssa, mihin ehtoon mahdollinen muuten- osa liittyy:
Jos kello 00.00- 07.00 Jos sinulla on rahaa niin ota taksi muuten kävele muuten mene linja- autolla
Auto on/oli rekisterinumeron 1. kirjaimen mukaan rekisteröity seuraavassa läänissä: X Keski- Suomen lääni K Kuopion lääni M Mikkelin lääni A,U Uudenmaan lääni
Silmukoihin liittyy aina ohjelmoinnin eräs klassisimmista vaaroista: päättymätön silmukka! Tämän takia silmukoita tulee käsitellä todella huolella. Eräs oleellinen asia on aina muistaa suorittaa silmukan rungossa jokin silmukan lopetusehtoon vaikuttava toimenpide. Mitä tapahtuu muuten?
Myös silmukan suorituskertojen lukumäärän kanssa tulee olla tarkkana. Silmukka tulee helposti suoritettua yhden kerran liikaa tai yhden kerran liian vähän.
kellonaika rahan määrä
Yksinkertainen luvun jaollisuuden testausalgoritmi voisi olla vaikkapa seuraavanlainen:
Jaetaan tutkittavaa lukua jakajilla 2,3,5,7...luku/2. Jos jokin jako menee tasan, niin ei alkuluku: 0. Laita jakaja:=2, kasvatus:=1, Jos luku=2 lopeta, alkuluku 1. Jaa luku jakajalla. Meneekö jako tasan? - jos menee, on luku jaollinen jakajalla, lopeta 2. Kasvata jakajaa kasvatus arvolla (jakaja:=jakaja+kasvatus) 3. Kasvatus:=2; (koska parillisilla ei kannata enää jakaa) 4. Onko jakaja<luku/2? - jos on, niin jatka kohdasta 1 - muuten lopeta, luku on alkuluku
Testataan esimerkiksi edellisen esimerkin algoritmi:
askel
|
Luku
|
Jakaja
|
Kasvatus
|
Luku/Jakaja
|
Jako
tasan?
|
Jakaja<Luku/2?
|
Tulostus
|
0
|
25
|
2
|
1
|
||||
1
|
12.500
|
ei
|
|||||
2
|
3
|
||||||
3
|
2
|
||||||
4
|
3<12.5
|
||||||
1
|
8.333
|
ei
|
|||||
2
|
5
|
||||||
3
|
2
|
||||||
4
|
5<12.5
|
||||||
1
|
5.000
|
kyllä
|
Jaollinen
5:llä
|
askel
|
Luku
|
Jakaja
|
Kasvatus
|
Luku/Jakaja
|
Jako
tasan?
|
Jakaja<Luku/2?
|
Tulostus
|
0
|
23
|
2
|
1
|
||||
1
|
11.500
|
ei
|
|||||
2
|
3
|
||||||
3
|
2
|
||||||
4
|
3<11.5
|
||||||
1
|
7.667
|
ei
|
|||||
2
|
5
|
||||||
3
|
2
|
||||||
4
|
5<11.5
|
||||||
1
|
4.600
|
ei
|
|||||
2
|
7
|
||||||
3
|
2
|
||||||
4
|
7<11.5
|
||||||
1
|
3.286
|
ei
|
|||||
2
|
9
|
||||||
3
|
2
|
||||||
4
|
9<11.5
|
||||||
1
|
2.556
|
ei
|
|||||
2
|
11
|
||||||
3
|
2
|
||||||
4
|
11<11.5
|
||||||
1
|
2.091
|
ei
|
|||||
2
|
13
|
||||||
3
|
2
|
||||||
4
|
|
|
13>11.5
|
Alkuluku
|
Tarvitsemme siis jonkin muun tietorakenteen. Mahdollisuuksia on useita: listat, jonot, pinot ja taulukot. Ohjelmoinnin alkuvaiheessa taulukot ovat tietorakenteista helpoimpia, joten keskitymme niihin aluksi.
Varataan pöydältä tilaa leveyssuunnassa 13 kortille. Varattua tilaa voimme nimittää taulukoksi tai vektoriksi. Taulukon yksi alkio on yhdelle kortille varattu paikka. Taulukon yhden alkion sisältö on se kortti, joka on siinä paikassa.
Mikäli numeroimme varatut paikat vaikkapa 0:sta alkaen vasemmalta oikealle, on meidän korteillamme osoitteet 0- 12:
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
7
|
3
|
K
|
2
|
5
|
9
|
4
|
6
|
Q
|
10
|
J
|
A
|
8
|
paikassa kortit[5] meillä on pata 9 paikassa kortit[8] meillä on pata akkaMinkälaisia algoritmeja tulee vastaan taulukoita käsiteltäessä? Esim 9:n siirtäminen taulukon viimeiseksi vaatisi 4:en siirtämistä paikkaan 5. 6:en siirtämistä paikkaan 6, Q:n siirtämistä paikkaan 7 jne. Näin loppuun saataisiin raivatuksi paikka 9:lle.
Lajittelun ilman valtaisaa korttien siirtelyä voisimme hoitaa seuraavasti:
0. laita alku paikkaan 0 1. etsi alku paikasta lähtien pienin kortti 2. vaihda pienin ja paikassa alku oleva kortti 3. alku:=alku+1 4. mikäli alku<suurin indeksi, niin jatka 1Sovitaan, että ässä=1. Nyt pienimmän kortin etsimisalgoritmi voisi olla seuraava:
0. Alkuarvaus: pien.paikka:=alku, tutki:=alku 1. Jos kortit[tutki] < kortit[pien.paikka] niin pien.paikka:=tutki 2. tutki:=tutki+1 3. Jos tutki<=suurin indeksi, niin jatka 1.Voisimme vielä pöytätestata algoritmin:
pien. |
Kortit |
[tutki]< |
tutki< | ||||||||||||||
askel |
paikka |
tutki |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
[pp] |
suur.ind |
0 |
0 |
0 |
7 |
3 |
K |
2 |
5 |
9 |
4 |
6 |
Q |
10 |
J |
A |
8 |
||
1 |
t |
7<7 ei |
|||||||||||||||
2&3 |
1 |
juu | |||||||||||||||
1 |
1 |
t |
3<7 juu |
||||||||||||||
2&3 |
2 |
juu | |||||||||||||||
1 |
t |
K<3 ei |
|||||||||||||||
2&3 |
3 |
juu | |||||||||||||||
1 |
3 |
t |
2<3 juu |
||||||||||||||
2&3 |
4 |
juu | |||||||||||||||
1 |
t |
5<2 ei |
|||||||||||||||
2&3 |
5 |
juu | |||||||||||||||
1 |
t |
9<2 ei |
|||||||||||||||
2&3 |
6 |
juu | |||||||||||||||
1 |
t |
4<2 ei |
|||||||||||||||
2&3 |
7 |
juu | |||||||||||||||
1 |
t |
6<2 ei |
|||||||||||||||
2&3 |
8 |
juu | |||||||||||||||
1 |
t |
Q<2 ei |
|||||||||||||||
2&3 |
9 |
juu | |||||||||||||||
1 |
t |
10<2 ei |
|||||||||||||||
2&3 |
10 |
juu | |||||||||||||||
1 |
t |
J<2 ei |
|||||||||||||||
2&3 |
11 |
juu | |||||||||||||||
1 |
11 |
t |
A<2 juu |
||||||||||||||
2&3 |
12 |
juu | |||||||||||||||
1 |
t |
8<A ei |
|||||||||||||||
2&3 |
13 |
ei |
Lajittelualgoritmi voitaisiin lausua esimerkiksi:
0. levitä kortit rinnakkain pöydälle osoita vasemman käden etusormella ensimmäiseen korttiin 1. etsi vasemman käden osoittamasta kohdasta alkaen oikealle pienin kortti ja osoita sitä oikean käden etusormella 2. vaihda etusormien kohdalla olevat kortit keskenään 3. siirrä vasemman käden etusormea yksi kortti oikealle päin 4. mikäli vasen sormi vielä kortin päällä, jatka kohdasta 1.
7
|
3
|
K
|
2
|
5
|
9
|
4
|
6
|
Q
|
10
|
J
|
A
|
8
|
Osoitin voi tarvittaessa osoittaa myös itse taulukon ulkopuolelle. Mikäli kirjoittaisimme pöydälle numeroita, voisimme osoittaa sormella yhtä hyvin pöydälle kirjoitettuja numeroita (älkää hyvät ihmiset nyt töhrätkö pöytää!) kuin pöydälle levitettyjä kortteja (taulukon alkioita).
Siis indeksit liittyvät kiinteästi taulukoihin ja osoittimet voivat liittyä mihin tahansa tietorakenteisiin alkaen yksinkertaisesta muuttujasta päätyen monimutkaisen lista- tai puurakenteen alkioon.
Alla on esimerkki 5x7 taulukosta (=pata, =Risti, =ruutu, =hertta):
0
|
1
|
2
|
3
|
4
|
5
|
6
| |
0
|
|||||||
7
|
A
|
||||||
1
|
|||||||
K
|
5
|
||||||
2
|
|||||||
A
|
|||||||
3
|
|||||||
7
|
2
|
2
|
9
|
6
|
3
|
7
| |
4
|
|||||||
2
|
J
|
peli[3][1] = 2
Usein taulukoiden indeksit ilmoitetaan eri järjestyksessä kuin koordinaatiston (x,y)- koordinaatit. Tämä johtuu siitä ajattelutavasta, että taulukon rivi sinänsä voidaan kuvitella yhdeksi alkioksi (rivityypiksi) ja tällöin ilmaisu
peli[3]tarkoittaa koko riviä (7, 2, 2, 9, 6, 3, 7), jonka indeksi on kolme. Mikäli tämän perään laitetaan vielä [1], niin tarkoitetaan ko. tietorakenteen alkiota jonka indeksi on yksi (2).
Tarvittaessa moniulotteiset taulukot voidaan muodostaa yksiulotteisenkin taulukon avulla. Esimerkin taulukko voitaisiin muodostaa yksiulotteisesta taulukosta siten, että yksiulotteisen taulukon 7 ensimmäistä alkiota kuvaisivat matriisin 0:ta riviä, 7 seuraavaa matriisin ensimmäistä riviä jne.
Siis mikäli yksiulotteisen taulukon nimi olisi pakka, niin voisimme käyttää samaistuksia:
peli[3][1] = pakka[7*3+1] peli[j][i] = pakka[7*j+i]Olemme siis numeroineet kaksiulotteisen taulukon alkiot juoksevasti. Voimmehan tehdä näin myös kerrostalon huoneistoille tai teatterin istumapaikoille.
Taulukot voivat olla myös useampiulotteisia, esimerkiksi 3x4x5 taulukko:
0 1 2 3 4 +--+ +--+ +--+ +--+ +--+2 0 | +--+ | +--+ | +--+ | +--+ | +--+1 +-| +--+ +-| +--+ +-| +--+ +-| +--++-| +--+0 +-| | +-|PJ| +-| | +-| | +-| | +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ 1 | +--+ | +--+ |R5--+ | +--+ | +--+ +-| +--+ +-| +--+ +-| +--+ +-|HA--+ +-| +--+ +-| | +-| | +-| | +-| | +-| | +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ 2 | +--+ | +--+ | +--+ | +--+ | +--+ +-| +--+ +-| +--+ +-| +--+ +-| +--+ +-| +--+ +-| | +-| | +-| | +-| | +-| | +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ 3 |P7--+ | +--+ | +--+ | +--+ | +--+ +-| +--+ +-| +--+ +-| +--+ +-| +--+ +-| +--+ +-| | +-| | +-| | +-| | +-| | +--+ +--+ +--+ +--+ +--+
isopeli[0][0][1]=PJ isopeli[2][1][2]=R5 isopeli[1][1][3]=HA isopeli[2][3][0]=P7
0 1 2 0 minä jag i 1 sinä du you 2 hän han heSe on kaksiulotteinen taulukko sanoista. Mitä sitten yksi sana on? Se on yksiulotteinen taulukko kirjaimista!
0 1 2 3 4 +--+ +--+ +--+ +--+ +--+2 0 |h+--+ |ä+--+ |n+--+ | +--+ | +--+1 +-|s+--+ +-|i+--+ +-|n+--+ +-|ä+--++-| +--+0 +-|m | +-|i | +-|n | +-|ä | +-| | +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+2 1 |h+--+ |a+--+ |n+--+ | +--+ | +--+1 +-|d+--+ +-|u+--+ +-| +--+ +-| +--++-| +--+0 +-|j | +-|a | +-|g | +-| | +-| | +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+2 2 |h+--+ |e+--+ | +--+ | +--+ | +--+1 +-|y+--+ +-|o+--+ +-|u+--+ +-| +--++-| +--+0 +-|i | +-| | +-| | +-| | +-| | +--+ +--+ +--+ +--+ +--+Siis "you" sanan indeksi on [1][2] ja sen kirjaimen "y" indeksi on [0]. Siis kaiken kaikkiaan "you"- sanan "y"- kirjaimen indeksi olisi [1][2][0].
Taulukko voitaisiin järjestää 3- ulotteiseksi myös toisinkin. Esimerkiksi yhdessä "tasossa" olisi yksi kieli jne.
Osoitinmuuttuja osoittaisi myös moniulotteisessa taulukossa yhteen alkioon kerrallaan. Esimerkiksi osoittamalla "you"- sanan "y"- kirjaimeen.
Moniulotteisen ja yksiulotteisen taulukon väliset muunnokset ovat tärkeitä, koska tietokoneen muisti (1997) on lähes aina yksiulotteinen. Siis loogisesti moniulotteiset taulukot joudutaan lopulta aina toteuttamaan yksiulotteisina. Onneksi useat kielet sisältävät moniulotteiset taulukot tietotyyppinä ja kääntäjät tekevät sitten muunnoksen. Tästä huolimatta esimerkiksi C- kielessä joudutaan usein muuttamaan moniulotteisia taulukoita yksiulotteisiksi.
0 1 2 3 0123456789012345678901234567890123 minä jag i sinä du you hän han heItse sanasto voisi sitten olla taulukko osoittimia sanojen alkupaikkoihin:
0
|
1
|
2
| |
0
|
00
|
05
|
09
|
1
|
11
|
16
|
19
|
2
|
23
|
27
|
31
|
// C++:lla char *sanasto[3][3];
sivu 0: |
sivu 1: |
sivu 2: | ||
Kassinen Katto Katto 3452 |
Susi Sepe |
Ankka Aku Ankkalinna 1234 |
sivu 1: |
Batman Gotham City 999 |
// C++:lla sivu[1] = uusi_osoite; // ei vaikuta Sepe Suteen *sivu[1] = uusi_henkilo; // laittaa uuden henkilön Sepen osoitteeseen // = "tähdätään osoitetta pitkin"Vastaavasti jos meillä on indeksimuuttuja nimeltä sivu, niin sijoitus muuttujalle
sivu=2ei muuta mitenkään itse sivun sisältöä. Vasta sijoitus
osoitteet[sivu]=muuttaisi sivun 2 sisältöä.
Keittokirjassa lukee:
pyöritä lihapullataikinasta pyöreitä pullia paista pullat kauniin ruskeiksiMiten pullat paistetaan kauniin ruskeiksi. Tämä olisi edellisen algoritmin aliohjelma. Kokenut kokki ei välitä aina (eikä edes suostuisi) joka reseptin kanssa lukea itse paistamisohjetta. Aloittelija tätä saattaisi tarvita, jottei naapuri hälyttäisi palokuntaa paikalle liian savunmuodostuksen takia. Siis toivottavasti keittokirjasta jostakin kohti löytyisi myös itse paistamisohje.
Aliohjelmille on tyypillistä, että ne saattavat suoriutua vastaavista tehtävistä eri muuttujillekin. Näitä kutsukerroista riippuvia muuttujia sanotaan parametreiksi.
Esim. lihapullan paisto- ohje saattaa semmoisenaan kelvata myös tavalliselle pullalle:
paista("paistettava","c") Korvaa seuraavassa sana "paistettava" sillä mitä olet paistamassa ja "c" sillä lämpötilalla, joka keittokirjan ohjeessa ko. paistettavan kohdalla on: 0. laita "paistettavat" pellille 1. lämmitä uuni "c"- asteeseen 2. laita pelti uuniin ... 9. mikäli "paistettavat" ovat mustia mene ostamaan kaupasta valmiita ...
Tutkikaamme aluksi muutamaa esimerkkiä jotka eivät suoranaisesti liity ohjelmointiin, mutta joissa esiintyy täsmälleen vastaava tilanne:
Tehtävä 3.4: Seisot tienhaarassa tuntemattomassa maassa. Toinen teistä vie pääkaupunkiin. Maan asukkaat joko valehtelevat aina tai puhuvat aina totta. Toisen tien alussa seisoskelee yksi heistä. Esität hänelle kyllä vai ei - kysymyksen ja saat vastauksen. Mitä kahta seuraavista neljästä kysymyksestä olisit voinut käyttää ollaksesi varma siitä, kumpi tie vie pääkaupunkiin - riippumatta siitä valehteleeko asukas vai ei?
B Puhutko totta? (mielenkiinnon vuoksi)
2 = C Olisitko sanonut että vie jos A?
3 <- D Tie pääk. XOR puhut totta?
4 <- E Tie pääk. AND puhut totta?
Nyt voimme kirjoittaa eri vaihtoehtojen mukaan seuraavan totuustaulun (V=vastaus kun valehteleminen otetaan huomioon):
Tie vie pää- |
Puhuu |
1 |
2 |
3 |
|
4 |
||||
kaupunkiin |
totta |
A |
B |
C |
D |
V |
E |
V | ||
E |
E |
K |
K |
E |
E |
K |
E |
K | ||
E |
K |
E |
K |
E |
K |
K |
E |
E | ||
K |
E |
E |
K |
K |
K |
E |
E |
K | ||
K |
K |
K |
K |
K |
E |
E |
K |
K |
00 - > E E 01 - > E K 10 - > K E 11 - > K K
Tehtävä 4.3: Pekka valehtelee maanantaisin, tiistaisin ja keskiviikkoisin; muina viikonpäivinä hän puhuu totta. Paavo valehtelee torstaisin, perjantaisin ja lauantaisin; muina viikonpäivinä hän puhuu totta. Eräänä päivänä Pekka sanoi: "Eilen valehtelin!" Paavo vastasi: "Niin minäkin!" Mikä viikonpäivä oli? Minä päivinä kaverukset saattaisivat sanoa ko. lausuman? Näitä päiviä on tietysti ne, jolloin joko eilen valehdeltiin ja tänään puhutaan totta TAI eilen puhuttiin totta ja tänään valehdellaan. (XOR)
|
Pekka |
valehteli eilen |
Paavo |
valehteli |
|
sunnuntai |
k sanoo |
||||
maanantai |
V |
sanoo |
|
||
tiistai |
V |
k |
|||
keskiviikko |
V |
k |
|||
torstai |
k sanoo |
V |
sanoo |
<== | |
perjantai |
V |
k |
|||
lauantai |
V |
k |
|||
sunnuntai |
k sanoo |
Mikäli kello 7- 20 ja et halua ulkoilla - mene bussilla ... Mikäli sinulla on rahaa tai saat kimpan - ota taksiYksittäinen ehto antaa tulokseksi tosi (T=true) tai epätosi (F=false). Ehtojen tulosta voidaan usein myös kuvata 1 tai 0. Ehtojen yhdistämistä loogisilla operaatioilla kuvaa seuraava totuustaulu (myös C++:n loogiset operaattorit merkitty):
ja |
tai |
ehd. tai |
ei |
|||||||||||||||
AND |
OR |
XOR |
NOT |
|||||||||||||||
p |
q |
|
p |
&& |
q |
p |
|| |
q |
p |
^ |
q |
! |
p |
^ toimii jos p ja q boolean | ||||
F |
0 |
F |
0 |
F |
0 |
F |
0 |
F |
0 |
T |
1 |
|||||||
F |
0 |
T |
1 |
F |
0 |
T |
1 |
T |
1 |
T |
1 |
|||||||
T |
1 |
F |
0 |
F |
0 |
T |
1 |
T |
1 |
F |
0 |
|||||||
T |
1 |
T |
1 |
T |
1 |
T |
1 |
F |
0 |
F |
0 |
Ehtojen sieventämisessä käytettäviä kaavoja voidaan todistaa oikeaksi totuustaulujen avulla. Todistetaan esimerkiksi de Morganin kaava (vrt. joukko- oppi, 1=true, 0=false):
NOT (p AND q) = (NOT p) OR (NOT q) Jaetaan ensin väittämä pienempiin osiin: NOT e1 = e2 OR e3
e1 |
e2 |
e3 |
|||||
p |
q |
p AND q |
NOT p |
NOT q |
NOT e1 |
e2 OR e3 |
|
0 |
0 |
0 |
1 |
1 |
1 |
1 |
|
0 |
1 |
0 |
1 |
0 |
1 |
1 |
|
1 |
0 |
0 |
0 |
1 |
1 |
1 |
|
1 |
1 |
1 |
0 |
0 |
0 |
0 |
e1 |
e2 |
e3 |
||||||
p |
q |
r |
q AND r |
p OR q |
p OR r |
p OR e1 |
e2 AND e3 |
|
0 |
0 |
0 |
||||||
0 |
0 |
1 |
||||||
0 |
1 |
0 |
||||||
0 |
1 |
1 |
||||||
1 |
0 |
0 |
||||||
1 |
0 |
1 |
||||||
1 |
1 |
0 |
||||||
1 |
1 |
1 |
Taulukoiden samaistaminen ruutupaperiin, korttipakkaan tai muuhun tuttuun asiaan auttaa asian käsittelyä. Osoitinmuuttuja on yksinkertaisesti jokin (vaikkapa sormi) joka osoittaa johonkin (vaikkapa yhteen kirjaimeen).
Silmukat ja ehtolauseet ovat hyvin luonnollisia asioita.
Aliohjelmat ovat vain tietyn asian tarkempi kuvaus. Tarvittaessa tiettyä asiaa ei ongelmaa tarvitse heti ratkaista, vaan voidaan määritellä aliohjelma, joka hoitaa homman ja kirjoitetaan itse aliohjelman määrittely joskus myöhemmin.
0 |
1 |
2 |
3 |
4 |
5 |
|
K |
i |
s |
s |
a |
NUL |