Algoritmer og datastrukturer Kapittel 4 - Delkapittel 4.4

Like dokumenter
Algoritmer og datastrukturer Kapittel 4 - Delkapittel 4.3

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.1

Algoritmer og datastrukturer Eksamen

Algoritmer og datastrukturer Eksamen

Algoritmer og datastrukturer Eksamen 22. februar 2011

Algoritmer og datastrukturer Eksamen

Algoritmer og datastrukturer Kapittel 4 Delkapittel 4.2

Algoritmer og datastrukturer Eksamen

Algoritmer og datastrukturer Løsningsforslag

Algoritmer og datastrukturer Kapittel 4 - Delkapittel 4.2

Emnekode: I-Dato: I ~ Antall oppgaver: I I Aiie -sk:i=rftlige - bme trykte og håndskrevne, samt alle typer

G høgskolen i oslo. Emne: Algoritmer og datastrukturer. Emnekode: 80131A. Faglig veileder: UlfUttersrud. Gruppe(r) : Dato:

Algoritmer og datastrukturer Kapittel 4 - Delkapittel 4.1

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.3

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.8

Hva er en kø? En lineær datastruktur der vi til enhver tid kun har tilgang til elementet som ble lagt inn først

Algoritmer og datastrukturer Kapittel 2 - Delkapittel 2.2

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.2

Algoritmer og datastrukturer Eksamen

Fagnr: A. Ant. vedlegg: 1 (2 sider)

EKSAMEN. Dato: 9. mai 2016 Eksamenstid: 09:00 13:00

Ny/utsatt EKSAMEN. Dato: 5. januar 2018 Eksamenstid: 09:00 13:00

Fagnr: A. Ant. vedlegg: 1 (2 sider)

Algoritmer og datastrukturer Løsningsforslag

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.3

Løsningsforslag. Oppgave 1.1. Oppgave 1.2

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

Algoritmer og datastrukturer E Løkker i Java

Algoritmer og datastrukturer Løsningsforslag

Oppgave 1. Løsningsforslag til eksamensoppgave. ITF20006 Algoritmer og datastrukturer Postorden traversering:

Hva er en kø? En lineær datastruktur der vi til enhver tid kun har tilgang til elementet som ble lagt inn først

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.1

Hva er en kø? En lineær datastruktur der vi til enhver tid kun har tilgang til elementet som ble lagt inn først

EKSAMEN. Algoritmer og datastrukturer. Eksamensoppgaven: Oppgavesettet består av 10 sider inklusiv vedlegg og denne forsiden.

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.3

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Algoritmer og datastrukturer Løsningsforslag

Ny/utsatt EKSAMEN. Dato: 6. januar 2017 Eksamenstid: 09:00 13:00

Sortering med Comparable og Comparator

Kap.8 Sortering og søking sist oppdatert 16.03

UNIVERSITETET I OSLO

INF1010 LISTER. Listeelementer og listeoperasjoner. Foran. Bak

Oppgavesettet består av 7 sider, inkludert denne forsiden. Kontroll& at oppgaven er komplett før du begynner å besvare spørsmålene.

EKSAMEN. Dato: 18. mai 2017 Eksamenstid: 09:00 13:00

EKSAMEN. Dato: 28. mai 2018 Eksamenstid: 09:00 13:00

Kapittel 8: Sortering og søking

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

UNIVERSITETET I OSLO

En implementasjon av binærtre. Dagens tema. Klassestruktur hovedstruktur abstract class BTnode {}

Algoritmer og datastrukturer Vedlegg A.2 BitOutputStream

Eksamen IN1010/INF1010 våren 2018

Kapittel 9: Sortering og søking Kort versjon

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.2

Lenkelister, iteratorer, indre klasser. Repetisjonskurs våren 2018 kristijb

PG4200 Algoritmer og datastrukturer Forelesning 5 Implementasjon av lister

Liste som abstrakt konsept/datatype

Algoritmer og datastrukturer Kapittel 2 - Delkapittel 2.1

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.2

Hva er en liste? Hvert element har en forgjenger, unntatt første element i listen. Hvert element har en etterfølger, unntatt siste element i listen

Heap* En heap er et komplett binært tre: En heap er også et monotont binært tre:

UNIVERSITETET I OSLO

Algoritmer og datastrukturer A.1 BitInputStream

~ta11 oppgaver: 4. Nle skriftlige hjelpemidler-både trykte og håndskrevne, er tillatt

PRIORITETSKØ. Aksjehandel. Datastruktur for aksjehandel. Nøkler og Totalorden-relasjonen

Kapittel 9: Sortering og søking Kort versjon

Kapittel 9: Sortering og søking Kort versjon

Algoritmer og Datastrukturer

Algoritmer og Datastrukturer

Fra Kap.10 Binære søketre (BS-tre) Sist oppdatert Definere en abstrakt datastruktur binært søketre. Vise hvordan binær søketre kan brukes

UNIVERSITETET I OSLO

Dagens tema INF1010 INF1010 INF1010 INF1010

INF1010 notat: Binærsøking og quicksort

Algoritmer og datastrukturer A.1 Filbehandling på bit-nivå

Oppgave 1. Sekvenser (20%)

Algoritmer og datastrukturer Kapittel 11 - Delkapittel 11.2

Løsnings forslag i java In115, Våren 1998

Fagnr: SO 131 A. Ant. vedlegg: 1 (2 sider)

UNIVERSITETET I OSLO

Løsnings forslag i java In115, Våren 1996

UNIVERSITETET I OSLO

Løsningsforslag til eksamen i INF1000 våren 2006

UNIVERSITETET I OSLO

EKSAMEN. Algoritmer og datastrukturer. Eksamensoppgaven: Oppgavesettet består av 11 sider inklusiv vedlegg og denne forsiden.

Eks 1: Binærtre Binærtretraversering Eks 2: Binærtre og stakk

Løsningsforslag Test 2

Hva er en liste? Hvert element har en forgjenger, unntatt første element i listen. Hvert element har en etterfølger, unntatt siste element i listen

Det finnes ingenting. som kan gjøres med interface. men som ikke kan gjøres uten

OPPGAVE 5b og 8b Java Kode

INF1020 Algoritmer og datastrukturer. Dagens plan

EKSAMEN. Algoritmer og datastrukturer

Søkeproblemet. Gitt en datastruktur med n elementer: Finnes et bestemt element (eller en bestemt verdi) x lagret i datastrukturen eller ikke?

UNIVERSITETET I OSLO

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

UNIVERSITETET I OSLO

Algoritmer og datastrukturer Kapittel 11 Delkapittel 11.2

Inf 1020 Algoritmer og datastrukturer

EKSAMEN med løsningsforslag

UNIVERSITETET I OSLO

PG4200 Algoritmer og datastrukturer Forelesning 7

Transkript:

Delkapittel 4.4 En prioritetskø Side 1 av 8 Algoritmer og datastrukturer Kapittel 4 - Delkapittel 4.4 4.4 En prioritetskø 4.4.1 Grensesnittet PrioritetsKø En prioritetskø (engelsk: priority queue) er en kø der de som «står» i køen har en prioritet. Da er regelen at den som har «best» eller «høyest» prioritet står først for tur til å bli tatt ut. En konsekvens er at den som har «lav» prioritet kan oppleve å måtte vente lenge. Vi skal bruke prioritetskøer flere ganger og da som et verktøy i bestemte algoritmer. Men også i «dagliglivet» er det mulig å finne eksempler på prioritetskøer: En søkerkø En søkerkø: Hvis en student som gjør seg ferdig med en bachelorutdanning, ønsker å søke på en masterutdanning, må han/hun normalt ha minst C som gjennomsnittskarakter. Hvis det er flere søkere enn plasser, vil søkerne normalt bli rangert etter karakterer. Det kan betyr at alle som har A i gjennomsnitt kommer foran de som har B, osv. Med andre ord er her «best» prioritet lik best gjennomsnittskarakter. En sykehuskø: Behandlingsrekkefølgen på et sykehus kan kanskje ses på som en slik kø. Der er det vel i mange tilfeller slik at man får prioritet etter hvor syk man er. Den som er sykest har «høyest» prioritet. Det høres vel ikke urimelig ut. Risikoen er at noen aldri blir behandlet fordi de har for lav prioritet - de blir hele tiden passert av andre med høyere prioritet. Kølapper: På mange steder, f.eks. på postkontorer, er det innført et kølappsystem. Da er det den med lavest nummer som står for tur til å bli betjent. Men dette er ikke en prioritetskø, men en vanlig kø fordi en nyankommet trekker alltid et kønummer som kommer etter det som sist ble trukket. Med andre ord kommer alltid en ny kunde bakerst i køen. Vi trenger minst de samme metodene i en prioritetskø som i en vanlig kø, dvs. legginn, kikk, taut, antall, tom og nullstill. Forskjellen er at taut nå skal ta ut den med «best» eller «høyest» prioritet. Hva som gir «best» eller «høyest» prioritet styrer vi ved hjelp av en komparator. Da det kanskje naturlig at den som er minst med hensyn på ordningen som komparatoren definerer, somhar best/høyest prioritet. Slik er det f.eks. gjort i prioritetskøen som følger med Java (klassen PriorityQueue i java.util). Det kan ofte hende at to eller flere elementer har samme prioritet. Hvem av dem skal da tas ut først? I mange anvendelser spiller dette ingen rolle og dermed kan man lage mer effektive prioritetskøer. I noen tilfeller er det viktig å kunne ha en bestemt rekkefølge på de som har samme prioritet. Et krav kunne f.eks. være at de som har samme prioritet ordnes som i en vanlig kø, dvs. den som har ventet lengst står først for tur til å bli tatt ut. Det kan man få til f.eks. ved å innføre et «kønummer» i tillegg til en prioritet. Den med lavest «kønummer» blant dem med samme prioritet skal da tas ut først.

Delkapittel 4.4 En prioritetskø Side 2 av 8 public interface PrioritetsKø<T> public void legginn(t verdi); public T kikk(); public T taut(); public boolean taut(t verdi); public int antall(); public boolean tom(); public void nullstill(); Programkode 4.4.1 a) // Java: PriorityQueue // Java: add/offer // Java: element/peek // Java: remove/poll // Java: remove // Java: size // Java: isempty // Java: clear Det er ingen spesielle krav til metoden legginn bortsett fra at null-verdier er ulovlige. Metoden kikk skal returnere (uten å fjerne) objektet med «best» prioritet. Er det flere med «best» prioritet, er det ingen bestemte krav til hvem av dem som skal returneres. Metoden taut skal virke som kikk, men i tillegg fjerne objektet fra køen. Metoden taut(t verdi) skal fjerne objektet verdi fra køen. Metoden antall skal returnere antallet i køen og dermed 0 hvis køen er tom. Metoden tom skal returnere sann (true) hvis køen er tom og usann (false) ellers. Metoden nullstill skal «tømme» køen. PriorityQueue i Java er en klasse og ikke et grensesnitt. Det kommer nok av at det ikke er aktuelt å ha flere implementasjoner siden det er én som normalt alltid er best. Dette i motsetning til f.eks. grensesnittene Queue og Deque. De kan implementeres på flere aktuelle måter. Vi lager her noen enkle, men lærerike implementasjoner av vårt grensesnitt. Den beste tar vi etter at vi har gått dypere inn i trestrukturer. Se Avsnitt 5.3. 4.4.2 En prioritetskø ved hjelp av en usortert tabell Prioritetskøen kan ha en usortert dynamisk tabell som intern datastruktur. Vi bestemmer at det objektet som en komparator sier er minst, er det som har best/høyest prioritet. I flg. eksempel inneholder køen heltall og det minste heltallet har dermed høyest prioritet: Figur 4.4.2 a) : En prioritetskø med 5 elementer usortert I Figur 4.4.2 a) består selve prioritetskøen av den grå delen av tabellen. Som vi ser er den usortert. Når tabellen er usortert kan nye verdier legges bakerst. Innlegging får derfor konstant orden. Hvis f.eks. tallet 9 legges inn, blir dette resultatet: Figur 4.4.2 b) : Prioritetskøen etter at 9 er lagt inn Men det å finne den som har best/høyest prioritet, dvs. det minste tallet, krever at vi må lete gjennom hele tabellen. Til det kan vi f.eks. bruke en metode som finner posisjonen til den minste verdien i et tabellintervall. Det betyr at det å ta ut en verdi får lineær orden. Hvis den verdien som her er tallet 3, tas ut av køen, tetter vi igjen «hullet» ved at det bakerste tallet (tallet 9) flyttes dit. Da får vi dette resultatet:

Delkapittel 4.4 En prioritetskø Side 3 av 8 Figur 4.4.2 c) : Prioritetskøen etter at 3 er tatt ut Det er enkelt å lage en implementasjon som bruker en usortert tabell som idé: public class UsortertTabellPrioritetsKø<T> implements PrioritetsKø<T> private T[] a; // en usortert tabell private int antall; // antall verdier i køen private Comparator<? super T> c; // en komparator // her skal konstruktører og metoder komme Programkode 4.4.2 a) Vi trenger i hvert fall to konstruktører - en som har en tabellstørrelse og en komparator som parametere, og en som kun har en komparator: public UsortertTabellPrioritetsKø(int størrelse, Comparator<? super T> c) a = (T[])new Object[størrelse]; // tabellens startstørrelse antall = 0; this.c = c; public UsortertTabellPrioritetsKø(Comparator<? super T> c) this(8,c); // bruker 8 som startstørrelse Programkode 4.4.2 b) Hvis datatypen T er en subtype til Comparable<T>, kan vi opprette en «naturlig» prioritetskø ved hjelp av en konstuksjonsmetode, dvs. ved hjelp av en statisk metode som returnerer en instans av klassen. Da er det datatypens «naturlige» ordning som brukes: public static <T extends Comparable<? super T>> PrioritetsKø<T> naturligordenkø() return new UsortertTabellPrioritetsKø<>(Comparator.naturalOrder()); Programkode 4.4.2 c) legginn legger nye elementer bakerst, men hvis tabellen er full, må den «utvides»: public void legginn(t verdi) if (verdi == null) throw new IllegalArgumentException("Nullverdi!"); if (antall == a.length) a = Arrays.copyOf(a,2*antall+1); // utvider a[antall++] = verdi; Programkode 4.4.2 d) // verdi legges inn bakesrt

Delkapittel 4.4 En prioritetskø Side 4 av 8 I metodene kikk og taut må vi først sjekke om køen er tom og deretter, hvis køen ikke er tom, lete etter verdien med best/høyest prioritet, dvs. den minste verdien. Letingen kan vi gjøre i en egen metode: public int antall() return antall; public boolean tom() return antall == 0; private int min() // finner posisjonen til den minste int m = 0; T minverdi = a[0]; for (int i = 0; i < antall; i++) if (c.compare(a[i],minverdi) < 0) m = i; minverdi = a[i]; return m; // returnerer posisjonen til den minste Programkode 4.4.2 e) Metodene kikk og taut blir da slik: public T kikk() if (tom()) throw new NoSuchElementException("Køen er tom!"); return a[min()]; // returnerer den minste public T taut() if (tom()) throw new NoSuchElementException("Køen er tom!"); int m = min(); T verdi = a[m]; antall ; a[m] = a[antall]; // posisjonen til den minste // tar vare på den minste verdien // reduserer antallet // tetter igjen ved å flytte den siste verdien a[antall] = null; // nuller for resirkulering return verdi; // returnerer den minste Programkode 4.4.2 f)

Delkapittel 4.4 En prioritetskø Side 5 av 8 Nå mangler kun nullstill av metodene fra grenesnittet PrioritetsKø: public void nullstill() while (antall > 0) a[ antall] = null; Programkode 4.4.2 g) Filen UsortertTabellPrioritetsKø.html inneholder hele klassen som vi nettopp har laget, med både konstruktører og metoder. Metoden legginn legger et nytt element bakerst. I taut-metoden (og i kikk-metoden) må det letes etter den minste verdien. Hvis køen har n elementer, trengs n - 1 sammenligninger for å finne den. Det betyr at den er av orden n eller av lineær orden. UsortertTabellPrioritetsKø Metode Operasjoner Orden legginn Et nytt element legges alltid bakerst. konstant taut Hvis det er n elementer, trengs n - 1 sammenligninger for å finne den minste. lineær Flg. eksempel viser hvordan klassen UsortertTabellPrioritetsKø kan brukes: char[] c = "VMUSXQCJKOATZPLDHIRBNFEGYW".toCharArray(); PrioritetsKø<Character> kø = UsortertTabellPrioritetsKø.naturligOrdenKø(); for (int i = 0; i < c.length; i++) kø.legginn(c[i]); while (!kø.tom()) System.out.print(kø.taUt() + " "); // Utskrift: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Programkode 4.4.2 h) Oppgaver til Avsnitt 4.4.2 1. Hva skjer med like verdier i UsortertTabellPrioritetsKø? Kommer de ut i samme rekkefølge som de ble lagt inn? Eller er det uforutsigbart hvilke rekkefølge de kommer i? 2. Metoden public boolean taut(t verdi) mangler kode. Lag kode for den. Hvis verdi ikke ligger i køen, skal den returnere false og true ellers. 3. Lag klassen public class UsortertLenketPrioritetsKø<T>. Klassen skal implementere grensesnittet PrioritetsKø<T> og bruke en usortert enkeltlenket pekerkjede som intern datastruktur. Da kan legginn legge verdien forrest. Men kikk og taut må lete etter den største verdien.

Delkapittel 4.4 En prioritetskø Side 6 av 8 4.4.3 En prioritetskø ved hjelp av en sortert tabell I Avsnitt 4.4.2 brukte vi en usortert tabell som intern datastruktur for en prioritetskø. Vi kan isteden bruke er sortert tabell: Figur 4.4.3 a) : En prioritetskø med 5 elementer sortert I Figur 4.4.3 a) består prioritetskøen av den grå delen av tabellen og er, som vi ser, sortert avtagende. Det betyr at den minste verdien ligger bakerst. I metodene kikk og taut er det bare å hente denne verdien og til det trengs én operasjon og dermed konstant orden. I metoden legginn blir det derimot mer arbeid. Vi må lete oss frem til rett sortert plass og samtidig rydde plass til den nye verdien. Hvis køen har n verdier trengs i gjennomsnitt ca. n/2 sammenligninger og n/2 forflyttninger. Antall sammenligninger kan imidlertid reduseres hvis vi bruker binærsøk, men det vil fortsatt bli n/2 forflyttninger. Det betyr at legginn-metoden blir av orden n eller av lineær orden. SortertTabellPrioritetsKø Metode Operasjoner Orden legginn Det må letes etter rett sortert plass og de til høyre må forskyves. lineær taut Den minste ligger alltid bakerst. konstant public class SortertTabellPrioritetsKø<T> implements PrioritetsKø<T> private T[] a; // en usortert tabell private int antall; // antall verdier i køen private Comparator<? super T> c; // en komparator public SortertTabellPrioritetsKø(int størrelse, Comparator<? super T> c) a = (T[])new Object[størrelse]; // tabellens startstørrelse antall = 0; this.c = c; public SortertTabellPrioritetsKø(Comparator<? super T> c) this(8,c); // bruker 8 som startstørrelse public static <T extends Comparable<? super T>> PrioritetsKø<T> naturligordenkø() return new SortertTabellPrioritetsKø<>(Comparator.naturalOrder()); // De øvrige metodene skal inn her. Programkode 4.4.3 a)

Delkapittel 4.4 En prioritetskø Side 7 av 8 I metoden legginn bruker vi samme teknikk som i innsettingssortering: public void legginn(t verdi) if (antall == a.length) a = Arrays.copyOf(a, 2*antall+1); int i = antall 1; // vi sammenligner og flytter for (; i >= 0 && c.compare(verdi,a[i]) > 0; i ) a[i+1] = a[i]; a[i+1] = verdi; antall++; public int antall() return antall; public boolean tom() return antall == 0; public T kikk() if (tom()) throw new NoSuchElementException("Køen er tom!"); return a[antall 1]; public T taut() if (antall == 0) throw new NoSuchElementException("Køen er tom!"); T minverdi = a[ antall]; a[antall] = null; return minverdi; // tar vare på den bakerste // klargjør for resirkulering // returnerer den største public void nullstill() while (antall > 0) a[ antall] = null; Programkode 4.4.3 b) Filen SortertTabellPrioritetsKø.html inneholder hele klassen med konstruktører og metoder. Oppgaver til Avsnitt 4.4.3 1. Kjør Programkode 4.4.2 h) med SortertTabellPrioritetsKø. 2. Hva skjer med like verdier i SortertTabellPrioritetsKø? Tas de ut i samme rekkefølge som de ble lagt inn? Eller er uttaksrekkefølgen uforutsigbar? Kan du eventuelt kode det om slik at like verdier tas ut i samme rekkefølge som de ble lagt inn? 3. Metoden public boolean taut(t verdi) mangler kode. Lag kode for den. Hvis verdi ikke ligger i køen, skal den returnere false og true ellers. 4. Lag klassen public class SortertLenketPrioritetsKø<T>.

Delkapittel 4.4 En prioritetskø Side 8 av 8 4.4.4 Sortering ved hjelp av en prioritetskø I en prioritetskø tas verdiene ut etter prioritet, dvs. at ved hvert uttak er det den med best eller høyest prioritet som velges. Det er verdienes ordning som bestemmer prioriteten. Den som etter ordningen er «minst», har best eller høyest prioritet. Dette betyr at hvis vi legger inn en samling verdier i en prioriteskø, får vi verdiene ut i stigende sortert rekkefølge. I Programkode 4.4.2 h) ble bokstaver, i usortert rekkefølge, lagt inn og utskriften viser at de kommer i sortert rekkefølge. Bruker vi en UsortertTabellPrioritetsKø vil taut-metoden hver gang finne den minste i tabellen, dvs. at dette er samme teknikk som i utvalgssortering. Hvis vi isteden bruker den andre prioritetskøen, dvs. en SortertTabellPrioritetsKø, vil legginn-metoden hver gang legge nye verdier på rett sortert plass i tabellen, mens taut-metoden tar ut den bakerste. Med andre ord er dette samme teknikk som i innsettingssortering. Som nevnt til slutt i Avsnitt 4.4.1 finnes det en mye «smartere» teknikk for en prioriteskø enn det å bruke en usortert eller en sortert tabell. Det går ut på å bruke en heap, dvs. et komplett minimumstre - se Avsnitt 5.3.3. Ideen der kan også brukes til sortering og da kalles det heapsortering. 4.4.5 PriorityQueue i java.util Klassen PriorityQueue er deklarert slik: public class PriorityQueue<T> extends AbstractQueue<T> implements java.io.serializable Denne klassen bruker en minimumsheap (et komplett minimumstre) som intern datastruktur. Bruk av en slik datastruktur for en prioritetskø tas opp i Delkapittel 5.3. De metodene som svarer til våre metoder legginn, kikk og taut er add/offer, element/peek og remove/poll. Her er et eksempel på bruk av klassen PriorityQueue. Comparator<Integer> c = Comparator.naturalOrder(); // en komparator PriorityQueue<Integer> prkø = new PriorityQueue<>(5,c); // plass til 5 int[] a = 3,5,2,4,1; for (int k : a) prkø.offer(k); // legger inn while (!prkø.isempty()) System.out.print(prkø.poll() + " "); // tar ut // Utskrift: 1 2 3 4 5 Copyright Ulf Uttersrud, 2015. All rights reserved.