-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBinarySearchTree.java
382 lines (361 loc) · 12.2 KB
/
BinarySearchTree.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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
//---------------------- BinarySearchTree.java -------------------------
import java.util.*;
import java.io.*;
/**
* BinarySearchTree -- this class uses a private inner class for
* tree nodes. (Although in this version it is public so I can
* do a prefix walk in DrawPanel.)
*
* @author rdb
* April 2, 2008
*
* Modified: April 6
* added iterator and node deletion code.
*
* mlb Nov 2008 for BSTrecursion
* rdb April 1, 2009 for revised BSTrecursion
* Students implement height(), sum(), nodeDepth(), rebuild()
* rdb March 2011: height, nodeDepth, setBalance, rebuild
* rdb March 2013: Added batch mode
* height, inOrderString, find, findMax
* rdb March 2014: reformatted; made checkstyle-correct
*/
public class BinarySearchTree
{
//-------------------- instance variables ---------------------
private Node _root;
private int _size;
//-------------------- constructors --------------------------
/**
* Construct an empty tree with no nodes.
*/
public BinarySearchTree()
{
_root = null;
_size = 0;
}
/**
* Construct a tree with a root.
* @param rootData Data data for root node
*/
public BinarySearchTree( Data rootData )
{
_root = new Node( rootData );
_size = 1;
}
//------------------ inOrderString() ------------------------------
/**
* Traverse the tree in in-order fashion to generate a string
* representing the nodes of the tree.
*
* This method uses a private utility method to generate a string for
* a subtree rooted at a particular node.
*
* @return String
*/
public String inOrderString()
{
return inOrderString( _root );
}
//------------------ inOrderString( node ) ---------------
/**
* Generate String representation of subtee rooted at "node".
*
* @param n Node
* @return String
*/
private String inOrderString( Node n )
{
////////////////////////////////////////////////////////////////
// Append the string for the node's Data object after generating
// the left subtree and before generating the right subtree
//
// Don't forget the base case
////////////////////////////////////////////////////////////////
if( n == null)
return "";
String left = inOrderString( n.left );
String right = inOrderString( n.right );
return left + " " + n.data + " " + right;
//return "";
}
//-------------------- height() ----------------------------------
/**
* The height of the tree is the depth of the deepest node.
*
* @return int
*/
public int height()
{
return height( _root );
}
//------------------- height( Node ) ----------------------
/**
* The height of a node of the tree is the maximum number of steps
* to reach a leaf from this node.
*
* @param n Node subtree whose height is returned
* @return int height of Node n
*/
private int height( Node n )
{
///////////////////////////////////////////////////////////////
// Height of a node is 1 more than the max height of its children
//
// Don't forget the base case
///////////////////////////////////////////////////////////////
int hLeft = 0;
int hRight = 0;
if( n.left != null )
hLeft = height( n.left );
else if( n.right != null )
hRight = height( n.right );
if( hLeft > hRight )
return hLeft + 1;
else
return hRight + 1;
//return 0;
}
//-------------------- find( String ) -------------------------
/**
* Given a key value, search the tree to find the node that has
* that key value, if it exists.
*
* Return the Data object from the node or null.
*
* @param key String string to search for as a key in the tree
* @return Data if id found, return Data object for id
* else return null
*/
public Data find( String key )
{
return find( _root, key );
}
//------------------ find( Node, String ) ----------------------
/**
* Recursion is done in this method.
* return the Data object with the specified key
* if it is in the subtree rooted at Node n.
*
* @param n Node subtree to search for key
* @param key String key to search for
* @return Data Data object containing found key, or null
*/
private Data find( Node n, String key )
{
///////////////////////////////////////////////////////////
// If searchKey equals node's data key, return its Data object.
// Otherwise if the searchKey < node's key, recurse down
// the left subtree, else recurse down the right subtree
//
// Don't forget you have to check for null references somewhere;
// that's the sign that the searchKey isn't in the tree
///////////////////////////////////////////////////////////
if( n == null )
return null;
int i = key.compareTo( n.data.key );
if( i == 0 )
return n.data;
else if( i < 0 )
return find( n.left, key );
else
return find( n.right, key );
}
//-------------------- maxFind() --------------------------------
/**
* Find the node in the tree that has the maximum value field.
* Remember the tree is organized by "key", not "value", so you need
* to traverse the entire tree. It doesn't matter what traversal
* you do. However, it make sense to define a method that finds the
* max value in a subtree and recursively call that for each child
* subtree.
*
* @return Data returned Data containing max value,
* or null if tree is empty.
*/
public Data maxFind()
{
return maxFind( _root );
}
//-------------------- maxFind( Node ) ----------------------------
/**
* Find maximum value in a subtree. Each invocation finds the max of
* the left subtree, the max of the right subtree, and returns the
* node with the max of those 2 values and the Data from that node.
*
* @param n Node subtree to find max data for
* @return Data the Data object with the max data value
*/
private Data maxFind( Node n )
{
///////////////////////////////////////////////////////////////
// Method should return the max Data object from the subtree
// whose root is "n".
// It needs to compare the value of n's Data object with the max
// of the Data objects returned from the left and right
// subtrees and return the one with the largest value.
///////////////////////////////////////////////////////////////
if( n == null )
return null;
Data max = n.data;
Data lmax = maxFind( n.left );
Data rmax = maxFind( n.right );
if( lmax != null && lmax.value > max.value )
max = lmax;
if( rmax != null && rmax.value > max.value )
max = rmax;
return max;
}
//////////////////////////////////////////////////////////////////
// MAKE NO CHANGES BELOW HERE
//////////////////////////////////////////////////////////////////
//--------------------- root() ----------------------------------
/**
* Return the root of the tree. This is package access so DrawPanel
* can do a prefix walk of the tree. Would be better to have multiple
* iterators.
* @return Node
*/
BinarySearchTree.Node root()
{
return _root;
}
//--------------------- add -----------------------------------
/**
* Add a node to the tree in its proper position determined by the
* "key" field of the Data object. This method uses the addNode
* recursive utility method.
*
* @param data Data Data object to be added to the tree.
*/
public void add( Data data )
{
boolean added = true;
if ( _root == null )
_root = new Node( data );
else
added = addNode( _root, data );
if ( added )
_size++;
}
//------------------ addNode( Node, Data ) -----------------------
/**
* A recursive method to add a new Data object to the subtree
* rooted at the first argument.
*
* @param parent Node subtree to which Data is to be added
* @param newOne Data Data object to be added to the tree
* @return boolean true if add was successful
*/
private boolean addNode( Node parent, Data newOne )
{
boolean added = true;
int cmp = newOne.compareTo( parent.data );
if ( cmp < 0 )
{
if ( parent.left != null )
added = addNode( parent.left, newOne );
else
{
parent.left = new Node( newOne );
parent.left.parent = parent;
}
}
else if ( cmp == 0 )
{
System.err.println( "== key found: Not adding: " + newOne );
added = false;
}
else
{
if ( parent.right != null )
added = addNode( parent.right, newOne );
else
{
parent.right = new Node( newOne );
parent.right.parent = parent;
}
}
return added;
}
//-------------------- size( ) -------------------------
/**
* Return the number of nodes in the tree.
* @return int size of tree
*/
public int size()
{
return _size;
}
//-------------------------- toString() -------------------------
/**
* Generate a string representation of the tree.
*
* @return String a string representation of the tree.
*/
public String toString()
{
return toString( _root, " ", "=" ) ;
}
/**
* Recursively generate a string representation for a Node of a tree;
* indent is increased for increasing depth.
* Branch is a short string that prefixes each node indicating
* whether the node is a left (L) or right (R) child.
* @return String string rep of subtree
* @param n Node subtree to convert to string
* @param indent String prefix string for indentation level
* @param branch String (L) or (R)
*/
private String toString( Node n, String indent, String branch )
{
String s = "";
if ( n != null )
{
String prefix = indent.substring( 0, indent.length() - 2 )
+ branch;
s += prefix + n.data.toString() + "\n";
if ( n.left != null )
s += toString( n.left, indent + " ", "L " );
if ( n.right != null )
s += toString( n.right, indent + " ", "R " );
}
return s;
}
//+++++++++++++++++++++++ inner class Node ++++++++++++++++++++++
/**
* The Node class does not have to be seen outside this class, so
* it is private.
* @author rdb
*/
public class Node
{
//-------------- instance variables ---------------------------
Data data;
Node left;
Node right;
Node parent;
//--------------- constructor --------------------------------
/**
* Construct a node with Data.
*
* @param d Data data for the node.
*/
public Node( Data d )
{
data = d;
left = null;
right = null;
parent = null;
}
}
//--------------------- main -------------------------------------
/**
* A convenience main that runs the app for this problem.
* @param args String[] command line args.
*/
public static void main( String[] args )
{
TreeRecursion.main( args );
}
}