Föreläsning 10-12 Datastrukturer Innehåll En datastruktur Vektorer kan innehålla många element. har ett namn, men man kan även komma åt enskilda element. Registrering (räkna element av olika slag) Sökning Exempel: Matriser Klasserna String och StringBuilder lista träd graf Repetition inför delmålskontroll 2 Undervisningsmoment: föreläsning 10-12 övning 4 laboration 7-8 I kursen används listor i form av vektorer klassen ArrayList Avsnitt i läroboken: 8.1-8.8, 8.10, 11 EDAA20 (F10-12 programmering) HT 2016 1 / 59 Program med vektor EDAA20 (F10-12 programmering) HT 2016 2 / 59 Deklarera vektorer Exempel Vektorer deklareras precis som andra variabler med public class MysteryProgram { public static void main(String[] args) { System.out.println("Skriv ett n-värde och " + "därefter n heltal:"); Scanner scan = new Scanner(System.in); int n = scan.nextInt(); int[] v = new int[n]; for (int i = 0; i < v.length; i++) { v[i] = scan.nextInt(); } for (int i = v.length - 1; i >= 0; i--) { System.out.println(v[i]); } } } datatyp namn Exempel: elementens typ Markerar att det är en vektor och inte en vanlig int-variabel int[] v; vektorns namn Vektorer är objekt i Java. v är alltså en referensvariabel. Observera att själva vektorn inte är skapad ännu. v Vad gör programmet? EDAA20 (F10-12 programmering) HT 2016 3 / 59 EDAA20 (F10-12 programmering) HT 2016 4 / 59 Skapa vektorer vektorns namn Vektorer är objekt elementens typ antal element v [0] [1] [2] [3] [4] v = new int[5]; v Antal element måste anges. Elementen får automatiskt startvärden. [0] [1] [2] [3] [4] 0 0 0 0 0 Vektorer är objekt i Java. v refererar till vektorn (vilket framgår av bilden ovan). Men ofta ritar man en enklare bild av vektorn: Oftast deklarerar och skapar man vektorn på samma gång: int[] v = new int[5]; EDAA20 (F10-12 programmering) v HT 2016 5 / 59 Använda vektorelement vektorns namn 0 42 1 3 2 13 3 50 4 7 EDAA20 (F10-12 programmering) HT 2016 6 / 59 HT 2016 8 / 59 Ta reda på vektorns längd index Använd length för att ta reda antal element i vektorn. v[0] = 42; for (int i = 0; i < v.length; i++) { v[i] = scan.nextInt(); } Ett vektorelement används som en vanlig variabel. Tänk på att elementen numreras från 0 och uppåt. Det är viktigt att indexet håller sig inom gränserna [0, antal element 1] EDAA20 (F10-12 programmering) 42 3 13 50 7 HT 2016 7 / 59 EDAA20 (F10-12 programmering) Övning Vektorer är objekt Skapa vektor Referenstilldelning Deklarera och skapa en vektor numbers med plats för 5 stycken element av typen double. Tilldela första elementet värdet 7.2. numbers [0] [1] [2] [3] [4] 7.2 1.0 1.0 1.0 1.0 Vad händer i detta exempel? Hur många vektorer skapas? Vad refererar b till? Komplettera bilden. int[] a = new int[3]; a[0] = 7; a[1] = 8; a[2] = 9; int[] b = a; Deklarera och skapa en vektor exist med plats för 4 stycken element av typen boolean. Tilldela tredje elementet värdet true. exist [0] [1] [2] [3] a [0] [1] [2] false false true false 7 8 9 EDAA20 (F10-12 programmering) EDAA20 (F10-12 programmering) HT 2016 HT 2016 10 / 59 9 / 59 Kopiera vektorer Genvägar Exempel Överkurs, men praktiskt Kopiera a, dvs. skapa en ny vektor med samma innehåll som a. // Skapa en vektor när man vet innehållet: int[] a = {7, 8, 9}; int[] a = new int[3]; a[0] = 7; a[1] = 8; a[2] = 9; int[] b = new int[a.length]; for (int i = 0; i < a.length; i++) { b[i] = a[i]; } a EDAA20 (F10-12 programmering) [0] [1] [2] 7 8 9 b // Kopiera en vektor till en ny vektor med längden a.length: int[] b = Arrays.copyOf(a, a.length); // Metoden Arrays.toString returnerar en sträng med vektorns // innehåll. Skriv ut innehållet i vektorn: System.out.println(Arrays.toString(b)); [0] [1] [2] a 7 8 9 HT 2016 11 / 59 EDAA20 (F10-12 programmering) [0] [1] [2] 7 8 9 b [0] [1] [2] 7 8 9 HT 2016 12 / 59 Lagra objekt i vektorer Lagra objekt i vektorer forts Vektorn vertices med plats för tre Point-objekt: vertices[0] = new Point(10,150); vertices[1] = new Point(50,10); vertices[2] = new Point(90,120); Point[] vertices = new Point[3]; vertices [0] [1] [2] null null null vertices Varje vektorelement är en referensvariabel av typen Point. Observera att vi inte har skapat några punktobjekt ännu, bara en vektor med plats för punkter. EDAA20 (F10-12 programmering) HT 2016 13 / 59 Klassen Triangle public class Triangle { private Point[] vertices; } 10 x 50 x 90 y 150 y 10 y 120 EDAA20 (F10-12 programmering) HT 2016 14 / 59 Huvudprogram som använder klassen Triangle // triangelns hörnpunkter /** Skapar en triangel med hörnpunkterna x1,y1 x2,y2 x3,y3. */ public Triangle(int x1,int y1,int x2,int y2,int x3,int y3) { vertices = new Point[3]; vertices[0] = new Point(x1,y1); vertices[1] = new Point(x2,y2); vertices[2] = new Point(x3,y3); } /** Ritar triangeln i fönstret w. */ public void draw(SimpleWindow w) { w.moveTo(vertices[0].getX(), vertices[0].getY()); for (int i = 1; i < vertices.length; i++) { w.lineTo(vertices[i].getX(), vertices[i].getY()); } w.lineTo(vertices[0].getX(), vertices[0].getY()); } EDAA20 (F10-12 programmering) x HT 2016 15 / 59 public class TriangleExample { public static void main(String[] args) { Triangle t = new Triangle(10, 150, 50, 10, 90, 120); SimpleWindow w = new SimpleWindow(200, 200, "Triangel"); t.draw(w); } } EDAA20 (F10-12 programmering) HT 2016 16 / 59 Registrering Exempel: räkna antal 6:or Exempel på användning av heltalsvektor Uppgift: Räkna antal element av olika slag. Lösning: Använd en vektor av typ int[] för att lagra de olika antalen. Exempel : Räkna mynt.Vi behöver en låda för enkronor, en för femkronor och en för tiokronor: int[] nbrCoins = new int[3]; enkronor femkronor tiokronor EDAA20 (F10-12 programmering) HT 2016 17 / 59 public class DieTest { public static void main(String[] args) { Die d = new Die(); Scanner scan = new Scanner(System.in); System.out.println("Antal tärningskast: "); int nbrRolls = scan.nextInt(); int nbr6 = 0; for (int i = 0; i < nbrRolls; i++) { d.roll(); if (d.getResult() == 6) { nbr6++; } } System.out.println("Det blev en 6:a i " + (double) nbr6/nbrRolls * 100 + " % av fallen"); } } Ändra i programmet så att även antal 1:or, antal 2:or, ... räknas. EDAA20 (F10-12 programmering) Exempel: räkna antal olika tärningskast HT 2016 18 / 59 Exempel: registrera poäng Räkna antal 1:or, antal 2:or . . . Antag att ett antal studenter har skrivit ett prov. På provet kan man ha max 50 poäng. Vi ska räkna int[]res = new int[6]; for (int i = 0; i < nbrRolls; i++) { d.roll(); res[d.getResult() - 1]++; } antal studenter som har 0, 1, ..., 50 poäng. antal studenter som har 0-9, 10-19, 20-29, 30-39, 40-50 poäng. Vi koncentrerar oss här bara på registreringen och och skriver ett litet huvudprogram där vi antar att antal studenter är 100. Poängen slumpar vi fram. (De blir rektangelfördelade vilket är orealistiskt.) I läroboken finns det ett större exempel med klasser för studenter och prov. 0 1 2 3 4 5 res 16454 16512 16786 16725 16731 16792 antal 1:or EDAA20 (F10-12 programmering) antal 2:or antal 6:or HT 2016 19 / 59 EDAA20 (F10-12 programmering) HT 2016 20 / 59 Exempel: registrera poäng Exempel: registrera poäng 0, 1 ,... , 50 0-9, 10-19, 20-29, 30-39, 40-50 public class RegExample { public static void main(String[] args) { Random rand = new Random(); int[] nbrs = new int[50]; // antal med 0 poäng, // antal med 1 poäng ... for (int i = 0; i < 100; i++) { int p = rand.nextInt(51); // slumpa poäng nbrs[p]++; // notera poängen } System.out.println(Arrays.toString(nbrs)); } } nbrs antal med 0 poäng 0 0 1 0 antal med 1 poäng EDAA20 (F10-12 programmering) 2 0 ... antal med 2 poäng Vi har 5 intervall och behöver en vektor med 5 platser: int[] nbrs = new int[5]; Översättning från poängantal till index: int index = p / 10; Poängantalet 50 måste särbehandlas. nbrs 50 0 0-9 poäng antal med 50 poäng HT 2016 Exempel: registrera poäng Registrering 0-9, 10-19, 20-29, 30-39, 40-50, forts Kommentar public class RegExampleInterval { public static void main(String[] args) { Random rand = new Random(); int[] nbrs = new int[4]; // antal med 0-10 poäng, // antal med 10-19 poäng ... for (int i = 0; i < 100; i++) { int p = rand.nextInt(51); // slumpa poäng int index = p / 10; // Ex: 37 poäng ger index 3 if(index == 5){ //särbehandla 50 poäng index = 4; } nbrs[index]++; } System.out.println(Arrays.toString(nbrs)); } } HT 2016 1 0 10-19 poäng 2 0 20-29 poäng 3 0 30-39 poäng 4 0 40-50 poäng 21 / 59 EDAA20 (F10-12 programmering) EDAA20 (F10-12 programmering) 0 0 23 / 59 HT 2016 22 / 59 Passar det alltid att använda en heltalsvektor för att räkna antal av olika slags element? I de exempel vi använt har det varit lätt att översätta från ”slag av element” till index i resultatsvektorn. I andra fall är det svårare. Antag att vi ska räkna antal förekomster av olika ord i en text. I så fall är det bättre att vi lagrar ordet tillsammans med antal förekomster i någon annan datastruktur. Det finns färdiga klasser i Java som kan användas i sådana fall (t.ex. HashMap) Detta behandlas i en senare kurs. EDAA20 (F10-12 programmering) HT 2016 24 / 59 Linjärsökning Linjärsökning Mönster Med for-sats Algoritm: for (int i = 0; i < "antal element"; i++) { if ("elementet på plats i är det vi söker") { avbryt } } Uppgift: Sök upp givet element i en följd av element. Lösning: Gå igenom elementen i tur och ordning och kontrollera för varje element om det är det sökta. Avbryt om det sökta elementet påträffas. EDAA20 (F10-12 programmering) HT 2016 25 / 59 Diskutera Exempel : /** Sök efter talet nbr i vektorn v. Om nbr finns returneras platsen för nbr, annars -1 */ public static int indexOf(int[] v, int nbr) { for (int i = 0; i < v.length; i++) { if (v[i] == nbr) { return i; } } return -1; } EDAA20 (F10-12 programmering) HT 2016 26 / 59 Linjärsökning Med while-sats Algoritm: public static int indexOf(int[] v, int nbr) { for (int i = 0; i < v.length; i++) { if (v[i] == nbr) { return i; } else { return -1; } } } i = "platsen för det första elementet" while ("fler element kvar att söka igenom" && "elementet på plats i inte är det vi söker") i = platsen för nästa element Exempel : Varför fungerar inte det här? EDAA20 (F10-12 programmering) HT 2016 27 / 59 public static int indexOf(int[] v, int nbr) { int i = 0; while (i < v.length && v[i] != nbr) { i++; } if (i < v.length) { return i; } else { return -1; } } EDAA20 (F10-12 programmering) HT 2016 28 / 59 Diskutera Linjärsökning Kommentar Ordningen mellan delvillkoren är viktig. Varför måste jämförelsen i < v.length göras först? I exemplet på föregående sida förutsäter vi att vektorns alla platser används och ska sökas igenom. Vi har alltså v.length element att söka igenom: int i = 0; while (i < v.length && v[i] != nbr) { i++; } while (i < v.length && v[i] != nbr) } Varför kan man inte använda villkoret v[i] == nbr för att avgöra om man funnit talet nbr eller ej? } if (i < v.length) { return i } else { return -1; } EDAA20 (F10-12 programmering) I motsvarande exempel i läroboken (avsnitt 8.8) har man en vektor där de bara de n första platserna i vektorn utnyttjas: while (i < n && v[i] != nbr) { HT 2016 29 / 59 Klassen Arrays EDAA20 (F10-12 programmering) HT 2016 30 / 59 Exempel: polygon Vektorer med godtyckligt antal element I Java finns det en klass Arrays som innehåller en hel del metoder bland annat för att söka i vektorer och sortera. Exempel: Antag att vi har en vektor v av typen int[] med sorterade heltal. Då kan vi söka efter platsen för talet 42 på följande sätt: int index = Arrays.binarySearch(v, 42); Antag att vi vill hantera polygoner med ett godtyckligt antal hörnpunkter. Vi måste skapa en tillräckligt stor vektor för punkterna. Det behövs också en variabel som håller reda på hur många punkter vi satt in i vektorn: Point[] vertices = new Point[8]; int n = 0; Vektorn kan sorteras genom följande anrop: Arrays.sort(v); Att använda denna klass ingår ej i kursen, men det kan vara bra att veta att det finns en hel del färdigt om du fortsätter skriva program efter kursens slut. Vill du veta mera så se vidare i Javas dokumentation. 0 1 2 3 4 5 6 7 vertices null null null null null null null null n 0 EDAA20 (F10-12 programmering) EDAA20 (F10-12 programmering) HT 2016 31 / 59 HT 2016 32 / 59 Exempel: polygon Sätta in en ny punkt forts Insättning av en ny punkt efter de andra punkterna i polygonen: Exempel: Polygon med fyra hörnpunkter 0 1 2 3 vertices vertices[n] = new Point(200, 40); n++; 4 5 6 7 null null null null 0 1 2 3 x y 350 350 4 5 6 7 null null null vertices x y x y 50 50 n 70 300 x y 350 350 x y 320 200 x y x y 50 50 x y x y 320 200 200 40 4 n EDAA20 (F10-12 programmering) HT 2016 33 / 59 Klassen Polygon public class Polygon { private Point[] vertices; private int n; EDAA20 (F10-12 programmering) HT 2016 34 / 59 Borttagning av punkten på plats pos i vektorn vertices: Täpp till ”hålet” i vektorn genom att flytta flytta alla element efter pos ett steg till vänster. Uppdatera n eftersom antal punkter minskat med 1. // polygonens hörnpunkter // antal hörnpunkter public void removeVertex(int pos) { for (int i = pos; i < n - 1; i++) { vertices[pos] = vertices[pos + 1]; } vertices[n - 1] = null; n--; } /** Sätter in en ny punkt med koordinaterna x, y. */ public void addVertex(int x, int y) { vertices[n] = new Point(x, y); n++; } EDAA20 (F10-12 programmering) 5 Ta bort en punkt /** Skapar en polygon med max 8 hörnpunkter. */ public Polygon() { vertices = new Point[8]; n = 0; } } 70 300 HT 2016 35 / 59 EDAA20 (F10-12 programmering) HT 2016 36 / 59 Före borttagning av punkten 0 1 2 Efter borttagning av punkten 3 4 5 6 7 null null null vertices 0 1 2 3 x y 320 200 vertices x y x y 50 50 n 5 pos 1 70 300 x y EDAA20 (F10-12 programmering) 350 350 x y 320 200 x y 200 40 HT 2016 37 / 59 Passar en vektor för detta? x y x y 50 50 n 4 pos 1 350 350 EDAA20 (F10-12 programmering) 4 5 6 7 null null null null x y 200 40 HT 2016 38 / 59 Exempel: Linjärsökning Klassen Polygon I exemplet på föregående bilder måste vi gissa hur stor vektor vi behöver. Vad händer om vi vill sätta in fler än 8 punkter? Då måste vi skapa en ny större vektor. För problem där antal element varierar är det enklare att använda den färdiga klassen ArrayList (behandlas senare i kursen). Ett ArrayList-objekt använder internt en vektor och har färdiga metoder för att sätta in element i listan, ta bort element etc. EDAA20 (F10-12 programmering) HT 2016 39 / 59 Lägg till en metod som undersöker om punkten x, y ingår bland polygonens hörnpunkter. public boolean hasVertex(int x, int y) { for (int i = 0; i < n; i++) { if (vertices[i].getX() == x && vertices[i].getY() == y) { return true; } } return false; } EDAA20 (F10-12 programmering) HT 2016 40 / 59 Håll koll på typerna Matriser Kontrollera att typerna stämmer vid tilldelningar och jämförelser för att undvika fel. index vektorn med punkter en punkt punktens x-koordinat punktens y-koordinat namn i vertices vertices[i] vertices[i].getX() vertices[i].getY() kolonn 0 rad 0 rad 1 rad 2 typ int Point[] Point int int kolonn 1 7 22 11 kolonn 2 9 -18 16 123 12 -4 EDAA20 (F10-12 programmering) EDAA20 (F10-12 programmering) HT 2016 kolonn 3 41 3 0 kolonn 4 1 -2 1 HT 2016 42 / 59 HT 2016 44 / 59 41 / 59 Deklarera och skapa matriser Använda matriser Att använda ett matriselement: radindex elementens typ m[2][0] = 0; int[][] m = new int [3][5]; antal rader kolonnindex Man kan ta reda på antal rader: antal kolonner m.length och antal kolonner på raden i: m[i].length EDAA20 (F10-12 programmering) HT 2016 43 / 59 EDAA20 (F10-12 programmering) Övning Exempel Matris Matris Deklarera och skapa en matris som representerar ett schackbräde med 8 x 8 rutor. På rutorna ska man kunna placera schackpjäser som beskrivs av en klass ChessPiece. Beräkna och skriv ut radsummorna i en 3 x 5-matris. för varje rad för varje element på raden behandla elementet for (int i = 0; i < m.length ; i++) { int sum = 0; for (int k = 0; k < m[i].length; k++) { sum = sum + m[i][k]; } System.out.println(sum); } EDAA20 (F10-12 programmering) HT 2016 45 / 59 Övning EDAA20 (F10-12 programmering) HT 2016 46 / 59 Klassen String Matris Antag att vi har en matris booked av typen boolean[][] som ska användas för att hålla reda på bokade platser i en biosalong. Varje matriselement motsvarar en plats i salongen och har värdet true om platsen är bokad, i annat fall värdet false. Klassen String beskriver en teckensträng (en följd av tecken). Tecknen kan läsas av men inte ändras. Exempel: Skriv satser som räknar antal bokade platser. String s = "En massa tecken"; String empty = ""; En massa tecken s empty EDAA20 (F10-12 programmering) EDAA20 (F10-12 programmering) HT 2016 47 / 59 HT 2016 48 / 59 Slå ihop (konkatenera) strängar Behandla alla tecken i strängen Mönster : String s1 = "En text"; String s2 = "En text till"; String result = s1 + " och " + s2; String s = ...; for (int i = 0; i < s.length(); i++) { // aktuellt tecken nås med anropet s.charAt(i); } En text Exempel: Räkna antal blanktecken i strängen s. En text till s1 s2 result int spaces = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == ’ ’) { spaces++; } } En text och En text till EDAA20 (F10-12 programmering) HT 2016 49 / 59 EDAA20 (F10-12 programmering) Övning 50 / 59 Jämföra teckensträngar med equals Vad skrivs ut? Förklara varför. Vill man jämföra innehållet i teckensträngarna måste man använda metoden equals: ↵ /** Returnerar true om innehållet i aktuell sträng är lika med innehållet i s. */ boolean equals(Object s); ⌦ Scanner scan = new Scanner(System.in); String s1 = scan.next(); String s2 = scan.next(); if (s1 == s2) { System.out.println("Lika"); } else { System.out.println("Inte lika"); } Exempel: abc s1 s2 EDAA20 (F10-12 programmering) HT 2016 if (s1.equals(s2)) { System.out.println("Samma innehåll"); } else { System.out.println("Inte samma innehåll"); } abc HT 2016 51 / 59 EDAA20 (F10-12 programmering) HT 2016 52 / 59 Jämföra teckensträngar med compareTo Klassen StringBuilder Med metoden compareTo kan man avgöra om en sträng är ”större än” eller ”mindre än” en annan sträng: ↵ /** Jämför aktuell sträng med s. Returnerar 0 om teckensträngarna är lika, ett negativt tal om aktuell sträng är mindre än s, ett positivt tal om aktuell sträng är större än s. int compareTo(String s); ⌦ Klassen StringBuilder beskriver en följd av tecken som kan läsas och ändras. Exempel: StringBuilder b = new StringBuilder("En massa tecken"); b.append("!"); */ En massa tecken! Exempel: b String s1 = "java"; s1.compareTo("java") == 0 s1.compareTo("javac") < 0 s1.compareTo("Java") > 0 s1.compareTo("jazz") < 0 EDAA20 (F10-12 programmering) EDAA20 (F10-12 programmering) HT 2016 HT 2016 Några metoder i klassen StringBuilder Ändra innehållet i StringBuilder-objekt ↵ /** Lägger in s efter tecknen i strängbufferten. */ StringBuilder append(String s); ↵ /** Skapar en tom strängbuffert. */ StringBuilder(); /** Skapar en strängbuffert med samma innehåll som s. */ StringBuilder(String s); /** Ändrar tecknet på plats k till ch. */ void setCharAt(int k, char ch); /** Tar reda på antal tecken. */ int length(); /** Lägger in s på plats k, flyttar tecknen efter. */ StringBuilder insert(int k, String s); /** Tar reda på tecknet på plats pos. */ char charAt(int pos); /** Returnerar ett String-objekt med samma innehåll som denna strängbuffert. */ String toString(); ⌦ EDAA20 (F10-12 programmering) 54 / 59 53 / 59 HT 2016 55 / 59 /** Tar bort tecknet på plats k. */ StringBuilder deleteCharAt(int k); ⌦ Man kan sätta in värden av andra typer än String i ett StringBuilderobjekt. Det finns flera metoder append och insert. Dessa har en parameter av typen int, double, char, .... EDAA20 (F10-12 programmering) HT 2016 56 / 59 Metoden toString Delmål 2 Det är vanligt att man lägger till metoden toString i sina klasser. Metoden toString anropas t.ex. inuti println och används av debuggern när ett objekt ska skrivas ut. Repetition På föreläsning 12 blir det repetition inför delmålskontroll 2. Det vi ska repetera är framförallt: Metoden toString i klassen Point (kap. 3) kan se ut så här: public String toString() { return x + " " + y; } implementering av klasser använda vektorer och matriser Material till denna repetitionsföreläsning delas ut separat. eller så här: public String toString() { StringBuilder b = new StringBuilder(); b.append(x); b.append(’ ’); b.append(y); return b.toString(); } EDAA20 (F10-12 programmering) HT 2016 57 / 59 Checklista Exempel på vad du ska kunna Förklara begreppen datastruktur, vektor, matris. Deklarera, skapa och använda vektorer och matriser. Formulera algoritmer och programkod för att söka i en vektor eller matris (linjärsökning). Formulera algoritmer och programkod för att räkna antal element av olika slag (registrering). Använda klasserna String och StringBuilder Implementera och använda klasser (större än tidigare). EDAA20 (F10-12 programmering) HT 2016 59 / 59 EDAA20 (F10-12 programmering) HT 2016 58 / 59