Download presentation
Presentation is loading. Please wait.
1
The Singleton Pattern II
Recursive Linked Structures
2
BST Interface public interface BST<E extends Comparable<E>> extends Collection<E>{ // Traversals public List<E> preorder(); public List<E> inorder(); public List<E> postorder(); }
3
LinkedBST Class public class LinkedBST<E extends Comparable<E>> extends AbstractCollection<E> implements BST<E>{ private TreeNode<E> root = null; // Join the Collection family public boolean add(E item){return true;} public int size(){return 0;} public Iterator<E> iterator(){return this.preorder().iterator();} // Tree-like methods public boolean contains(Object item){return true;} public String toString(){return "";} // Traversals public List<E> preorder(){return new ArrayList<E>();} public List<E> inorder(){return new ArrayList<E>();} public List<E> postorder(){return new ArrayList<E>();} }
4
The TreeNode Class root “A”
public class TreeNode<E extends Comparable<E>>{ public E data; public TreeNode<E> left, right; public TreeNode(E data){ this.data = data; this.left = null; this.right = null; } TreeNode<String> root = new TreeNode<>("A"); root “A”
5
Recursive Data Structures
A recursive data structure is either a basic value, such as null, or contains a value of the same type of data structure The TreeNode class is a good example
6
Recursive Data Structures
A linked structure is either empty (null) or contains a data value followed by other linked structures (left, right) of exactly the same form
7
Recursive Algorithms When processing a linked structure
Handle the case of empty (null) Do something with the data value and then “recurse” with the linked structure (left, right) of exactly the same form
8
Some Recursive Patterns: Preorder Traversal
if the linked structure is not empty process the value process the linked structure on the left process the linked structure on the right Note that there is an if statement rather than a while loop The process just quits when the base case (the end of the structure) is reached
9
Some Recursive Patterns: Preorder Traversal
// In the LinkedBST class public List<E> preorder(){ List<E> list = new ArrayList<>(); preorderTraverse(this.root, list); return list; } private preorderTraverse(TreeNode<E> node, List<E> list){ if (node != null){ list.add(node.data); preorderTraverse(node.left, list); preorderTraverse(node.right, list);
10
Some Recursive Patterns: Search
if the linked structure is empty return false else if the target equals the value return true else return the result of searching the rest of the linked structure
11
Some Recursive Patterns: Search
public boolean contains(Object item){ return containsTraverse(this.root, (Comparable)item); } private boolean containsTraverse(TreeNode<E> node, Comparable<E> item){ if (node == null) return false; else{ int relation = item.compareTo(node.data); if (relation == 0) return true; else if (relation < 0) return containsTraverse(node.left, item); else return containsTraverse(node.right, item);
12
Some Recursive Patterns: size
if the linked structure is empty return 0 else return 1 + the size of the rest of the linked structure
13
Some Recursive Patterns: size
public int size(){ return sizeTraverse(this.root); } public int sizeTraverse(TreeNode<E> node){ if (node == null) return 0; else return 1 + sizeTraverse(node.left) + sizeTraverse(node.right);
14
Problems With Current Version
Uses null for the case of an empty structure, so we must check for null with if statements in every method
15
Problems With Current Version
A linked structure should be able to compute its own length But a recursive implementation of this would be pretty hard TreeNode n = new TreeNode("Ken"); int myLength = n.length();
16
Our View of the Current Version
A linked structure is either empty (null) or contains a data value followed by another linked structure (next) of exactly the same form
17
A Better View A linked structure is either or empty (an empty node)
compound (a compound node that contains a data value and another linked structure)
18
From Data to Algorithms
Two concrete classes of nodes that implement the same interface The empty node’s methods handle the base cases The compound node’s methods handle the recursive ones Use polymorphism to make the choices (no explicit if statements in the code!)
19
From Data to Algorithms
TreeNode CompoundNode EmptyNode
20
The TreeNode Interface
public interface TreeNode<E extends Comparable<E>>{ public void preorder(List<E> list); public boolean contains(Comparable<E> item); public int size(); // etc. }
21
Node Classes, Etc. EmptyNode – The class of an empty node
CompoundNode – The class of compound nodes EmptyNode.THE_EMPTY_NODE – The single instance used for any empty node
22
Using the New Implementation
// In the class LinkedBST public List<E> preorder(){ List<E> list = new ArrayList<>(); this.root.preorderTraverse(list); return list; } public boolean contains(Object item){ return this.root.contains((Comparable)item); public int size(){ return this.root.size();
23
The EmptyNode Class The singleton instance is created just once
public class EmptyNode<E> implements TreeNode<E>{ public void preorder(List<E> list){return;} public boolean contains(Comparable<E> item){return false} public int size(){return 0;} // etc. other instance methods go here // Constructor to prevent other instantiations private EmptyNode(){} static public final EmptyNode<E> THE_EMPTY_NODE = new EmptyNode<E>(); } The singleton instance is created just once
24
The CompoundNode Class
public class CompoundNode<E> implements TreeNode<E>{ private E data; private CompoundNode<E> left, right; public CompoundNode(E data){ this.data = data; this.left = EmptyNode.THE_EMPTY_NODE; this.right = EmptyNode.THE_EMPTY_NODE; } public void preorder(List<E> list){ list.add(this.data) left.preorder(list); # Not recursion, but right.preorder(list); # polymorphism! public int size(){ return 1 + this.left.size() + this.right.size();
25
The CompoundNode Class
public boolean contains(Comparable<E> item){ relation = item.compareTo(node.data); if (relation == 0) return true; else if (relation < 0) return this.left.contains(item); else return this.right.contains(item); }
26
Recursive Objects Instead of using explicit if statements to handle choices, try using polymorphism, which automatically handles them Divide the cases into different types of objects that obey the same interface (avoid using null for the simple case) Use simple objects for the base cases and recursive objects for the recursive ones
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.