TDDC30 Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 6 Jonas Lindgren, Institutionen för Datavetenskap, LiU På denna föreläsning: Omega, Theta Selectionsort, Shellsort, Quicksort Grafiskt användargränssnitt, Swing, Layout 1
Repetition, Ordo Definition: Givet två funktioner f(n) och g(n) Om det finns positiva konstanter c och n 0 sådana att f(n) cg(n) för n n 0 Då f(n) O(g(n)) (dvs. f(n) tillhör Ordo(g(n)) T Harry (n) = 5*n + 2 T Anna (n) = 8*log 2 (n) + 2 Antagande: g(n) = n 5n +2 cn (c-5)n 2 n 2 c 5 låt c = 6, n 0 =2 => 5n + 2 6n för n 2 => T Harry (n) O(n) Antagande: g(n) = n 8log 2 (n) + 2 cn 8 log c 2(n)) + 2 n c låt c = 8, n 0 =2 => 8log 2 (n) + 2 8n för n 2 =>T Anna (n) O(n) 2
Asymptotisk storlek spelar roll n 3n 3 19500000n 10... Vid tillräckligt stora probleminstanser Om en tidsenhet motsvarar 1 ns 100 1000 2 500 10 000 1 000 000 3 mikrosekunder 200 ms 3 ms 2s 3 s 22 s 50 s 51 s 49 min 3.2 min 95 år 5.4 tim Konstanter före spelare inte så stor roll O(n 3 ) O(n) Funktionens klass är det som dominerar asymptotiskt! 3
Ordoklasser Ordo Benämning O(1) Konstant O(log(n)) Logaritmisk O(n) Linjär O(nlog(n)) O(n 2 ) Kvadratisk O(n 3 ) Kubisk O(2 n ) Exponentiell O(n!) Faktoriell O(n x ) Polynomisk Effektivare algoritm Högre komplexitet 4
Räkneregler O(a(n) + b(n)) O( max(a(n), b(n)) ) Exempel: om vi skall räkna alla Smiths och fotografera dem. T foto (n) = 1, T räkna n = 2n, O T foto n + T räkna n O max T foto n, T räkna n O T räkna n O 2n O n => När antalet blir många så är det räknandet som kommer ta tid! Exempel 2: om vi skall låta alla på en konferens få en namnbricka och sedan skall alla skaka hand med alla. T dela ut brickor n = n, T skaka hand n = n(n 1) 2 = n2 n 2 O n + n2 n O n2 O n 2 2 2 2 => när antalet blir många så är det handskakningen som tar tid! 5
Räkneregler Konstant log a (n) = (1/log b (a)) * log b (n) Om vi byter mellan baser får vi bara en annan konstant D.v.s, basen spelar ingen roll Om f(x) O(log(n)) så f(x) O(n) välj den som beskriver algoritmen bäst Låt funktionen a O(g) och b O(h) Då gäller a*b O(gh) T.ex. om vi skall berätta namnet på alla på konferensen för varje person som får en namnbricka. => n*n O(n^2) 6
Omega och Theta Givet två funktioner f och g f tillhör Ω(g) om det finns två positiva konstanter c, n 0 sådana att f(n) cg(n) för n n 0 Ω(g) är en undre gräns för funktionen, jmf. O(g) Givet två funktioner f och g f tillhör Θ(g) om f tillhör Ω(g) och O(g) O Ordo Θ Theta Ω Omega 7
Enklare metod public static void algorithm(int[] numbers) { int tmp; for (int i = 1; i < numbers.length; ++i) { for (int j = numbers.length; j >= i; ++j) { if (numbers[i] < numbers[j]) { tmp = numbers[i]; 1 numbers[i] = numbers[j]; numbers[j] = tmp; } } } } T alg (n) O(n 2 ) n n 2 8
Indatas innehåll kan påverka Beror ej bara på indatas storlek, utan även innehållet Värstafallet Bästafallet Medelfallet Oftast analyseras värstafallet Ibland missvisande, kanske är statistiskt sällsynt fall Amorterad analys T.ex. analys av metoden push för en Lista implementerad med en array. (lägger till ett element sist). 9
Amorterad analys T.ex. analys av metoden push (lägger till ett element sist) för en Lista implementerad med en array som heter A. n perationer Metod push(elementet e) { om antal element = A:s storlek { Allokera en ny array B (dubbelt så stor som A). } Kopiera över alla element i A till B Kalla B för A 1 lägg till e på plats (antal element + 1) peration } Är push verkligen O(n)? Oftast tar det ju bara 1 tidssteg! 10
Amorterad analys Vi kan se detta som en försäljningsautomat som säljer push-operationer i utbyte mot tidsenheter. Varje gång vi använder den måste vi då betala 1 tidsenhet, eller eventuellt n tidsenheter. Om vi låter automaten lagra tidsenheter så skulle den kunna ta mer betalt för varje push, t.ex. 3 tidsenheter, då kanske vi har tillräckligt mycket sparat när vi väl behöver de extra n tidsenheterna. Om vi simulerar detta ett par steg 11 => O(3) O(1)
Rumskomplexitet Mäter hur mycket extra minne algoritmen allokerar förutom indatan int[] tmp = new int[10000000] => O(1) int[] tmp = new int[n.length*2] => O(n) int[][] tmp = new int[n.length][n.length] => O(n 2 ) Harrys och Annas algoritmer har båda konstant rumskomplexitet 12
Problemkomplexitet Ett problems inneboende komplexitet är den minsta komplexiteten av alla algoritmer som kan lösa problemet Sökning i sorterad array (Harry och Annas problem) => O(log(n)) Sökning i osorterad array => O(n) En algoritm med samma komplexitet som problemet är optimal Vinnare: Anna, med en optimal algoritm med konstant rumskomplexitet! 13
Sorteringsstrategier Insertion sorts (hitta rätt plats för ett element) Linear insertion Shell sort... Selection sorts (hitta rätt element för en plats) Straight selection Heap sort... Exchange sorts (byt plats på element som ligger fel) Quick Sort Merge sort... 14
Selection sort Strategi: I varje iteration, sök efter det minsta elementet i den osorterade mängden, och lägg till elementet i slutet av den sorterade mängden. Naiv lösning ( rak selectionsort ) Dela upp arrayen i en sorterad och osorterad del Leta upp det minsta elementet i den osorterade delen och lägg sist i den sorterade Upprepa 15
Selection sort(2) Implementationsexempel void selectionsort(int[] a){ for (int i = 0; i < a.length-1; ++i) { int x = i; for (int j = i+1; j < a.length; ++j) { if (a[j] < a[x]) { x = j; } } byt plats på a[i] och a[x]; } } n n 2 Asymptotisk (tids)komplexitet? Stabil? O(n 2 ) Nej långsam Få byten 16
Shell sort Upprepad insertionsort Strategi: Välj ett lucktal N och låt n vara 0. 1. Markera vart N:te element från och med n i listan och sortera dessa inbördes med insertion sort. 2. Öka n med ett och upprepa (1) tills n == N. 3. Minska N, låt n vara 0 och upprepa (1), (2) tills N < 1 Noteringar: Börja med ett stort N, upp till size/2 Att N == 1 i slutet => Vanlig insertionsort som sista steg 17
Shell sort(2) Val av lucksekvens N i Hibbards [ 1, 3, 7,..., 2 k -1 ] Knuths: [ 1, 4, 13,..., (3 k -1)/2 ] Gonnets: Dividera N med 2.2 stegvis, avrunda nedåt, se till att den sista blir 1, ex. n=100: [ 1, 4, 9, 20, 45 ] T shellsort? Stabil? Svårt, beror på lucksekvensen. Ej sämre än O(n 2 ) Nej 18
Quick Sort Strategi: Divide and conquer : Välj ut ett element p, pivotelementet, och flytta åt sidan. Placera alla element < p till vänster i fältet, alla element > p till höger. Flytta in pivotelementet där den högra och vänstra delen möts Upprepa detta (rekursivt) på vänstra och högra delen. T quicksort = O(n 2 ) MEN Medelfallet nästan lika med bästafallet Ω(nlog(n))! Fördel: Jämför tal nära varandra. Bra när datamängden är mycket stor (för mer info, läs om cache-minnen!) 19
Quick Sort(2) Val av pivotelement Pivotelementet kan väljas godtyckligt men ju bättre val, desto jämnare uppdelning mellan höger och vänster Elementet längst till höger (ligger redan åt sidan ) Slumpa ett element (hoppas att det blir lagom ) Median av tre element (större chans att det blir lagom ) 20
Dialogrutor JOptionPane används för att visa dialogrutor Ett urval av de statiska metoderna: showconfirmationdialog showinputdialog showmessagedialog String name = JOptionPane.showInputDialog("Vad heter du?"); if (name!= null) { // null if user cancels JOptionPane.showMessageDialog(null, "Hej " + namn); } 21
Dialogrutor(2) Körexempel: 22
Fönster Rätt snart vill man rita upp egna typer av fönster Lösning: Klassen JFrame implementerar ett fönster För att skapa ett eget, skriv en klass som ärver från denna Fyll sedan fönstret med de komponenter du vill ha 23
Fönster, exempel public class MyFrame extends JFrame { public MyFrame() { super("välkomstfönster"); JLabel text = new JLabel("Hej allesammans!"); getcontentpane().add(text); setsize(new Dimension(300, 200)); setdefaultcloseoperation(jframe.exit_on_close); } } public static void main(string[] args) { JFrame thewindow = new MyFrame(); thewindow.setvisible(true); } 24
Komponenter 25
Layouthanterare Problem: Om två eller flera komponenter läggs till, var placeras de? Lösning: Använd en layouthanterare getcontentpane().setlayout(new FlowLayout()); FlowLayout GridLayout(r, k) BorderLayout BoxLayout(riktning)... Komponenterna placeras från vänster till höger i rader, uppifrån och ner Delar upp fönstret i rutmönster om r rader och k kolumner. Alla rutor (d.v.s. komponenter) blir lika stora Delar upp fönstret i fem delar: längs sidorna och i mitten: NORTH, SOUTH, WEST, EAST, CENTER En gör-det-själv layout. Placerar komponenterna brevid varandra antingen i x-led eller y-led. Lätt att förstå, mycket att skriva. 26
Layouthanterare(2) Gissa layouthanterare: Borderlayout - Layouten blir ofta ganska grov + Enkel att använda Förfina med under-layouter! 27
Händelser och lyssnare För att programmet ska kunna reagera på händelser kopplar man på olika typer av lyssnare till komponenter i fönstret Lyssnarna kan fånga upp händelser som knapptryckningar och musrörelser Observera att lyssnare är interfaces, du måste själv implementera dem Händelse ActionEvent MouseEvent KeyEvent MenuEvent Lyssnare ActionListener MouseListener, MouseMotionListener KeyListener MenuListener 28