-
Notifications
You must be signed in to change notification settings - Fork 0
/
AVLTree.java
294 lines (291 loc) · 7.76 KB
/
AVLTree.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
import java.util.ArrayList;
import java.util.*;
/**
* This class implements an AVLTree implementation of a tree
* @author Dana Curca, dcurca, 250976773
*/
public class AVLTree implements AVLTreeADT {
//initialize instance variables
private AVLTreeNode root;
private int size;
public AVLTree() {
this.size = 0;
this.root = new AVLTreeNode();
}
/**
* Given node set the root of the tree to node
*/
public void setRoot(AVLTreeNode node) {
root = node;
}
/**
* returns the root of the BST tree
*/
public AVLTreeNode root() {
return root;
}
/**
* checks to make sure that the node given is the root node
*/
public boolean isRoot(AVLTreeNode node) {
return node.isRoot();
}
/**
* returns the size of the BST tree
*/
public int getSize() {
return size;
}
/**
* returns the node of the BST that contains node, key given otherwise return leaf node
*/
public AVLTreeNode get(AVLTreeNode node, int key) {
if(node.isLeaf()) {
return node;
}
else {
if (key == node.getKey()) {
return node;
}
if (key < node.getKey()) {
return get(node.getLeft(), key);
}
else {
return get(node.getRight(), key);
}
}
}
/**
* returns the node with the smallest key given the root node
*/
public AVLTreeNode smallest(AVLTreeNode node) {
if (node.isLeaf()) {
return null;
}
else {
AVLTreeNode temp = node;
while (temp.isInternal()) {
temp = temp.getLeft();
}
return temp.getParent();
}
}
/**
* returns the node that contains the new key,data information otherwise if duplicate key throw an exception
*/
public AVLTreeNode put(AVLTreeNode node, int key, int data) throws TreeException {
AVLTreeNode temp = get(node,key);
if (temp.isInternal()) {
throw new TreeException("Duplicate Key " + key);
}
else {
size++;
temp.setKey(key);
temp.setData(data);
//creates two leaf nodes to point at new node inserted
AVLTreeNode newLeft = new AVLTreeNode(temp);
AVLTreeNode newRight = new AVLTreeNode(temp);
temp.setLeft(newLeft);
temp.setRight(newRight);
return temp;
}
}
/**
* removes the record that contains key within the binary search tree returns the node that used to store the node removed
*/
public AVLTreeNode remove(AVLTreeNode node, int key) throws TreeException {
AVLTreeNode temp = get(node,key);
AVLTreeNode prime, child;
//if key does not exist within tree throw exception
if (temp.isLeaf()) {
throw new TreeException("Null Pointer, Leaf Node " + key);
}
else {
if (temp.getLeft().isLeaf() || temp.getRight().isLeaf()) {
prime = temp.getParent();
//checks to see which side of the BST tree is a leaf
if(temp.getLeft().isLeaf() == true) {
size--;
child = temp.getRight();
if (temp.isRoot()) {
setRoot(child);
}
else {
child.setParent(prime);
if(child == temp.getRight()) {
prime.setRight(child);
}
else {
prime.setLeft(child);
}
}
}
else {
size--;
child = temp.getLeft();
if (temp.isRoot()) {
setRoot(child);
}
else {
child.setParent(prime);
if(child == temp.getRight()) {
prime.setRight(child);
}
else {
prime.setLeft(child);
}
}
}
}
else {
AVLTreeNode small = smallest(temp.getRight());
temp.setKey(small.getKey());
temp.setData(small.getData());
temp = remove(small, small.getKey());
}
}
return temp;
}
/**
* returns an arraylist that contains AVLTreeNode objects after an inorder traversal
*/
public ArrayList<AVLTreeNode> inorder(AVLTreeNode node) {
ArrayList<AVLTreeNode> array = new ArrayList<AVLTreeNode>();
inorderRec(node,array);
return array;
}
/**
* performs an inorder traversal each time appending to a list
*/
public void inorderRec(AVLTreeNode node, ArrayList<AVLTreeNode> list) {
if(!node.isLeaf()) {
inorderRec(node.getLeft(), list);
list.add(node);
inorderRec(node.getRight(), list);
}
}
/**
* recomputes the height of a subtree given node
*/
public void recomputeHeight(AVLTreeNode node) {
node.setHeight(1 + Math.max(node.getLeft().getHeight(), node.getRight().getHeight()));
}
/**
* rebalances the tree and updates the height of the tree as it moves upwards toward the root of the tree
*/
public void rebalanceAVL(AVLTreeNode r, AVLTreeNode v) {
AVLTreeNode tallest;
if (!v.isLeaf()) {
recomputeHeight(v); }
while (v != r) {
v = v.getParent();
if(Math.abs(v.getLeft().getHeight()-v.getRight().getHeight()) > 1) {
if(v.getLeft().getHeight() > v.getRight().getHeight()) {
tallest = taller(v,true);
}
else {
tallest = taller(v,false);
}
AVLTreeNode notLeft = taller(tallest,false);
rotation(v,tallest,notLeft);
}
recomputeHeight(v);
}
}
/**
* given node insert key,data into AVLTree and rebalance the tree after
*/
public void putAVL(AVLTreeNode node, int key, int data) throws TreeException {
AVLTreeNode newNode = put(node,key,data);
rebalanceAVL(node,newNode);
}
/**
* given node remove the node that contains the key and rebalance the tree after
*/
public void removeAVL(AVLTreeNode node, int key) throws TreeException {
AVLTreeNode oldNode = remove(node,key);
rebalanceAVL(node, oldNode);
}
/**
* checks the children of node and returns the subtree that is taller, if a tie in height use onleft to determine if the parent is on the left or right
*/
public AVLTreeNode taller(AVLTreeNode node, boolean onLeft) {
if (node.getLeft().getHeight() > node.getRight().getHeight()) {
return node.getLeft();
}
if (node.getLeft().getHeight() < node.getRight().getHeight()) {
return node.getRight();
}
if (node.isRoot()) {
return node.getLeft();
}
if (onLeft == true) {
return node.getLeft();
}
else {
return node.getRight();
}
}
/**
* a left or right rotation which promotes node as the new parent
*/
public AVLTreeNode rotate(AVLTreeNode node) {
AVLTreeNode parent = node.getParent();
boolean right = check(node);
node.setParent(parent.getParent());
//if parent is a root there are no other nodes to check therefore promote node as new root
if (parent.isRoot() == true) {
setRoot(node);
}
//check if parent is on the left if so set node to be on the left subtree
else if (check(parent) == true) {
node.getParent().setLeft(node);
}
//else set node to be on the right subtree
else {
node.getParent().setRight(node);
}
//R rotation
if (right == true) {
parent.setParent(node);
parent.setLeft(node.getRight());
node.getRight().setParent(parent);
node.setRight(parent);
}
//L rotation
else {
parent.setParent(node);
parent.setRight(node.getLeft());
node.getLeft().setParent(parent);
node.setLeft(parent);
}
recomputeHeight(parent);
recomputeHeight(node);
return node;
}
/**
* private method that checks whether the node given is in the left subtree of a tree
*/
private boolean check(AVLTreeNode node) {
if(node.getParent().getLeft() == node) {
return true;
}
else {
return false;
}
}
/**
* performs LL,RR,LR,RL given z where the rebalance occurs, using rotate either once or twice given the rotation is single (LL,RR) or double (LR,RL)
*/
public AVLTreeNode rotation(AVLTreeNode z, AVLTreeNode y, AVLTreeNode x) {
if((z.getRight() == y && y.getRight() == x )|| (z.getLeft() == y && y.getLeft() == x)) {
rotate(y);
return y;
}
else {
rotate(x);
rotate(x);
return x;
}
}
}