Post on 08-Jun-2015
1
Hoofdstuk 20:
GEGEVENSSTRUCTUREN
2
H 20. GEGEVENSSTRUCTUREN
1. INLEIDING
• Reeds gezien : gegevensstructuren met een vaste lengte
- Eéndimensionele arrays - Meerdimensionele arrays
3
H 20. GEGEVENSSTRUCTUREN
1. INLEIDING
• H 20: Dynamische gegevensstructuren
– Variabele lengte: lengte kan kleiner en groter worden tijdens runtime.
– Enkele dynamische gegevensstructuren:
• Gelinkte lijsten• Stacks• Queues• Binaire bomen
4
2. ZELF-REFERENTIE KLASSE
• Zelf-referentie klasse– Bevat een instantie-variabele dat refereert
naar een object van dezelfde klasse. Bv: class Node { // Node = knoop
private int data; private Node nextNode; public Node (int data) {…} // constructor public void setData (int data) {…} public int getData() {…} public void setNext (Node next) {…} public Node getNext() {…} }
5
2. ZELF-REFERENTIE KLASSE
• private Node nextNode;
De instantie-variabele nextNode wordt een "link" genoemd.
– nextNode verbindt ("links") een Node object met een ander Node object.
6
2. ZELF-REFERENTIE KLASSE
Programma’s kunnen "zelf-referentie objecten" verbinden. Zo kan er een gegevensstructuur gecreëerd worden zoals lijsten, queues, stacks en bomen.
Bv:
15 10
7
3. DYNAMISCHE GEHEUGENTOEWIJZING
• Dynamische geheugentoewijzing
– Als we objecten aan de dynamische gegevensstructuur toevoegen, verzoeken we het systeem om meer geheugen.
– Als we een object niet meer nodig hebben, geven we de ruimte aan het systeem terug:
• JAVA heeft een automatische garbage collection.
8
3. DYNAMISCHE GEHEUGENTOEWIJZING
• Declaratie en creatie van nodeToAdd
Node nodeToAdd = new Node ( 10 ); - De expressie "new Node (10)" kent
geheugen toe om het Node object te bewaren en geeft een referentie van het object terug. Deze referentie wordt toegekend aan nodeToAdd.
- Indien geheugen tekort dan geeft deze expressie OutOfMemoryError terug.
9
4. GELINKTE LIJSTEN
• Gelinkte lijst– is een lineaire (sequentiële) collectie van
zelf-referentie objecten (= nodes = knopen).
– Knopen kunnen toegevoegd en verwijderd worden aan het begin, midden of eind van de lijst.
– Elke knoop bevat een referentie naar de volgende, alleen de laatste knoop heeft niks om naar te verwijzen de laatste knoop bevat null.
10
4. ENKEL GELINKTE LIJST
firstNode
...H D Q
lastNode
– Een object bevat de referentie van de eerste knoop van de gelinkte lijst (firstNode). Het object kan ook de referentie van de laatste knoop bevatten (lastNode).
11
4. DUBBEL GELINKTE LIJST
firstNode
...H Q
lastNode
Bv: class Node { private Node previousNode;
private int data; private Node nextNode;
D
12
4. VOORBEELD VAN EEN ENKEL GELINKTE LIJST• Voorbeeld:
Drie domeinklassen: ListNode, List en EmptyListExceptionApplicatie: ListTest
• ListNode is een zelf-referentie klasse. De objecten van deze klasse zijn de knopen van de gelinkte lijst.
• List zal verwerkingen met de gelinkte lijst uitvoeren: toevoegen en verwijderen van knopen.
• EmptyListException werpt een exception indien er een poging wordt gedaan om een knoop uit een lege lijst te verwijderen.
13
4. KLASSE ListNode class ListNode { private Object data; private ListNode nextNode; // constructors ListNode( Object object ) { this( object, null ); } ListNode( Object object, ListNode node )
{ data = object; nextNode = node; } // accessors en mutators Object getData() { return data; } void setData(Object data) { this.data = data;} ListNode getNext() { return nextNode; } void setNext(ListNode node) { nextNode = node; } } // einde klasse ListNode
De zelf-referentie klasse ListNode bevat "data" en de link "nextNode". "data" is een referentie naar een object van de klasse Object, dus kan "data" refereren naar gelijk welk object.
14
4. KLASSE List • Klasse List:
Attributen: firstNode, lastNode, name Constructors
In de constructors wordt er een naam aan de gelinkte lijst toegekend.
Methodes : isEmpty : controleren indien de lijst al dan niet leeg is;print : de inhoud van de gelinkte lijst wordt teruggegeven als string;insertAtFront : knoop vooraan in de lijst toevoegen;insertAtBack : knoop achteraan in de lijst toevoegen;removeFromFront : knoop vooraan in de lijst verwijderen;removeFromBack : knoop achteraan in de lijst verwijderen.
15
4. KLASSE List : instantie-variabelen en constructors
public class List { private ListNode firstNode; private ListNode lastNode; private String name;
// constructors public List() { this( "list" ); } public List( String listName ) { name = listName; }
"firstNode" referereert naar de eerste knoop en "lastNode" refereert naar de laatste knoop van de gelinkte lijst. “name" zal de naam van de gelinkte lijst bijhouden. De attributen "firstNode" en "lastNode" worden automatisch op null gezet.
16
4. KLASSE List : accessors en mutators
protected ListNode getFirstNode(){ return firstNode; }
protected ListNode getLastNode(){ return lastNode; }
public String getName(){ return name; }
protected void setFirstNode(ListNode node){ firstNode = node; }
protected void setLastNode(ListNode node){ lastNode = node; }
public void setName(String name) { this.name = name; }
17
4. KLASSE List: methode isEmpty
// controleert indien de gelinkte lijst al dan niet leeg ispublic synchronized boolean isEmpty(){ return firstNode == null; // return true indien de lijst // leeg is}
• De methode isEmpty is een "predicate method". Deze methode test een conditie van een object zonder dat object te wijzigen.• synchronized om zeker te zijn dat de toestand niet wijzigt tijdens de uitvoering van deze methode.
18
// de inhoud van de knopen weergevenpublic synchronized String print(){ if ( isEmpty() ) return "Empty " + name ; StringBuffer buffer = new StringBuffer(); ListNode current = firstNode; // zolang niet einde lijst wordt de inhoud van de // huidige knoop (= current) weergegeven. Vervolgens wordt // de huidige knoop gelijkgesteld aan de volgende knoop while ( current != null ) { buffer.append( current.getData().toString() + " " ); current = current.getNext(); } return buffer.toString();} // einde methode print
4. KLASSE List: methode print
19
4. KLASSE List : methode insertAtFront
// voegt een knoop toe aan het begin van de gelinkte lijstpublic synchronized void insertAtFront( Object insertItem ){ if ( isEmpty() ) firstNode = lastNode = new ListNode( insertItem ); else firstNode = new ListNode( insertItem, firstNode );}
• Indien de gelinkte lijst leeg is dan zal firstNode en lastNode naar de nieuwe knoop wijzen. • Indien de lijst niet leeg is dan zal firstNode naar de nieuwe eerste knoop wijzen.
20
4. KLASSE List : methode insertAtFront• Schematische voorstelling van insertAtFront:
Indien de gelinkte lijst leeg is dan zal firstNode en lastNode naar de nieuwe knoop wijzen. firstNode
10
10
new Listnode
firstNode
new Listnode
(a)
(b)
lastNode
lastNode
21
4. KLASSE List : methode insertAtFront• Schematische voorstelling van insertAtFront
Indien de gelinkte lijst niet leeg is dan zal firstNode naar de nieuwe knoop wijzen.
firstNode
7 11
12
7 11
12
new Listnode
firstNode
new Listnode
(a)
(b)
lastNode
lastNode
22
4. KLASSE List : methode insertAtBack// voegt een knoop toe aan het einde van de lijst
public synchronized void insertAtBack( Object insertItem ){ if ( isEmpty() ) firstNode = lastNode = new ListNode( insertItem ); else // lastNode's nextNode zal naar de nieuwe node wijzen { lastNode.setNext(new ListNode( insertItem )); lastNode = lastNode.getNext();}}
• Indien de gelinkte lijst leeg is dan zal firstNode en lastNode naar de nieuwe knoop wijzen.
• Indien de lijst niet leeg is dan zal lastNode's nextNode naar de nieuwe knoop wijzen. M.a.w. de knoop die op de laatste plaats stond wijst nu naar de nieuwe knoop. Vervolgens wijst lastNode naar de nieuwe knoop.
23
4. KLASSE List : methode insertAtBack
• Schematische voorstelling van insertAtBack: Indien de gelinkte lijst leeg is dan zal firstNode en lastNode naar de nieuwe knoop wijzen.
firstNode
2
2
new Listnode
firstNode
new Listnode
(a)
(b)
lastNode
lastNode
24
4. KLASSE List : methode insertAtBack• Schematische voorstelling van insertAtBack:
Indien de lijst niet leeg is dan zal lastNode's nextNode naar de nieuwe knoop wijzen. Vervolgens zal lastNode naar de nieuwe knoop wijzen.
firstNode
12
new Listnode(a)
(b) firstNode new Listnode
lastNode
lastNode
7 11 5
12 7 11 5
25
4. KLASSE List : methode removeFromFront// verwijdert de eerste knoop van de gelinkte lijst
public synchronized Object removeFromFront() throws EmptyListException{ if ( isEmpty() ) // exception wordt gegooid indien de // gelinkte lijst leeg is throw new EmptyListException( name ); Object removedItem = firstNode.getData(); // de data van de // eerste knoop in de lijst wordt toegekend aan removedItem
// firstNode wordt gewijzigd. lastNode wordt gewijzigd // indien de lijst maar één knoop bevat. if ( firstNode == lastNode ) firstNode = lastNode = null; else firstNode = firstNode.getNext(); return removedItem; // de data van de verwijderde knoop // wordt teruggegeven. } // einde methode removeFromFront
26
4. KLASSE List : methode removeFromFront• Schematische voorstelling van removeFromFront
: Indien de gelinkte lijst één knoop bevat dan zal na deze methode firstNode en lastNode aan null worden toegekend.
firstNode
5
firstNode
removeItem
(b)
ab)
lastNode
lastNode
5
27
4. KLASSE List : methode removeFromFront
• Schematische voorstelling van removeFromFront : Indien de lijst meer dan één knoop bevat dan zal firstNode naar de tweede knoop wijzen.
firstNode
12
(a)
(b)
7 11 5
12 7 11 5
lastNode
lastNode
firstNode
removeItem
28
4. KLASSE List : methode removeFromBack// verwijdert de laatste knoop van de gelinkte lijst
public synchronized Object removeFromBack() throws EmptyListException{ if ( isEmpty() ) // exception wordt gegooid indien de // gelinkte lijst leeg is
throw new EmptyListException( name ); Object removedItem = lastNode.getData(); // de data van de // laatste knoop in de lijst wordt toegekend aan removedItem // lastNode wordt gewijzigd. firstNode wordt gewijzigd // indien de lijst maar één knoop bevat.
if ( firstNode == lastNode ) firstNode = lastNode = null; else
29
4. KLASSE List : methode removeFromBack
// de lijst bevat meer dan één knoop :
{ // de nieuwe laatste knoop zoeken (m.a.w. de voorlaatste // knoop zoeken
ListNode current = firstNode; // de gelinkte lijst doorlopen totdat de current.nextnode // (= de volgende knoop in de lijst) gelijk is aan lastnode
while (current.getNext() != lastNode ) current = current.getNext(); lastNode = current; // current is de nieuwe laatste knoop current.setNext(null); // vermits current de nieuwe // laatste knoop is, is er geen volgende knoop meer
} return removedItem; // de data van de verwijderde knoop // wordt teruggegeven. } // einde methode removeFromBack
30
4. KLASSE List : methode removeFromBack• Schematische voorstelling van
removeFromBack : Indien de gelinkte lijst één knoop bevat dan zal na deze methode firstNode en lastNode aan null worden toegekend.
firstNode
7
firstNode
removeItem
(b)
ab)
lastNode
lastNode
7
31
4. KLASSE List : methode removeFromBack
• Schematische voorstelling van removeFromBack : Indien de lijst meer dan één knoop bevat dan zal lastNode naar de nieuwe laatste knoop wijzen.
12
(a)
(b)
lastNode
7 11 5
12 7 11 5
lastNode
firstNode
removeItem
firstNode current
32
4. KLASSE List : synchronized
Als we de klasse binnen één thread gebruiken, gaat alles goed, maar wat gebeurt er wanneer meerdere threads de methoden op precies (of bijna) dezelfde tijd kunnen benaderen?
Stel bvb. dat één thread een knoop verwijdert en dat tegerlijkertijd een ander de inhoud opvraagt. Moet de geretourneerde inhoud, de verwijderde knoop, al dan niet bevatten? Eigenlijk worden de gegevens onbetrouwbaar.
Door het sleutelwoord synchronized te gebruiken, weten we zeker dat slechts één thread tegerlijkertijd een methode benadert. Elke andere thread moet wachten totat het object weer vrij is.
33
4. KLASSE EmptyListExceptionpublic class EmptyListException extends RuntimeException
{ // constructors public EmptyListException() { this( "List" ); // roept de constructor met één // parameter, van deze klasse, op } public EmptyListException( String name ) { super( name + " is empty" ); // roept de // constructor van zijn superklasse op }} // einde klasse EmptyListException
Exception wordt gegooid indien het programma een knoop uit een lege lijst wenst te verwijderen.
34
public class ListTest { public static void main( String args[] ) { List list = new List(); // de lege gelinkte lijst "list" is // gecreëerd. // objects creëren om nadien in de gelinkte lijst te zetten Boolean bool = Boolean.TRUE; Character character = new Character( '$' ); Integer integer = new Integer( 34567 ); String string = "hello"; // knopen in de lijst toevoegen en vervolgens de inhoud weergeven
list.insertAtFront( bool ); System.out.println( list.print()); list.insertAtFront( character ); System.out.println( list.print()); list.insertAtBack( integer ); System.out.println( list.print()); list.insertAtBack( string ); System.out.println( list.print()); The list is: true The list is: $ true The list is: $ true 34567 The list is: $ true 34567 hello
4. KLASSE ListTest
35
4. KLASSE ListTest // knopen verwijderen uit de gelinkte lijst try { Object removedObject = list.removeFromFront(); System.out.println( removedObject.toString() + " removed" ); System.out.println( list.print()); removedObject = list.removeFromFront(); ... removedObject = list.removeFromBack(); ... removedObject = list.removeFromBack(); ... } // einde try blok
// catch exception indien een poging werd uitgevoerd om een // knoop uit een lege lijst te verwijderen catch ( EmptyListException emptyListException ) { emptyListException.printStackTrace(); } } // einde methode main } // einde klasse ListTest
36
4. KLASSE ListTestUitvoer van : list.print(); Object removedObject = list.removeFromFront(); ... removedObject = list.removeFromFront(); ... removedObject = list.removeFromBack(); ... removedObject = list.removeFromBack(); ...
The list is: $ true 34567 hello
$ removed The list is: true 34567 hello true removed The list is: 34567 hello hello removed The list is: 34567 34567 removed Empty list
37
OEFENING
Schrijf een dubbel gelinkte lijst
Klasse DoubleListNode : zie slide 11
Klasse DoubleList : insertAtFront, insertAtBack en printInverse (herschrijf de klasse List)
38
5. STACKS: VOORBEELD 1
• Voorbeeld 1:
– We zullen een stack implementeren door gebruik te maken van de klasse List
• De klasse StackInheritance zal erven van List.
39
5. KLASSE StackInheritancepublic class StackInheritance extends List { // constructor public StackInheritance() { super( "stack" ); }
// voegt een object aan de stack toe public synchronized void push( Object object ) { insertAtFront( object ); } // verwijdert een object van de stack public synchronized Object pop() throws EmptyListException { return removeFromFront();}} // einde klasse StackInheritance
• De klasse StackInheritance erft van List, omdat een stack een beperkte versie is van een gelinkte lijst. • De methoden isEmpty en print kunnen gestuurd worden naar een object van StackInheritance, omdat deze erft van List
40
5. KLASSE StackInheritanceTestpublic class StackInheritanceTest
{ ... StackInheritance stack = new StackInheritance(); Boolean bool = Boolean.TRUE; Character character = new Character( '$' ); stack.push( bool ); stack.push( character ); ... while ( true ) { removedObject = stack.pop(); ... } ...
(1) (2) (3) (4) (5)
($ popped) (true popped) $ zie volgende
slide true true true
41
5. KLASSE StackInheritanceTest
com.deitel.jhtp5.ch20.EmptyListException: stack is empty at com.deitel.jhtp5.ch20.List.removeFromFront(List.java:82) at com.deitel.jhtp5.ch20.StackInheritance.pop( StackInheritance.java:22) at StackInheritanceTest.main(StackInheritanceTest.java:33)
42
5. STACKS: VOORBEELD 2
• Andere manier om een stack te implementeren:
• De klasse StackComposition zal een referentie naar een List bevatten. Deze manier van implementatie heet "composition".
• Voordeel t.o.v. voorbeeld 1 (overerving):Deze stack bevat enkel de vier nodige methodes (push, pop, isEmpty en print). De methodes van List (removeFromBack, insertAtBack, …) zijn nu geen methodes van de stack. Terwijl dit bij overerving wel het geval was.
43
5. KLASSE StackComposition public class StackComposition { private List stackList; public StackComposition() { stackList = new List( "stack" ); } public synchronized void push( Object object ) { stackList.insertAtFront( object ); } public synchronized Object pop() throws EmptyListException { return stackList.removeFromFront(); }
public synchronized boolean isEmpty() { return stackList.isEmpty(); }
public synchronized String print() { return stackList.print(); }} // einde klasse StackComposition
44
6. QUEUES
• Queue (= wachtrij)– is ook een beperkte versie van een gelinkte
lijst.
– Men kan zich een queue voorstellen als een rij bij een loket, waarbij de voorste in de rij als eerste geholpen wordt en nieuwkomers achter aansluiten. De persoon die het eerst in de rij staat, wordt het eerst bediend queue is een FIFO gegevensstructuur: first-in, first-out.
45
6. QUEUES
– Het element van de queue dat vooraan staat in de queue, dat dus als eerste zal worden verwijderd, heet de kop van de queue.
– Het element dat achteraan staat, dat dus als laatste aan de queue is toegevoegd, heet de staart van de queue
– We spreken hier niet van push en pop maar van enqueue en dequeue. enqueue : element toevoegen aan de
queue dequeue : element verwijderen uit de
queue
46
6. QUEUE: VOORBEELD
• Voorbeeld:
– We zullen een queue implementeren door gebruik te maken van de klasse List
• De klasse Queue zal een referentie naar een List bevatten ("composition").
47
6. KLASSE QUEUE public class Queue { private List queueList;
public Queue() { queueList = new List( "queue" ); } // element toevoegen aan de queue public synchronized void enqueue( Object object ) { queueList.insertAtBack( object ); } // element verwijderen uit de queue public synchronized Object dequeue() throws EmptyListException { return queueList.removeFromFront(); }
public synchronized boolean isEmpty() { return queueList.isEmpty(); }
public synchronized String print() {return queueList.print();}} // einde klasse Queue
48
6. KLASSE QueueTestpublic class QueueTest { ... Queue queue = new Queue(); Boolean bool = Boolean.TRUE; Character character = new Character( '$' ); queue.enqueue( bool ); queue.enqueue( character );
... while ( true ) {removedObject = queue.dequeue(); ... } ...
(1) (2) (3) (4) (5)
(true dequeued) ($ dequeued) true true $ $ zie volgende
slide
kop staart kop staart kop staart
49
6. KLASSE QueueTest
com.deitel.jhtp5.ch20.EmptyListException: queue is empty
at com.deitel.jhtp5.ch20.List.removeFromFront(List.java:88)
at com.deitel.jhtp5.ch20.Queue.dequeue(Queue.java:23)
at QueueTest.main(QueueTest.java:33)
50
OEFENING
Gegeven : De queue bestaat uit een array van 5 elementen. De array houdt gehele getallen bij.
Gevraagd:
Schrijf de klasse Queue : constructor en de methodes enqueue en dequeue.
51
7. BINAIRE BOOM
- Binaire boom is óf leeg óf zij bestaat uit de wortel, en twee binaire bomen, de linker subboom en de rechter subboom. M.a.w. de knopen bevatten twee "links".
- Het linkerkind is de eerste knoop in de linker subboom.
- Het rechterkind is de eerste knoop in de rechter subboom.
52
7. BINAIRE BOOM
• Voorbeeld van een binaire boom- Een programma bevat de referentie van
de wortel van de binaire boom (root).
B
A D
C
root
53
7. BINAIRE ZOEKBOOM
- binaire zoekboom is een binaire boom die óf leeg is óf waarin elke knoop een sleutel bevat die voldoet aan de volgende voorwaarden:– De sleutel van het linkerkind (als deze
bestaat) van een knoop is kleiner dan de sleutel van de ouders.
– De sleutel van het rechterkind (als deze bestaat) van een knoop is groter dan de sleutel van de ouders.
54
7. BINAIRE ZOEKBOOM
• Voorbeeld van een binaire zoekboom
47
11 43 65 93
25 77
7 17 31 44 68
55
7. BINAIRE ZOEKBOOM- Hoe een binaire zoekboom eruit ziet
hangt af van de volgorde van de ingegeven sleutels.
- Bv. (1) Voeg 22 toe (3) Voeg 35 toe
(2) Voeg 10 toe (4) Voeg 15 toe
22
22
10
22
10 35
22
10 35
15
56
7. BINAIRE ZOEKBOOM
• Voordeel van een binaire zoekboom t.o.v. gesorteerde gelinkte lijst
– Indien we een sleutel moeten opzoeken in een enkel gelinkte lijst dan kunnen we niets anders dan knoop voor knoop door de lijst te bewegen (sequentieel zoeken). Maar sequentieel zoeken is vergeleken bij binair zoeken erg langzaam.
– Indien we met de elementen van een gesorteerde lijst een binaire zoekboom construeren, zullen we zien dat we een sleutel kunnen opzoeken in O(log n) stappen, net zoals bij binair zoeken. Bovendien kunnen elementen in de tijd O(log n) toegevoegd of verwijderd worden.
57
7. DOORLOPEN VAN DE BINAIRE BOOM
– Eén van de belangrijkste operaties bij binaire bomen is het doorlopen van de boom, waarbij elke knoop bezocht wordt.
Het doorlopen van een gelinkte lijst gaat in de natuurlijke volgorde van de eerste tot de laatste knoop. Een boom kunnen we echter in vele verschillende volgorden doorlopen.
58
7. DOORLOPEN VAN DE BINAIRE BOOM
In een gegeven knoop zijn er drie taken die we in een of andere volgorde willen uitvoeren: het bezoeken van de knoop zelf, het doorlopen van zijn linker subboom en het doorlopen van zijn rechter subboom.
Gewoonlijk beperkt men zich tot de gevallen waarin de linker subboom voor de rechter wordt doorlopen. M.a.w. men beperkt zich tot drie gevallen. Deze hebben speciale namen: preorder, inorder en postorder.
59
7. DOORLOPEN VAN DE BINAIRE BOOM
doorlopen in preorder : de knoop wordt eerst bezocht. Als tweede de linker subboom en al laatste de rechter subboom.
Bv.
20, 8, 33, 27, 41
20
8 33
27 41
60
7. DOORLOPEN VAN DE BINAIRE BOOM
doorlopen in inorder : de linker subboom wordt eerst bezocht. Als tweede de knoop en al laatste de rechter subboom.
Bv.
8, 20, 27, 33, 41
20
8 33
27 41
61
7. DOORLOPEN VAN DE BINAIRE BOOM
doorlopen in postorder : de linker subboom wordt eerst bezocht. Als tweede de rechter subboom en al laatste de knoop.
Bv.
8, 27, 41, 33, 20
20
8 33
27 41
62
7. OEFENING
Bepaal de uitvoer indien de boom wordt doorlopen in:
(1) preorder (2) inorder (3) postoder
47
11 43 65 93
25 77
31 44 688
63
7. VOORBEELD VAN EEN BINAIRE BOOM
• Voorbeeld:Twee domeinklassen: TreeNode en TreeApplicatie: TreeTest
• TreeNode: De objecten van deze klasse zijn de knopen van de binaire zoekboom. Bevat de methode insert: een knoop wordt toegevoegd aan de boom.
• Tree bevat de instantie-variable "root". Deze zal refereren naar de wortel van de binaire zoekboom. Bevat methodes om de boom te doorlopen en om knopen toe te voegen.
64
7. KLASSE TreeNode class TreeNode { private TreeNode leftNode; private int data; private TreeNode rightNode; // constructor public TreeNode( int nodeData ) { data = nodeData; leftNode = rightNode = null;// de knoop heeft geen kinderen }
leftNode is het linkerkind en rightNode is het rechterkind.In de constructor wordt er een blad ("leaf node") gecreëerd. De ingegeven data wordt in het blad geplaatst.
65
7. KLASSE TreeNode : accessors public void setLeftNode(TreeNode leftNode)
{ this.leftNode = leftNode; }
public void setRightNode(TreeNode rightNode){ this.rightNode = rightNode; }
public void setData(int data){ this.data = data; }
public TreeNode getLeftNode() { return leftNode; }
public TreeNode getRightNode() { return rightNode; }
public int getData() { return data; }
In het boek zijn de instantie-variabelen als package-toegankelijk gedeclareerd.
66
7. KLASSE TreeNode : methode insert // locate insertion point and insert new node; ignore duplicate values
public synchronized void insert( int insertValue ) { // insert in left subtree if ( insertValue < data ) { // insert new TreeNode if ( leftNode == null ) leftNode = new TreeNode( insertValue ); else // continue traversing left subtree leftNode.insert( insertValue ); } // insert in right subtree else if ( insertValue > data ) { // insert new TreeNode if ( rightNode == null ) rightNode = new TreeNode( insertValue ); else // continue traversing right subtree rightNode.insert( insertValue ); } } // end method insert } // end class TreeNode
67
7. KLASSE TreeNode : methode insert • Een knoop kan enkel toegevoegd worden in de binaire
boom als een blad ("leaf node").
• De methode insert is recursief.
• De toe te voegen waarde "insertValue" wordt vergeleken met de waarde, die in de wortel staat "data".
Indien de toe te voegen waarde kleiner is "if (insertValue<data)"
dan: indien de knoop geen linkerkind bevat dan wordt het nieuw blad toegevoegd "leftNode= new TreeNode(insertValue);"
anders wordt de methode insert naar de linker subboom
gestuurd "leftNode.insert( insertValue );" anders: idem als "dan", behalve rechterkind en rechter subboom i.p.v. linkerkind en linker subboom.
68
7. KLASSE Tree public class Tree { private TreeNode root; // constructor: de binaire boom is leeg public Tree() { root = null; }
public void setRoot(TreeNode root) {
this.root = root; }
public TreeNode getRoot() {
return root; }
69
7. KLASSE Tree // een knoop toevoegen in de binaire zoekboom public synchronized void insertNode( int insertValue ) { if ( root == null ) root = new TreeNode( insertValue ); // de wortel // ("root node") wordt gecreëerd else root.insert( insertValue ); // methode insert oproepen }
Indien de boom leeg is dan is de instantie-variable "root" gelijk aan null, anders refereert "root" naar de wortel.
70
7. KLASSE Tree : inorder // doorlopen van de boom volgens inorderpublic synchronized void inorderTraversal(){ inorderHelper( root ); }
// recursieve methode om de boom te doolopen volgens inorderprivate void inorderHelper( TreeNode node ){ if ( node == null ) return; inorderHelper( node.getLeftNode()); // doorloop linker subboom System.out.print( node.getData()+ " " ); // inhoud van de // knoop weergeven inorderHelper( node.getRightNode());//doorloop rechter subboom}
Indien de programmeur de boom wenst te doorlopen kan hij een methode oproepen, zonder dat hij de "root" dient door te geven (bv. methode inorderTraversal).
71
• Voorbeeld: root 27
inorderHelper( node.getLeftNode() ); 1 System.out.print( node.getData()+" "); inorderHelper( node.getRightNode() );
root 13
inorderHelper( node.getLeftNode() ); 2 System.out.print( node.getData()+" "); 8 inorderHelper( node.getRightNode());
root 6 root null inorderHelper( node.getLeftNode() ); return; System.out.print( node.getData() + " " ); 5 inorderHelper( node.getRightNode()); 3 6 root 17 4 root null inorderHelper( node.getLeftNode() ); return; System.out.print( node.getData()+" " ); 7 inorderHelper( node.getRightNode());
6 13 17 27
27
6
13
17
72
7. KLASSE Tree : preorder // doorlopen van de boom volgens preorderpublic synchronized void preorderTraversal(){ preorderHelper( root ); } // recursieve methode om de boom te doolopen volgens preorderprivate void preorderHelper( TreeNode node ){ if ( node == null ) return; System.out.print( node.getData()+ " " ); // inhoud van de // knoop weergeven preorderHelper( node.getLeftNode()); //doorloop linker subboom preorderHelper(node.getRightNode());//doorloop rechter subboom}
Preorder– data weergeven, vervolgens doorloop linker subboom
en als laatste doorloop rechter subboom
73
7. KLASSE Tree : postorder // begin postorder traversal public synchronized void postorderTraversal() { postorderHelper( root ); } // recursive method to perform postorder traversal private void postorderHelper( TreeNode node ) { if ( node == null ) return; postorderHelper( node.getLeftNode()); //doorloop linker subboom postorderHelper(node.getRightNode());//doorloop rechter subboomSystem.out.print( node.getData() + " " ); // inhoud van de // knoop weergeven }} // einde klasse Tree
Postorder – doorloop linker subboom, vervolgens doorloop
rechter subboom en als laatste de data weergeven
74
7. KLASSE TreeTest ... public static void main( String args[] ) { Tree tree = new Tree(); int value;
// voeg 10 random getallen van 0-99 in de binare zoekboom for ( int i = 1; i <= 10; i++ ) { value = ( int ) ( Math.random() * 100 ); System.out.print( value + " " ); tree.insertNode( value ); }
tree.preorderTraversal(); // doorlopen volgens preorder tree.inorderTraversal(); // doorlopen volgens inorder tree.postorderTraversal(); // doorlopen volgens postorder
...
75
7. KLASSE TreeTest
• uitvoer
Inserting the following values: 39 69 94 47 50 72 55 41 97 73 Preorder traversal 39 69 47 41 50 55 94 72 73 97 Inorder traversal 39 41 47 50 55 69 72 73 94 97 Postorder traversal 41 55 50 47 73 72 97 94 69 39
39
73
72
94
69
47
50
97
41
55