Saker du ska kunna Föreläsning 13 & 14 LISTOR Ta bort element från en vektor Både sorterad och osorterad Söka upp element i en vektor Linjärsökning räcker (jag har även visat binärsökning) Registrering (dvs. att använda en vektor för att räkna förekomster av något) Sortering Jag har visat sett urvalssortering och bubbelsortering Sätta in element i sorterad följd Vektorer med objekt Exempel: hantera alla punkterna Point[] vertices = new Point[3]; vertices[0] = new Point(10,10); vertices[1] = new Point(50,10); vertices[2] = new Point(30,40); Vektorn vertices innehåller punkter, som utgör hörnen i en månghörning. Flytta punkterna i vektorn: for (int i = 0; i < vertices.length; i++) { vertices[i].move(10, 20); vertices x 10 Y 10 0 1 2 x 50 Y 10 x 30 Y 40 Rita månghörningen: SimpleWindow w = new SimpleWindow(600, 600, Polygon"); 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());
Vektor för att representera en polygon Antag att vi vill hantera polygoner med ett godtyckligt antal hörnpunkter. Då får vi gissa hur stor vektor vi behöver för punkterna: 0 1 2 3 4 5 6 7 vertices x 50 y 50 x 70 y 300 x 350 y 350 null null null null x 320 y 200 Det behövs också en variabel som håller reda på hur många punkter vi satt in i vektorn: n 4 Vektorernas begränsningar Här har vi valt ett maximalt antal punkter i polygonen. Hur väljer man ett sådant värde? Om man gör vektorn för liten från början kan inte alla polygoner representeras (t ex en 40-hörning). Om man gör vektorn stor från början (säg, 1000 element) blir många element oanvända (t ex 997 st för en triangel). Då slösar vi med minne. Ibland är det inte praktiskt möjligt att ange ett maximalt antal element på förhand! Klassen Polygon Vektorernas begränsningar (forts.) Per Holm, 2007, avsnitt 8.3 8.5 Visas i Eclipse Vi kan utöka metoden addvertex så att en ny, större vektor skapas vid behov......men det blir en del att skriva. Måste göras igen om vi vill ha en annan, dynamiskt växande, lista. (T.ex. en lista av Turtle, eller heltal.) Det vore smidigt med en datastruktur...... som inte kräver att vi känner antalet element från början... där vi enkelt kan lägga in eller ta bort element... som kan hantera element av olika slag (precis som vektorer)
ArrayList ArrayList: är en standardklass i Java (paketet java.util). innehåller alltid objekt (inte int, double,... ). lagrar sina element i en vektor. utökar vektorns storlek vid behov. har metoder för att sätta in och ta bort element Viktiga operationer på ArrayList (urval) ArrayList<E> /** Skapar en ny lista */ ArrayList<E>(); /** Tar reda på elementet på plats pos */ E get(int pos); /** Lägger in objektet obj sist */ void add(e obj); /** Lägger in obj på plats pos; efterföljande flyttas */ void add(int pos, E obj); /** Tar bort elementet på plats pos och returnerar det */ E remove(int pos); /** Tar reda på antalet element i listan */ int size(); ArrayList är en generisk klass Klassen Polygon med ArrayList (1) ArrayList är en generisk klass och kan innehålla objekt av godtycklig typ. E är en typparameter till klassen. Mer om detta i EDAA01 Programmeringsteknik fördjupningskurs. à Ersätt E med typen på de objekt som lagras i listan. Exempel där vi skapar en lista av Point-objekt och sätter in tre sådana i listan: ArrayList<Point> vertices = new ArrayList<Point>(); vertices.add(new Point(50, 50)); vertices.add(new Point(50, 10)); vertices.add(new Point(30, 40)); public class Polygon { private ArrayList<Point> vertices; /** Skapar en polygon. */ public Polygon() { vertices = new ArrayList<Point>(); /** Definierar en ny punkt med koordinaterna x, y. */ public void addvertex(int x, int y) { vertices.add(new Point(x, y)); /** Flyttar polygonen avståndet dx i x-led, dy i y-led. */ public void move(int dx, int dy) { for (int i = 0; i < vertices.size(); i++) { vertices.get(i).move(dx, dy);
Klassen Polygon med ArrayList (2) /** Ritar polygonen i fönstret w. */ public void draw(simplewindow w) { if (vertices.size() == 0) { return; Point start = vertices.get(0); w.moveto(start.getx(), start.gety()); for (int i = 1; i < vertices.size() ; i++) { w.lineto(vertices.get(i).getx(), vertices.get(i).gety()); w.lineto(start.getx(), start.gety()); Klassen Polygon med ArrayList (3) /** Lägger in en ny punkt med koordinaterna x,y på plats pos. Efterföljande element flyttas */ public void insertvertex(int pos, int x, int y) { vertices.add(pos, new Point(x, y)); /** Tar bort punkten på plats pos. Efterföljande element flyttas */ public void removevertex(int pos) { vertices.remove(pos); Övning: sökning i lista Att traversera listor Lägg till följande metod i klassen Polygon: /** Undersöker om polygonen har någon hörnpunkt med koordinaterna x, y. */ boolean hasvertex(int x, int y) { Anta att vi vill gå igenom en lista (t.ex. för att göra något med alla element). Då kan vi använda for på två sätt: Som tidigare, med hjälp av ArrayLists metoder för att få ut element och storlek, samt en vanlig for-sats. for-each-loopen ("the enhanced for loop ), som är särskilt anpassad för datastrukturer som ArrayList.
Skriv ut alla element: med "vanlig" for-loop Traversera med for-each for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); Antag att vi har följande lista: ArrayList<String> list = new ArrayList<String>(); Då kan vi skriva ut alla element i listan så här: for (String s : list) { System.out.println(s); Sådana for-satser kan även användas för vektorer. ArrayList och primitiva datatyper Typklassen Integer (en skiss) Elementtypen i ArrayList anger elementens klass. Men vad gör man om man vill ha element av primitiva datatyper som int eller double? Detta går alltså inte: ArrayList<int> list = new ArrayList<int>(); Javas lösning på detta har två delar: Typklasser (för objekt som innehåller tal) Autoboxing (specialregler för typklasser) public class Integer { private int value; public static final MIN_VALUE = -2147483648; public static final MAX_VALUE = 2147483647; public Integer(int value) { this.value = value; public int intvalue() { return value;...
Typklasser Typklassen Integer: exempel Primitiva datatyper i Java, och motsvarande typklasser primitiv typ typklass boolean Boolean int Integer double Double char Character Observera skillnaden mellan datatypen int (enkel datatyp) och Integer (klass). int a = 12; Integer b = new Integer(27); b är en referensvariabel som kan referera till ett Integer-objekt. a b 12 27 En lista av heltal (med hjälp av typklassen Integer) Heltal i ArrayList public class ArrayListExample { public static void main(string[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); Scanner scan = new Scanner(System.in); while (scan.hasnextint()) { int nbr = scan.nextint(); Integer obj = new Integer(nbr); list.add(obj); for (int i = list.size() - 1; i >= 0; i--) { Integer obj = list.get(i); int nbr = obj.intvalue(); System.out.println(nbr); Om man vill lagra heltal, reella tal etc. måste man använda motsvarande typklass: ArrayList<Integer> list = new ArrayList<Integer>(); list.add(new Integer(2)); inte ArrayList<int> list = new ArrayList<int>();
Autoboxing (specialregler för typklasser) Typklassen Integer: exempel med autoboxing Om ett int-värde v förekommer där det behövs ett Integerobjekt, så skapas ett Integer-objekt med värdet v. Om ett Integer-objekt obj förekommer där det behövs ett int-värde, så görs automatiskt obj.intvalue(). int a = 12; Integer b = new Integer(27); Det senare kan alltså även skrivas (enklare): a b 12 27 Java översätter alltså automatiskt mellan typen int och klassen Integer. Integer b = 27; Samma sak gäller för double/double, char/character, boolean/boolean m.fl. Använd de primitiva typerna när det är möjligt. Autoboxing är emellertid ofta praktiskt i samband med ArrayList. Heltalslistan, nu med autoboxing Ett exempel: Dictionary public class ArrayListExample { public static void main(string[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); Scanner scan = new Scanner(System.in); while (scan.hasnextint()) { int nbr = scan.nextint(); list.add(nbr); // samma sak som: list.add(new Integer(nbr)); for (int i = list.size() - 1; i >= 0; i--) { int nbr = list.get(i); // samma sak som: int nbr = list.get(i).intvalue(); System.out.println(nbr); Hur kan man implementera följande specifikation? Dictionary /** Skapar en ny ordlista */ Dictionary(); /** Sätt in ett nytt ord på rätt plats i listan */ void insertword(string w); /** Returnerar listans ord, skilda av mellanslag */ String tostring();
public class Dictionary { private String[] words; private int n; /** Skapar en ny ordlista */ public Dictionary() { n = 0; words = new String[100]; // svårt att välja värde! /** Sätt in ett nytt ord på rätt plats i listan */ public void insertword(string word) { int pos = 0; while (pos < n && words[pos].compareto(word) < 0) { pos++; for (int i = n; i > pos; i--) { words[i] = words[i 1]; words[pos] = word; n++; /** Returnerar listans ord, skilda av mellanslag */ public String tostring() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) { sb.append(words[i]); sb.append(' '); return sb.tostring(); public class Dictionary { private ArrayList<String> words; /** Skapar en ny ordlista */ public Dictionary() { words = new ArrayList<String>(); /** Sätt in ett nytt ord på rätt plats i listan */ public void insertword(string word) { int pos = 0; while (pos < words.size() && words.get(pos).compareto(word) < 0) { pos++; words.add(pos, word); /** Returnerar listans ord, skilda av mellanslag */ public String tostring() { StringBuilder sb = new StringBuilder(); for (String w : words) { sb.append(w); sb.append(' '); return sb.tostring(); Vi utökar Dictionary Hur kan man implementera följande metod? /** True om ordet finns i listan, annars false */ boolean contains(string word); Enkel lösning: linjärsökning public boolean contains(string word) { for (String w : words) { if (w.equals(word)) { return true; return false;
En ännu enklare linjärsökning: Metoden equals i klassen Integer ArrayList har en inbyggd contains-metod: public boolean contains(string word) { return words.contains(word); Metoden contains i ArrayList anropar equals i String. Fungerar alltså bara om listans elementklass (String i detta exempel) har en equals-metod. Och det har ju String vi har ju tidigare anropat den: for (String w : words) { if (w.equals(word)) {... public class Integer { private int value; public boolean equals(object obj) { if (! (obj instanceof Integer)) { return false; return value == ((Integer) obj).value; Att göra Point jämförbar Metoden hasvertex ArrayList-metoden contains fungerar bara om elementklassen har en equals-metod. Vår klass Polygon har element av klassen Point. public class Point { private int x; private int y; //... konstruktorer och metoder public boolean equals(object obj) { if (! (obj instanceof Point)) { return false; // obj är inte ett Point-objekt Point p = (Point) obj; return x == p.x && y == p.y; Nu kan man skriva metoden hasvertex i Polygon så här: public boolean hasvertex(int x, int y) { return vertices.contains(new Point(x, y)); Detta förutsätter alltså att Point har en equals-metod (så som just beskrivits).
Hur kan vi göra detta effektivare? Insättningssortering Linjärsökning är det enda alternativet för osorterade listor Men vår lista är ju sorterad! Då är binärsökning effektivare. Då kan vi dock inte längre förlita oss på den inbyggda contains-metoden i ArrayList. Denna metod kan användas för att sortera en mängd S. En resultatlista, R, är inledningsvis tom Element från S sätts, ett i taget, in på rätt ställe i R Detta kallas insättningssortering: Insertion Sort (se insättningssortering och rumänsk folkdans på kurssidan) Mer om detta i övning 9 Sortering med ArrayList Byta plats på två element, ArrayList Exakt samma sorteringsalgoritmer, som visades för vektorerna, kan användas med ArrayList. Skillnaden är att vi nu använder metoderna i ArrayList för att ta ut och sätta in (byta plats på) objekt. Från dokumentationen av ArrayList: public E set(int index, E element) Replaces the element at the specified position in this list with the specified element. Returns: the element previously at the specified position Antag att vi ska byta plats på element med index i och k i en ArrayList a: Integer temp = a.set(i, a.get(k)); a.set(k, temp); alternativt (kortare men klurigare): a.set(k, a.set(i, a.get(k)))
Övning: Vilka tal kommer att skrivas ut? Inför lab 7: matriser int[] v = new int[5]; for (int i = 0; i < 5; i++) { v[i] = 2 * i + 1; System.out.println(v[0]); System.out.println(v[v[0]]); System.out.println(v[v[v[0]]]); System.out.println(v[v[v[v[0]]]]); Lunds Tekniska Högskola Xxxxxxxxxxxxxxxx Xxxxxxxxxxxxxx ÅÅÅÅ-MM-DD Matriser (eng: multidimensional array) Deklarera och skapa matriser En matris är en vektor av vektorer. Man kan också se det som ett rutnät (förutsatt att alla delvektorer har samma storlek) Språkbruket varierar: kolumn/kolonn kolonn: [0] [1] [2] [3] rad: [0] 12 24 2-13 [1] 0 25 35 78 [2] -42 22-36 66 elementens typ matrisens namn antal rader int[][] m = new int[3][5]; antal kolonner Varje cell kommer man åt matrisens namn och cellens index: namn[radindex][kolonnindex] [3] [4] 0 1 2 6 89 4-99 12
Att använda matriser Exempel: matris Att använda ett matriselement: m[2][0] = 0; radindex kolonnindex Man kan ta reda på antal rader: m.length och antal kolonner på raden i: m[i].length (normalt har alla rader lika många kolonner) Beräkna och skriv ut radsummorna i en matris m. // 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); Övning matriser: tic-tac-toe metoder Skapa en klass som representerar ett tic-tac-toe-bräde ("tre-irad"). Spelplanen ska representeras av en char [][] board som ska vara 3x3 element stor. Varje ruta kan innehålla något av tecknen O, X eller (det sista är ett mellanslag). Klassen ska innehålla metoderna som beskrivs på nästa sida. Implementera klassen. (Vi bortser här från användargränssnittet.) Metod för att returnera tecknet vid en given position: public char readposition(int row, int col) Metod för att sätta ett tecken på en given position: public void markposition(char mark, int row, int col) Metod för att se om någon har vunnit, och i så fall returnera det vinnande tecknet: public char getwinner()