PG4200 Algoritmer og datastrukturer Forelesning 5 Implementasjon av lister Lars Sydnes, NITH 5. februar 2014
I. Implementasjoner
Tabell-implementasjon av Stakk Tabellen er den lettest tilgjengelige datastrukturen Oppslag i tabell har kjøretid av orden O(1). La oss bruke en en variabel int top til å holde orden på hvor det øverste elementet i stakken ligger. posisjon: 0 1 2 3 k-1 k adresse: A B C D (TOPP) null null top = 4
Tabell-implementasjon av Stakk Representasjon av data public class ArrayStack{ private int top; private T[] stack; public ArrayStack(int initialcapaticy) { top = 0; stack = (T[])(new Object[initialCapacity]); } /*...*/ }
Tabell-implementasjon av Stakk push public void push(t theelement) { if(!(top < stack.length)) { expandcapacity(); } stack[top] = element; top++; } private void expandcapacity() { stakk = Arrays.copy(stakk,stakk.length*2); }
Tabell-implementasjon av Stakk pop og peek public T pop() { T result = peek(); top--; stack[top] = null; // HVORFOR!!! return result; } public T peek() { if (top == 0) return null; return stack[top-1]; }
Tabell-implementasjoner Tabeller har fast kapasitet: Integer[] tall = new Integer[100]; Hvis vi skal lage mer fleksible datastruktrer, må vi kunne utvide kapasiteten: tall = Arrays.copyOf(tall,200); Dette innebærer alltid kopiering av alle elementene i tabellen. Fast kapasitet = Grunnleggende problem med tabeller. Indeksering = Grunnleggende fordel med tabeller.
Lenkede strukturer Figur 1: Java-kode public class LinearNode<T> { public T innhold; public LinearNode<T> adresse; } Figur 2: Utdrag av minnet Peker til T Peker LinearNode<T> Figur 3: Grafisk fremstilling T 1 T 2
Lenkede lister: Innsetting TOP T 4 T 3 T 2 T 1 T 5 (Setter inn ny node T 5 ) TOP T 4 T 3 T 2 T 1 TOP T 5 T 4 T 3 T 2 T 1 Dette gir stakk-operasjonen push
Lenkede lister: Ta ut elementer TOP T 5 T 4 T 3 T 2 T 1 T 5 (Fjerner node T 5 ) TOP T 4 T 3 T 2 T 1 TOP T 4 T 3 T 2 T 1 Dette gir stakk-operasjonen pop
Lenkede Lister: Generell innsetting: TOP T 4 T 3 T 2 T 1 T NY (Setter inn ny node T NY ) TOP T 4 T 3 T 2 T 1 TOP T 4 T NY T 3 T 2 T 1
Lenkede lister: Ta ut generelle elementer TOP T 5 T 4 T 3 T 2 T 1 T 4 (Fjerner node T 4 ) TOP T 5 T 3 T 2 T 1 TOP T 5 T 3 T 2 T 1
Lenkede Lister vs. Tabeller Lenkede Lister: Det er vanskelig å finne fram til elementer: Vi må spørre om veien. Enkelt å sette inn og ta ut elementer. Størrelsen passer seg selv. Tabeller: Det er enkelt å finne fram til en konkret adresse. De har en oversiktlig representasjon i datamaskinens minne. Vi må holde øye med kapasiteten.
II. Sirkulære tabeller: Array-implementasjon av kø.
Naiv implementasjon class ArrayQueue<E> { E[] queue; int count; /*...*/ } Det første objektet i køen har indeks 0. Det bakerste opbjektet i køen har indeks count-1. Innsetting (offer) går greit: Plassér nytt objekt i indeks count og inkrementer count Å ta ut objekter (poll) er mer tungvint: Hent ut objektet i indeks 0 og kopiér alle de andre objektene ett steg til venstre.
Sirkulær tabell class CircularQueue<E> { E[] queue; int front,rear; /*...*/ } Det første objektet i køen har indeks front. Det bakerste opbjektet i køen har indekx rear-1. Innsetting (offer): Plassér nytt objekt i indeks rear og inkrementer rear Å ta ut objekter (poll): Hent ut objektet i indeks front og inkrementer front.
Demonstrasjon A B C D null null null front = 0, rear = 4 null null C D E null null front = 2, rear = 5 null null C D E F null front = 2, rear = 6
Demonstrasjon: Twist in the tail null null null null E F G front = 4, rear = 0 Er det fullt her nå? H I null null E F G front = 4, rear = 2 Nei, vi kan utnytte den ledige plassen ved begynnelsen av tabellen!
Sirkulær tabell noen spørsmål Det kan være praktisk å bruke hjelpevariabler som int count,capacity; Disse hjelpevariablene er strengt tatt unødvendige. Hva skjer med front,rear når de overstiger listens kapasitet? Rest-operatoren % kan være nyttig: Når n, m > 0 er n%m lik resten i divisjonen n/m, dette er et tall 0 men < m.
Liste-implementasjoner Forenklet liste-grensesnitt: interface List<E> implements Iterable<E> { boolean set(e e,int i); E get(int i) E remove(int i); int size(); } Iterator<E> iterator(); // SENERE Lage lenket liste Lage tabell-liste.
III. Iteratorer
Iterable<E> For beholdere som implementerer Iterable<E>-grensesnittet kan vi skrive for-each-løkker: for(string str: beholder) System.out.println(str); Iterable-grensesnittet: package java.lang; import java.util.iterator; public interface Iterable<T> { Iterator<T> iterator(); }
Iterator<E> Iterator-grensesnittet: package java.util; public interface Iterator<E> { boolean hasnext(); E next(); } void remove(); Obs: Remove er ofte ikke implementert.
Iterator<E> Vi kan se på for(string str: beholder) dosomething(str); Som en praktisk forkortelse for Iterator<String> itr = beholder.iterator(); while (itr.hasnext()) dosomething(itr.next()
Implementasjon av iterator Iteratorobjektet må hele tiden holde orden på hvor i listen vi befinner oss. Lenket liste: Hvilken node er vi i for øyeblikket? Tabell-liste: Hvilken indeks er aktuell?
IV. Bruk av lineære strukturer
Bruk av lister Som en ren beholder. Lagre objekter Hentet ut uspesifiserte objekter Som en ordnet liste: Vi vil holde ting i en bestemt rekkefølge. Som en indeksert liste: Vi vil assosiere objekter med en indeks.
Ikke-bruk av lister Lister egner seg ikke for vanlig lagring og søk: arraylist.contains(target); Her står vi i fare for å sammenligne target med alle objektene i beholderen. HashSet o.l egner seg utmerket for denne operasjonen. Jfr. Lab 1. Mer om HashSet i en senere forelesning.