-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAbstractTree.java
205 lines (185 loc) · 7.52 KB
/
AbstractTree.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
/**
* An abstract base class providing some functionality of the Tree interface.
*
* The following three methods remain abstract, and must be
* implemented by a concrete subclass: root, parent, children. Other
* methods implemented in this class may be overridden to provide a
* more direct and efficient implementation.
*
*/
public abstract class AbstractTree<E> implements Tree<E> {
/**
* Returns true if Position p has one or more children.
*
* @param p A valid Position within the tree
* @return true if p has at least one child, false otherwise
* @throws IllegalArgumentException if p is not a valid Position for this tree.
*/
@Override
public boolean isInternal(Position<E> p) { return numChildren(p) > 0; }
/**
* Returns true if Position p does not have any children.
*
* @param p A valid Position within the tree
* @return true if p has zero children, false otherwise
* @throws IllegalArgumentException if p is not a valid Position for this tree.
*/
@Override
public boolean isExternal(Position<E> p) { return numChildren(p) == 0; }
/**
* Returns true if Position p represents the root of the tree.
*
* @param p A valid Position within the tree
* @return true if p is the root of the tree, false otherwise
*/
@Override
public boolean isRoot(Position<E> p) { return p == root(); }
/**
* Returns the number of children of Position p.
*
* @param p A valid Position within the tree
* @return number of children of Position p
* @throws IllegalArgumentException if p is not a valid Position for this tree.
*/
@Override
public int numChildren(Position<E> p) {
int count=0;
for (Position child : children(p)) count++;
return count;
}
/**
* Returns the number of nodes in the tree.
* @return number of nodes in the tree
*/
@Override
public int size() {
int count=0;
for (Position p : positions()) count++;
return count;
}
/**
* Tests whether the tree is empty.
* @return true if the tree is empty, false otherwise
*/
@Override
public boolean isEmpty() { return size() == 0; }
//---------- support for computing depth of nodes and height of (sub)trees ----------
/** Returns the number of levels separating Position p from the root.
*
* @param p A valid Position within the tree
* @throws IllegalArgumentException if p is not a valid Position for this tree.
*/
public int depth(Position<E> p) throws IllegalArgumentException {
if (isRoot(p))
return 0;
else
return 1 + depth(parent(p));
}
/** Returns the height of the tree.
*
* Note: This implementation works, but runs in O(n^2) worst-case time.
*/
private int heightBad() { // works, but quadratic worst-case time
int h = 0;
for (Position<E> p : positions())
if (isExternal(p)) // only consider leaf positions
h = Math.max(h, depth(p));
return h;
}
/**
* Returns the height of the subtree rooted at Position p.
*
* @param p A valid Position within the tree
* @throws IllegalArgumentException if p is not a valid Position for this tree.
*/
public int height(Position<E> p) throws IllegalArgumentException {
int h = 0; // base case if p is external
for (Position<E> c : children(p))
h = Math.max(h, 1 + height(c));
return h;
}
//---------- support for various iterations of a tree ----------
//---------------- nested ElementIterator class ----------------
/* This class adapts the iteration produced by positions() to return elements. */
private class ElementIterator implements Iterator<E> {
Iterator<Position<E>> posIterator = positions().iterator();
public boolean hasNext() { return posIterator.hasNext(); }
public E next() { return posIterator.next().getElement(); } // return element!
public void remove() { posIterator.remove(); }
}
/**
* Returns an iterator of the elements stored in the tree.
* @return iterator of the tree's elements
*/
@Override
public Iterator<E> iterator() { return new ElementIterator(); }
/**
* Returns an iterable collection of the positions of the tree.
* @return iterable collection of the tree's positions
*/
@Override
public Iterable<Position<E>> positions() { return preorder(); }
/**
* Adds positions of the subtree rooted at Position p to the given
* snapshot using a preorder traversal
* @param p Position serving as the root of a subtree
* @param snapshot a list to which results are appended
*/
private void preorderSubtree(Position<E> p, List<Position<E>> snapshot) {
snapshot.add(p); // for preorder, we add position p before exploring subtrees
for (Position<E> c : children(p))
preorderSubtree(c, snapshot);
}
/**
* Returns an iterable collection of positions of the tree, reported in preorder.
* @return iterable collection of the tree's positions in preorder
*/
public Iterable<Position<E>> preorder() {
List<Position<E>> snapshot = new ArrayList<>();
if (!isEmpty())
preorderSubtree(root(), snapshot); // fill the snapshot recursively
return snapshot;
}
/**
* Adds positions of the subtree rooted at Position p to the given
* snapshot using a postorder traversal
* @param p Position serving as the root of a subtree
* @param snapshot a list to which results are appended
*/
private void postorderSubtree(Position<E> p, List<Position<E>> snapshot) {
for (Position<E> c : children(p))
postorderSubtree(c, snapshot);
snapshot.add(p); // for postorder, we add position p after exploring subtrees
}
/**
* Returns an iterable collection of positions of the tree, reported in postorder.
* @return iterable collection of the tree's positions in postorder
*/
public Iterable<Position<E>> postorder() {
List<Position<E>> snapshot = new ArrayList<>();
if (!isEmpty())
postorderSubtree(root(), snapshot); // fill the snapshot recursively
return snapshot;
}
/**
* Returns an iterable collection of positions of the tree in breadth-first order.
* @return iterable collection of the tree's positions in breadth-first order
*/
public Iterable<Position<E>> breadthfirst() {
List<Position<E>> snapshot = new ArrayList<>();
if (!isEmpty()) {
LinkedQueue<Position<E>> fringe = new LinkedQueue<>();
fringe.enqueue(root()); // start with the root
while (!fringe.isEmpty()) {
Position<E> p = fringe.dequeue(); // remove from front of the queue
snapshot.add(p); // report this position
for (Position<E> c : children(p))
fringe.enqueue(c); // add children to back of queue
}
}
return snapshot;
}
}