Demo 10 / 22.11
Tehtävät
V1.
Tee
Ville-tehtävät: 8.1, 8.2, 8.3, 9.7, 9.9
1.
M: 19. Rekursio: Katso mallia rekursiivisesta
kolmion piirtämisestä. Valitse neljästä vaihtoehdosta se, jonka parhaiten ymmärrät (käytännössä
Kolmiot.java -malli riittää kunhan ei piirretä alle pikselin kokoisia oksia). Tee mallia muokaten ohjelma, joka piirtää
puu.png -kuvan kaltaisen puun rekursiosta:
/**
* Puun yksi oksa ja kolme muuta rekursiivisesti
* @param x oksan alkupiste
* @param y oksan alkupiste
* @param d oksan suunta radiaaneina
* @param l oksan pituus
*/
oksa( x, y, d, l)
viiva pisteestä (x,y) pisteeseen (x+l*cos(d),y+l*sin(d))
jos l < 2 lopeta
oksa(x+l*cos(d),y+l*sin(d),d+0.6,l*0.6);
oksa(x+l*cos(d),y+l*sin(d),d-0.6,l*0.6);
oksa(x+l*cos(d),y+l*sin(d),d,l*0.3);
Ikkuna kannattaa aluksi skaalat niin, että origo on vasemmalla alhaalla. Hyvä alkukulma piirtämiseen on vaikkapa pi/2. ja pituus vajaa puolet ikkunan korkeudesta. Kokeile vaihdella suuntaa ja oksan pituutta muuttavia vakioita ja katso miten ne vaikuttavat kuvaan.
public static void main(String[] args) {
List<Integer> pallot = new ArrayList<Integer>();
// täytä pallot numeroilla 1-39, esim: pallot.add(4);
// sotke pallot (ks. Collections)
// tulosta 7 ekaa "palloa"
// tulosta 3 seuraavaa palloa
}
3.
M: 15. Toistorakenteet: Erilaisten 7 numeroa sisältävien lottorivien määrä saadaan binomikertoimen kaavasta:
Katso: http://fi.wikipedia.org/wiki/Kombinaatio
kaava 1 kaava 2 kaava 3
39 39! 33*34*35*36*37*38*39
( ) = -------------- = ---------------------- = 15380937
7 7! * (39-7)! 1*2*3*4*5*6*7
Tulos voidaan laskea käyttämällä long -tyyppisiä lukuja. Tee funktio
long nYliK(int n,int k)
jonka kutsulla nYliK(39,7) saat mainitun tuloksen. Tulosta ei voi laskea keskimmäisestä kaavasta 2, koska 39! ylittäisi reilusti pitkienkin (long) kokonaislukujen lukualueen.
Vinkki: Tässä tehtävässä ei tarvita listoja tms., pelkästään kerto- ja jakolaskuja sekä silmukoita. Vastaus on nätimpi jos avuksi kirjoittaa yhden pienen aliohjelman.
http://www1.nordea.fi/s/merita/kurssit/val-tilival_eur.asp
ja katso sen lähdekoodia (Firefoxissa Ctrl-U). Tee pääohjelma ja tarvittavat aliohjelmat tyyliin:
lista = Tiedosto.lueListaan(osoite);
valuuttalista = etsiVainValuutat(lista); // ottaa <pre> </pre> välin
while ( true) {
valuutta = kysy käyttäjältä valuutan nimi
if ( valuutta == "" ) break;
tulostaValuutta(valuuttalista,valuutta); // etsii ja tulostaa
}
6.
M: 23. Poikkeukset: Kirjoita
Double.parseDouble ja poikkeuksia käyttäen funktio
muutaJono(String s,double oletus) jota voidaan käyttää seuraavasti:
public static void main(String args[]) {
double d1 = muutaJono("12.3",0.0);
double d2 = muutaJono("12.3e",0.0);
System.out.printf("%5.2f %5.2f",d1,d2); // 12.30 0.00
}
7.
Katso edellisen demon kuvankäsittelytehtävän vastausta. Tee siihen lisäksi metodi
mediaanisuodatin(int[][] kuva,int n), joka toimii niin, että kulkee kuten konvoluttio koko kuvamatriisin läpi, mutta kunkin pikselin kohdalla ottaa nxn-alueen (n pariton) pisteet yksiulotteiseen taulukkoon ja ottaa sen mediaanin (=keskimmäinen alkio) uuden kuvan vastaavan pikselin arvoksi. Yksiulotteisen taulukon voit lajitella
Arrays.sort(taulukko). Mediaanisuodatin on mielekäs oikeastaan vain harmaasävykuvalle. Värikuvalle se pitäisi tehdä
eritavalla, joten saat tehdä tehtävän olettaen että käsiteltävänä on harmaasävykuva tai ainakin tuottaa tulokseksi harmaasävykuvan. Missä tilanteessa mediaanisuodatin on parempi kuin keskiarvoistava konvoluutio?
B1.
Tutki miten Javassa toimii
BigInteger -luokka ja tee
nYliK(int n,int k) sen avulla. Tee siis tehtävää 3 vastaava toteutus erityyppisellä kokonaisluvulla.
B2.
M: 20. Dynaamiset tietorakenteet: Jopa kaavalla (3)
long -lukualue voi ylittyä jaettavassa, jos käsitellään paljon isompia lukujoukkoja kuin 39 (nyt raja on 515). Tällöin yksi mahdollisuus on ennen laskuja sieventää mahdollisimman paljon jaettavaa ja jakajaa. Sievennä ensin käsin mahdollisimman paljon kaavan 3 laskua. Mieti mitä teit.
Maara.java -tiedostossa on valmiita aliohjelmien esittelyjä ja testejä avuksi siihen, miten laskua voisi tehdä, jos jaettava ja jakaja pidettäisiin kumpikin listana kertoimista. Toteuta metodit
tayta,
kerro, ja
poista. Metodien pitää toimia kuten kommenteissa olevissa testeissä on kuvattu. Koska supistaminen/sieventäminen ei yksittäisten alkioiden kohdalta ole yksikäsitteistä, testeihin saa halutessaan tehdä seuraavanlaisia muutoksia:
Testien jotka ovat tyyliin:
jaettava.toString() === "[2, 3, 2, 5, 3, 7]";
tilalle saa supistus/sievennys metodeissa laittaa testin,
joka tutkii, että osamäärän tekijä on oleellisesti sama, eli
kerro(jaettava) === 2*3*2*5*3*7;
Pyri ajamaan ComTest -testit ja varmistu sillä tavalla, että aliohjelmasi toimivat oikein.
Vinkki: ConcurrentModificationException tarkoittaa että iterointi (listan alkioiden läpikäynti) silmukalla for (int alkio:lista) on johtanut ristiriitaan sen kanssa, että listaa on muutettu kesken iteroinnin (läpikäynnin). Tällöin pitää valita toisenlainen tapa listan läpikäyntiin. Kannattaa piirtää kuva itselle siitä, mitä alkion poistaminen taulukkomaisesta listasta aiheuttaa.
int supista(List<Integer> jaettava, List<Integer> jakaja, int supistaja)
totuttamaan kommenteissa kuvatut vaatimukset. Näin voit laskea maksimissaan
nYliK(1733,7) = 9202167919706100768L
GURU-tehtävät
G1.
Mieti miten
nYliK(int n,int k) ( kirjoitetaan jatkossa
C(n,k) ) voidaan lausua rekursiivisesti, eli:
C(n+1,k) = C(n,k) * f(n,k) // mieti millainen on f(n,k):n lauseke.
C(k,k) = 1
Kirjoita sitten tämän avulla iteratiivinen (silmukkaan, ei rekursioon) perustuva ratkaisu, jossa kertolaskut eivät ”helposti” ylitä lukualueen rajaa. Tällä algoritmilla päästään tuloksiin, jotka ovat < Long.MAX_VALUE/n. Kaavan 3 versiolla päästiin tuloksiin< Long.MAX_VALUE/(k!).
G2.
Toteuta ja testaa
Maara.java -luokkaan metodit:
public static int sievenna(List<Integer> jaettava, List<Integer> jakaja)
public static int supista(List<Integer> jaettava, List<Integer> jakaja)