1 Hoofdstuk 20: GEGEVENSSTRUCTUREN. 2 H 20. GEGEVENSSTRUCTUREN 1. INLEIDING Reeds gezien :...

Post on 08-Jun-2015

213 views 1 download

Transcript of 1 Hoofdstuk 20: GEGEVENSSTRUCTUREN. 2 H 20. GEGEVENSSTRUCTUREN 1. INLEIDING Reeds gezien :...

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