Föreläsning jan 15 v3, jan 22 v4. GT Chapter 6, GT Chapter 7 Hemuppgifter redovisning v4, v5. Planer för läsperiod 3. I GT kap 7 kommer vi att läsa I GT kap 8 kommer vi att läsa I GT kap 9 kommer vi att läsa I GT kap 10 kommer vi att läsa
285 <= sida < 316. 333 <= sida < 362 , dvs 8.1, 8.2, 8.3, 8.4 och 8.5. 379 <= sida < 393, dvs 9.1. 447 <= sida < 486. Dock ej avsnitt 10.4 478 <= sida <=479
Dessutom skall vi lära oss I/O (Input/Output) i Java och förhoppningsvis ha en avslutande repetitionsföreläsning. GT kap 11 och GT kap 12 ingår inte i kursen. Det är ingen katastrof om man råkar lära sig något av det överhoppade, det mesta av detta ingår i kommande kurser, främst ADK-kusen (Algoritmer-Datastrukturer-Komplexitet).
GT Kapitel 6
analogt med boken. Vi har kvar implementationerna i slutet på kapitlet. Klassdiagram för EulerTour med ärvande klass PrintExpressionTour: EulerTour protected InspectableBinaryTree tree; public Object execute(BinaryTree T) protected Object eulerTour(Position p) protected void visitExternal(Position p, TraversalResult r) protected void visitLeft(Position p, TraversalResult r) protected void visitBelow(Position p, TraversalResult r) protected void visitRight(Position p, TraversalResult r) protected TraversalResult initResult() protected Object result(TraversalResult r)
PrintExpressionTour public Object execute(BinaryTree T) protected void visitExternal(Position p, TraversalResult r) protected void visitLeft(Position p, TraversalResult r) protected void visitBelow(Position p, TraversalResult r) protected void visitRight(Position p, TraversalResult r)
GT Kapitel 7
analogt med boken
Hemuppgifter redovisning v4 . C = 1, 4, 5 B= 1, 3, 4, 5 A = 1, 2, 4, 5, 6 Inlämning under läsperiod 3 senast måndagar klockan 12.00. 1. CBA-hemuppgift : (delvis P-6.3 GT page 281) Deluppgift: Komplettera bokens text så att klassen LinkedBinaryTree fungerar (på en egen katalog). Alla behövliga gränsnitt, dvs interface Position och alla interface från och med InspectableContainer till och med BinaryTree i höger del av figure 6.11 GT sid 248, och bokens text till LinkedBinaryTree och BTNode finns på /info/inda01/GTCh6/. Det mesta finns också på nätet, varifrån jag kopierat koden. Jag har dock kompletterat BinaryTreegränssnittet med två metoder (som redan finns implementerade i bokens LinkedBinaryTree) : public interface BinaryTree extends InspectableBinaryTree, PositionalContainer { /** Transform v from an external into an internal node by creating two new external nodes and making them the left and right children of v, respectivley. */ public void expandExternal(Position v) ; /** Remove the external node w together with its parent v, replacing v with the sibling of w. */ public void removeAboveExternal(Position v); }
Om man försöker kompilera upptäcker man att metoden positions() innehåller begrepp som är oidentiferade. Skriv om metodens "kropp" så att att metoden vid anrop enbart slänger ett RuntimeException med texten "positions()
in class LinkedBinaryTree not implemented yet"
Gör på motsvarande sätt med de andra metoderna (iterator-returnerare) som saknas. Om allt fungerar skall man nu kunna köra det givna (av mig skrivna) programmet UsePedigree (studera programmet!) som också finns på katalogen som angetts ovan. Körresultat: Antavla : Rut Bo Adam Eva Siv Per Kersti
Utskriften visar Ruts härstammning, (far tv, mor t.h), som finns i detta binär träd, en antavla eller stamtavla (engelska pedigree) som vi också kan rita så här (för en gångs skull ritar vi träd rättvänt!): Adam Bo
Eva
Per
Kersti
Siv
Rut Ruts mormor är alltså Kersti, Ruts far heter Bo osv.
Deluppgift: Komplettera programmet UsePedigree så att man gång på gång kan ge en persons namn och få reda på personens relation med personen i roten. Körexempel : Ge namnet Kersti Kersti är Ge namnet Bo Bo är far Ge namnet Pia Pia finns Ge namnet
på den person vars relation till Rut du vill veta (Sluta ge vagnretur) : mormor till Rut på den person vars relation till Rut du vill veta (Sluta ge vagnretur) : till Rut på den person vars relation till Rut du vill veta (Sluta ge vagnretur) : ej i släktträdet på den person vars relation till Rut du vill veta (Sluta ge vagnretur) :
Du kan utgå ifrån att varje namn bara finns på max ett ställe i trädet. Programmet använder förstås svenska språkets smarta och rekursiva sätt att benämna anfäder och anmödrar. Det är OK att i större träd än det ovanstående få utskrifter som mormorfarfarmor osv. Om du gör A-uppgift 6 så får du inte lösa denna uppgift med hjälp av Euler-tur-mallen. PS. Problemet löses lämpligen med rekursion. Om du blivit så van att programmera OO-mässigt att du ogillar att skriva klassmetoder kan du gå via en klass, kallad Pedigree t ex. DS. 2. A-hemuppgift : (P-6.2 GT page 281) Implementera gränssittet BinaryTree med en vektor med klassen VectorBinaryTree . Använd java.util.Vector. Du ska kunna testköra din implementatiion med UsePedigree från uppgift 1, det enda som ska behöver ändras är BinaryTree pg = new LinkedBinaryTree(); till BinaryTree pg = new VectorBinaryTree();
De iterator-returnerande metoderna i gränssnittet som man kunde implementera med att slänga undantag kan även nu "implementeras" på samma sätt. Tips: Det står ju en del i avsnitt GT 6.4.1. Jag är lite osäker på hur svårt ni tycker detta är, man måste nog väl förstå definitionerna i kap 5 och kapitel 6 i GT för att lösa uppgiften. Den som vill tänka helt själv kan ju sluta läsa här. Vi måste ju ha ett Position-begrepp för våra träd-element i vektorn. I avsnitt 5.3.3 resoneras om två olika sätt att lösa motsvarande problem för vektorimplementerade sekvenser. Det första sättet som föreslås i första stycket på sid 209 avfärdas dock för sekvenser, eftersom positionerna "inte hänger med" vid t ex insertFirst. I våra träd ändras dock aldrig positioner, de bara tillkommer nya när trädet växer "ytterst" eller försvinner positioner när trädet "ansas" genom att man beskär trädet "ytterst", varför även första sättet är ganska OK såvitt jag förstår. Det är nog också det som avses med meningen "That is, each position object v is simply a "wrapper" for the index p(v) into the vector S." på sid 264. Jag använde det första sättet för mitt vektorbaserade binära träd. Jag skrev en klass VectorPosition som implementerar Position och i någon mån ersätter BTNode i implementeringen med länkning. Genom att förse VectorPosition med lämpliga metoder blev koden för VectorBinaryTree rätt lik den givna koden för LinkedBinaryTree.
3. B-hemuppgift : Skriv ut antavlan i UsePedigree med hjälp av en Euler-tur, dvs designmönstret 6.3.5 "Templet Method Pattern" istället för med den givna metoden public static void preorderPrint(..). Utskriften skall bli densamma, dvs Antavla : Rut Bo Adam Eva Siv Per Kersti På /info/inda01/GTCh6/ finns bokens klass EulerTour (GT sid 260) och hjälpklassen TraversalResult. Man skall alltså skriva en subklass PrintPedigree till EulerTour.Testkörningen sker genom att i UsePedigree instansiera ett PrintPedigree-objekt och sedan anropa execute i detta objekt. Har du gjort A-uppgift 2 så kolla att det fungerar också med VectorBinaryTree. Tips: För att hålla reda på nivån (och därmed hur många blanktecken som skall föregå ett namn) använder jag inte alls TraversalResult utan har istället en instansvariabel i mitt PrintPedigreeobjekt som jag räknar upp eller ned på lämpligt sätt. 4. CBA-hemuppgift : Implementera metoden positions() i LinkedBinaryTree på riktigt, dvs så att den retunerar en PositionIterator istället för att slänga ett undantag som vi gjorde i uppgift 1. Om man gör som boken antyder måste man skriva en metod inorderPositions och en klass ArrayPositionIterator som implementerar PositionIterator. Provkör genom att skriva en komplettering av UsePedigree som använderanvända en PositionIterator för att få få denna utskrift Alla elementen med PositonIterator : Rut Bo Adam Eva Siv Per Kersti Har du gjort A-uppgift 2 så gör även samma sak för VectorBinaryTree. Min lösning blev identisk med lösningen för LinkedBinaryTree. 5. CBA-hemuppgift : Kör UNIX-kommando >du på din startkatalog. Katalogerna och filerna bildar ett träd. Hur traverseras trädet? Finns det anledning att städa bland dina filer?
6. A-hemuppgift : Lös andra deluppgiften i uppgift 1, att finna någon persons relation med personen i trädets rot, med hjälp av en Euler-tur, dvs med designmönstret 6.3.5 "Templet Method Pattern" Utskriften skall bli densamma, t ex : Ge namnet på den person vars relation till Rut du vill veta (Sluta ge vagnretur) : Kersti Kersti är mormor till Rut
På /info/inda01/GTCh6/ finns bokens klass EulerTour (GT sid 260) och hjälpklassen TraversalResult. Man skall alltså skriva en subklass till en EulerTour.Testkörningen sker genom att i UsePedigree instansiera ett subklass-objekt och sedan anropa execute i detta objekt. Har du gjort A-uppgift 2 så kolla att det fungerar också med VectorBinaryTree. Tips: Jag lät subklassens execute-metod ha denna signatur för att föra över nyckeln till en instansvariabel i subklass-objektet: public Object execute(BinaryTree T, String ikey)
Hemuppgifter redovisning v5 . C = 1, 2 B= 2, 3, 4 A = 2, 3, 4, 5 Inlämning under läsperiod 3 senast måndagar klockan 12.00. Allmänt om uppgifterna : I boken byggs implementationer av mer avancerade ADT upp med hjälp av implementationer av enklare ADT, man kan alltså tänka sig att en DLPriorityQueue skulle byggas på en List från kapitel 5 och ett HeapTree med BinaryTree från kap 6. Men till slut blir det nog enklare (och mindre kod) att direkt bygga en ADT från "scratch", vilket jag tänkt att vi gör i sorteringsuppgifterna denna vecka. För enkelhets skull är nycklarna och elementen i de "Items", dvs nyckel-element-par, vi skall sortera ofta strängar med samma innehåll. När vi skapar implementationer av prioitetsköer, t ex DLPriorityQueue i uppgift 1 och HeapPriorityQueue i uppgift 4 skall vi som argument till konstruktorn ge ett objekt som implementerar gränsnittetet Comparator. Det finns ett förslag till detta gränssnitt i boken, men också ett annat i java.util. Skillnaderna diskuteras i GT överst på sidan 295, och jag tycker att vi använder java.bibliotekets version. Många klasser i Javabiblioteket, bl a String, implementerar ytterligare ett annat gränssitt Comparable, vilket jag utnyttjat i MyComparator. Jag ger ett MyComparatorobjekt till mina proritetsköer som används på nycklarna vid sorteringarna för att avgöra ordningen mellan "Items": import java.util.*; class MyComparator implements Comparator{
// implements java.util.Comparator
public int compare(Object a, Object b) { if (a instanceof Comparable || b instanceof Comparable ) { return ((Comparable) a).compareTo((Comparable) b); } else { throw new RuntimeException("compare() in MyComparator," + " arguments must be Comparable"); } } }
Körresultaten i programmen är ofta av denna typ: /*Körresultat : ...>java ....Sort... bertil david adam ludvig martin zero rudolf adam bertil david ludvig martin rudolf zero */
1. C-hemuppgift : Implementera en prioritetskö med en dubbellänkad lista (som hålls sorterad) i en klass DLPriorityQueue som skall implementera gränsnittet PriorityQueue. Gränssittet finns givet på /info/inda01/GTCh7, tillsammans med DLItemNode, och Item som man också har glädje av. Med hjälp av implementationen kan man göra en insättningssortering med detta program (finns också på info/inda01/GTCh7 ), som alltså kan användas som test på att implementationen är riktig: import java.util.*; public class PriorityQueueSort { public static void main(String [] arg) { // PriorityQueue p = new HeapPriorityQueue(new MyComparator()) ; PriorityQueue p = new DLPriorityQueue(new MyComparator()) ; for (int i = 0; i < arg.length; i = i+1) { p.insertItem(arg[i], arg[i]); } for (int i = 0; i < arg.length; i = i+1) { System.out.println(p.removeMin()); } } }
Tips: Min favoritstruktur är dubbellänkade noder, men till skillnad från boken med samma nod som både header och trailer, dvs vi får en cirkulär dubbellänkad lista med en vaktpost (sentinel) som är både "header" och "trailer". Till vänster en bild på strukturen när den är tom, till höger med tre element: 0
3
tom prioitetskö
prioitetskö med 3 element vaktpost, sentinel
vaktpost, sentinel
david adam
adam
david bertil
bertil
När du skriver insertItem kommer du antagligen att skriva en snurra som söker efter första elementet som har större nyckel, dvs du traskar vidare i kedjan så länge examinerat element har för liten nyckel. Avbrottsvillkoret i snurran kan skrivas enklare om man fyller vaktposten med nyckeln i det element som man skall stoppa in i kedjan.
2. CBA-hemuppgift : Implementera en "på-plats"sortering, (In-place-sort). Du kan välja mellan att göra en bubbelsortering eller en insättningsortering genom att kommentera bort de andra sorterarna i nedanstående testprogram. Inget av dessa sorteringssätt är något vidare val för på-plats-sortering, vilket däremot "in-place-heapsort" är, vilket är en senare uppgift. Detta testprogram (på /info/inda01/GTCh7) kan används för att kontrollera implementationen: import java.util.*; public class SortInPlace { // finns på/info/inda01/GTCh7 public static void main(String [] arg) { Vector v = new Vector(); for (int i = 0; i < arg.length; i = i+1) { v.add(new JustItem(arg[i], arg[i])); } //Sorter p = new HeapSort(new MyComparator(), v); //Välj sorterare!!!!! Sorter p = new BubbelSort(new MyComparator(), v); //Sorter p = new InsertionSort(new MyComparator(), v); p.sort(); for (int i = 0; i < v.size(); i = i+1) { System.out.println((String) ((Item) (v.get(i))).element()); } } } public interface Sorter { public void sort(); }
// Gränssnittet Sorter (på /info/inda01/GTCh7)
Tips: Det är alltså java.util.Vector v som blir sorterad. Uppgiften är att skriva klassen Bubbel sort eller klassen InsertionSort som skall implementera interface Sorter, dvs klassen skall ha metoden sort(). Ett Sorter-objekt får en vektor och en komparator när det skapas. Vektorn kan sedan sorteras med sort(), varvid komparatorn bestämmer vad som menas med "mindre än".
3.BA-hemuppgift : Det kan ju vara roligt att se vad som händer under på-plats-sorteringen i uppgift 2. Följande givna program lägger in den sekvens items som skall sorteras dels i en vanlig vektor v, dels i en FinalRankRankVector frrv. Märk att "items" är gemensamma! Därefter sorteras v. Med hjälp av v kan vi nu byta elementen i alla items så att vi i stället har slutgiltiga rangen som elementvärde. Om vi nu sorterar frrv så skrivs hela frrv ut varje gång vi anropar set, pga att set är omdefinerad för FinalRankRankVector. Om du kombinerar SortInPlace1 med den sorterarare du gjort i förgående uppgift skall du kunna provköra för att få frrv utskriven gång på gång. Utskriften består av varje items | . import java.util.*; public class SortInPlace1 { // finns på/info/inda01/GTCh7 public static void main(String [] arg) { // Move items to be sorted to v and frrv Vector v = new Vector(); Vector frrv = new FinalRankRankVector(); for (int i = 0; i < arg.length; i = i+1) { Item ii = new JustItem(arg[i], arg[i]); frrv.add(ii); v.add(ii); } // Get a sorter for v, and sort //Sorter p = new InsertionSort(new MyComparator(), v); //Välj sorterare!!!!! Sorter p = new BubbelSort(new MyComparator(), v); //Sorter p = new HeapSort(new MyComparator(), v); p.sort(); System.out.println("Result of sort:"); for (int i = 0; i < v.size(); i = i+1) { System.out.println((String) ((Item) (v.get(i))).element()); } // Change item elemnets to final rank for (int i = 0; i < v.size(); i = i+1) { ((Item) (v.get(i))).setElement(new Integer(i)); } System.out.println("finalrankrankvector :"); for (int i = 0; i < frrv.size(); i = i+1) { System.out.println((Integer) ((Item) (frrv.get(i))).element()); } // Sort frrv, which is a // FinalRankRankVector => vector will be shown at every set //p = new InsertionSort(new MyComparator(), frrv);//Välj sorterare!!!!! p = new BubbelSort(new MyComparator(), frrv); //p = new InsertionSort(new MyComparator(), frrv); p.sort(); } }
import java.util.*; public class FinalRankRankVector extends Vector { // finns på/info/inda01/GTCh7 public void show() { for (int i = 0; i < size() ; i = i+1) { Item ii = (Item) get(i); if ( ii != null) { System.out.print(" |" + i + " " + ii.key() + " " + ii.element()); } else { System.out.print(" |" + i + " "); } } System.out.println(); } public Object set(int index, Object oitem) { Object result = super.set(index, oitem); show(); return result; }
//overrides inherited set
}
Uppgiften är att komplettera FinalRankRankVector så att man även får se sorteringen i en JavaFrame. Provkör klassfilen /info/inda01/GTCh7/SortInPlace1 så får du se min bubbelsortering "live in action". T ex .... >java SortInPlace1 bertil adam david tore sverker erik eva sven zero per filip
Gör teminalfönstret smalt och lägg de vid sedan så att fönstret inte skymmer "framen". Gör terminalfönstret aktivt och ge vagnreturer, så får man ser hur elementen bubblar på tills allt är sorterat, dvs man får en diagonal i fönstret. Ett element skrivs alltså ut på (rang, slutgiltig rang)-stället i ett n x n rutmönster, där n = v.size(); Tips: Jag försåg min FinalRankRankVector med en Frame FinalRankRankFrame (storleken 800 pixel * 800 pixel) som använder GridLayout och har en matris java.Label []. Metoden show() i FinalRankRankVectora kompletteras så att den även skriver ny text i "framen".
4.BA-hemuppgift : Implementera (direkt, utan att gå via något ADT binärt träd som boken gör) en prioritetskö med en heap (i en java.util.Vector) med en klass HeapPriorityQueue som skall implementera gränsnittet PriorityQueue. Gränsittet finns givet på /info/inda01/GTCh7, tillsammans med bokens Item, som man ju har glädje av. Programmet kan testköras med samma testprogram som uppgift1, om man skriver PriorityQueue p = new HeapPriorityQueue(new MyComparator()) ;
i stället för PriorityQueue p = new DLPriorityQueue(new MyComparator()) ;
Märk finessen med "att programmera mot ett interface"!. Programmet gör nu förstås en "heap"sortering. Delar av texten för uppgift 1 är relevant för denna uppgift också, förutom bokens avsnitt 7.3.2 på sid 314.
5. A-hemuppgift : Implementera en "på-plats"heap-sortering, (In-place heap-sort). Testprogrammmet i uppgift 2 kan ändras så att man kan testa denna uppgift. Även testprogrammmet i uppgift 3 och din lösning till uppgift 3 skall kunna fungera med lösningen till denna uppgift, dvs du skall kunna se din "på-plats"heapsortering "live". Tips: Man kan säkert skriva HeapSort genom att bygga om HeapPriorityQueue, vilket är OK. Jag har dock löst problemet så här genom arv (mer intellektuell utmaning kanske): PriorityQueue HeapPriorityQueue protected Comparator comp protected Vector v protected int size .... public void insertItem(Object k, Object e) ... /* m fl */ Sorter
HeapSort
:
public HeapSort(Comparator ic, Vector iv) public void sort() private void insertItem(Item ii)
Vid arv behöver man en "omvänd komparator" vilket man kan få så här: class MyInvertedComparator implements Comparator{ private Comparator c; public MyInvertedComparator(Comparator ic) { c = ic; } public int compare(Object a, Object b) { return -c.compare(a,b); } }