-
Notifications
You must be signed in to change notification settings - Fork 0
/
TreeComponent.java
303 lines (288 loc) · 10.2 KB
/
TreeComponent.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
package tree2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.JTextField;
/**
*
* @author Luke
*/
// Each instance of TreeComponent will be populated with seven nodes.
public class TreeComponent extends JComponent
{
TreeNode root;
TreeNode one;
TreeNode two;
TreeNode three;
TreeNode four;
TreeNode five;
TreeNode six;
TreeNode currentNode;
TreeNode node;
TreeNode parent;
TreeNode child;
// Each node will have a left child, right child, parent, data, and an AVL
// integer value, which denotes the difference of balance between the left
// and right sides of the node. A negative AVL value means the node is off
// balanced in favor of the left side, while a positive one, the right side.
// Keeping track of these AVL values is essential to a functioning AVL binary
// search tree.
private class TreeNode {
TreeNode left;
int data;
TreeNode right;
int AVL;
TreeNode parent;
public TreeNode(TreeNode left,int data, TreeNode right,int AVL, TreeNode parent){
this.left = left;
this.data = data;
this.right = right;
this.AVL = AVL;
this.parent = parent;
}
}
public TreeComponent(){
TreeNode root = new TreeNode(null,200,null,0,null);
TreeNode one = new TreeNode(null,100,null,0,root);
TreeNode two = new TreeNode(null,300,null,0,root);
TreeNode three = new TreeNode(null,50,null,0,one);
TreeNode four = new TreeNode(null,150,null,0,one);
TreeNode five = new TreeNode(null,250,null,0,two);
TreeNode six = new TreeNode(null,350,null,0,two);
root.left = one;
root.right = two;
one.left = three;
one.right = four;
two.left = five;
two.right = six;
JTextField numberField = new JTextField();
JButton printButton = new JButton("Print All");
printButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if(root.parent!=null){
getRoot(root);
}else printAll(root);
}
});
JButton addButton = new JButton("Add Node");
addButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
int data = Integer.parseInt(numberField.getText());
if(root.parent!=null){
getRootAdd(data,root);
}else addNode(data,root);
}
});
setLayout(new FlowLayout());
JPanel addPanel = new JPanel(new GridLayout(1,2));
addPanel.add(numberField);
addPanel.add(addButton);
JPanel userPanel = new JPanel(new GridLayout(2,1));
userPanel.add(addPanel);
userPanel.add(printButton);
add(userPanel,BorderLayout.SOUTH);
}
// Method prints two values of each node. (data, AVL)
public void printAll(TreeNode currentNode){
if(currentNode!=null){
printAll(currentNode.left);
System.out.println(currentNode.data +", "+ currentNode.AVL);
printAll(currentNode.right);
}
}
// addNode() inserts a new node at the appropriate spot in the binary search
// tree. If the input is a repeated value, this function does nothing.
// After adding the node, the avlIterator() function is called.
public void addNode(int data, TreeNode currentNode){
if(data == currentNode.data) return;
if(data < currentNode.data){
if(currentNode.left==null) {
TreeNode node = new TreeNode(null,data,null,0,currentNode);
currentNode.left = node;
currentNode.AVL--;
avlIterator(currentNode,currentNode);
}else addNode(data,currentNode.left);
}
if(data > currentNode.data) {
if(currentNode.right==null) {
TreeNode node = new TreeNode(null,data,null,0,currentNode);
currentNode.right = node;
currentNode.AVL++;
avlIterator(currentNode,currentNode);
}else addNode(data,currentNode.right);
}
}
// avlIterator() iterates through all of the parent nodes affected by the added
// node and updates the value of each affected AVL integer value. After all
// necessary updates are made, avlChecker() is called.
public void avlIterator(TreeNode node,TreeNode originalParent){
parent = node.parent;
if(parent==null){
avlChecker(originalParent);
return;
}
if(node.AVL==0){
avlChecker(originalParent);
return;
}else{
if(parent.left==node){
parent.AVL--;
avlIterator(parent,originalParent);
}else{
parent.AVL++;
avlIterator(parent,originalParent);
}
}
}
// avlChecker() checks if any of the parent nodes of the added node is greater
// than 1 or less than -1, which denotes an unbalanced tree. If the tree is
// unbalanced, avlDecider() is called.
public void avlChecker(TreeNode node){
parent = node.parent;
if(parent==null)return;
if(parent.AVL<-1) avlDecider(parent);
else if(parent.AVL>1) avlDecider(parent);
else avlChecker(parent);
}
// avlDecider() checks if a double rotation or a single rotation is needed, in
// order to rebalance the tree. This function calls one of four functions:
// single or double left rotations or single or double right rotations.
public void avlDecider(TreeNode node){
if(node.AVL==-2){
if(node.left.AVL>0) avlDLeft(node.left);
else avlLeft(node);
}else {
if(node.right.AVL<0) avlDRight(node.right);
else avlRight(node);
}
}
// avlLeft() is called when a single left rotation is needed for rebalancing.
// It then executes the rotation.
public void avlLeft(TreeNode node){
child = node.left;
parent = node.parent;
if(parent==null){
changeRoot(node);
return;
}
if(child.right!=null) node.left = child.right;
else node.left = null;
if(parent.left==node) parent.left = child;
else parent.right = child;
child.parent = parent;
child.right = node;
node.parent = child;
child.AVL = 0;
node.AVL = 0;
avlUpdater(child);
}
// avlDLeft() is called when a double left rotation is needed for rebalancing.
// It then executes the first rotation of the double rotation, and then proceeds
// to call avlLeft() for the second rotation.
public void avlDLeft(TreeNode node){
parent = node.parent;
child = node.right;
if(child.left!=null) node.right = child.left;
else node.right = null;
child.left = node;
node.parent = child;
parent.left = child;
child.parent = parent;
node.AVL = 0;
if(child.AVL>0) node.AVL--;
child.AVL = -1;
avlLeft(parent);
}
// avlRight() is called when a single right rotation is needed for rebalancing.
// It then executes the rotation.
public void avlRight(TreeNode node) {
child = node.right;
parent = node.parent;
if(parent==null){
changeRoot(node);
return;
}
if(child.left!=null) node.right = child.left;
else node.right = null;
if(parent.right==node) parent.right=child;
else parent.left=child;
child.parent = parent;
child.left = node;
node.parent = child;
node.AVL = 0;
child.AVL = 0;
avlUpdater(child);
}
// avlDRight() is called when a double right rotation is needed for rebalancing.
// It then executes the first rotation of the double rotation, and then proceeds
// to call avlRight() for the second rotation.
public void avlDRight(TreeNode node){
child = node.left;
parent = node.parent;
if(child.right!=null) node.left = child.right;
else node.left = null;
child.right = node;
node.parent = child;
parent.right = child;
child.parent = parent;
node.AVL = 0;
if(child.AVL<0) node.AVL++;
child.AVL = 1;
avlRight(parent);
}
// avlUpdater() is called after a rebalancing. It updates the affected AVL
// integer values.
public void avlUpdater(TreeNode node){
parent = node.parent;
if(parent==null)return;
if(parent.left==node){
parent.AVL++;
if(parent.AVL==1)return;
else avlUpdater(parent);
}else{
parent.AVL--;
if(parent.AVL==-1)return;
else avlUpdater(parent);
}
}
// When the root needs to be changed in order to balance the tree, changeRoot()
// is called.
public void changeRoot(TreeNode root){
if(root.AVL<0){
node = root.left;
child = node.right;
root.left = child;
child.parent = root;
node.right = root;
root.parent = node;
node.parent = null;
root.AVL = 0;
node.AVL = 0;
}else{
node = root.right;
child = node.left;
root.right = child;
child.parent = root;
node.left = root;
root.parent = node;
node.parent = null;
root.AVL = 0;
node.AVL = 0;
}
}
// Admittedly, this part is a bit messy. When the root is changed for
// rebalancing purposes, the global root of TreeComponent doesn't get updated.
// These two functions are called to get the correct root.
public void getRoot(TreeNode node){
parent = node.parent;
if(node.parent==null) printAll(node);
else getRoot(parent);
}
public void getRootAdd(int data,TreeNode node){
parent = node.parent;
if(node.parent==null) addNode(data,node);
else getRootAdd(data,parent);
}
}