-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBalancedPersistentDynamic.java
executable file
·332 lines (310 loc) · 12.9 KB
/
BalancedPersistentDynamic.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
import javax.swing.*;
import java.util.*;
/**
* BalancedPersistentDynamic it is subclass of bst (basically it is red black tree)
*/
public class BalancedPersistentDynamic extends BinarySearchTree implements VisitEventListener{
private JTabbedPane jTabbedPane = new JTabbedPane();//tabbed pane that display all version of trees sequence wise
private HashMap<Node, Integer> nodeColors = new HashMap<Node, Integer>(); //maintain node colors
private Node lastNode = null; //copy of last visited node
private ArrayList<BinarySearchTree> trees = new ArrayList<BinarySearchTree>(); //old version of tree
private Vector<Node> visited = null; //list of actual visited nodes it will be helpful in insertion and deletion
/**
* default constructor that add listener
*/
public BalancedPersistentDynamic() {
addVisitListener(this);
}
/**
*
* @param data
*
* add node in tree and perform rotation and recoloring
*/
public void add(Comparable data){
visited = new Vector<Node>(); //refresh list of visited nodes
super.add(data); //add data in tree just like bst
nodeColors.put(visited.get(visited.size()-1), 1); //last node in visited list will be new added node so make its color red
jTabbedPane.add("Add " + data, trees.get(trees.size()-1).getTreePanel()); // add version tree (without balancing) in tabbed pane
balance(visited.get(visited.size()-1), visited.size()-1); //balance tree
visited = null;//make visited null
lastNode = null; //make last node null
jTabbedPane.add("balance", getTreePanel()); //add tree (with balance) in tabbed pane
}
/**
*
* @param data
* remove node from tree and perform rotation and recoloring (remove double black)
*/
public void remove(Comparable data){
visited = new Vector<>();//refresh list of visited nodes
super.remove(data); //remove data from tree just like bst
jTabbedPane.addTab("Remove " + data , getTreePanel());// add version tree (without balancing) in tabbed pane
Node del = visited.get(visited.size()-1); //deleted node
Node rep = null; // replacer node
//find rep node
if(del.left == null) // if del left is null mean it is replaced by right child
rep = del.right;
else //else it is replaced by its left child
rep = del.left;
if(rep != null && nodeColors.get(del) != nodeColors.get(rep)){ // if atleast one is red either rep or del
nodeColors.put(rep, 0); //make replacer black node
}
else if((rep == null || nodeColors.get(rep) == 0) && nodeColors.get(del) == 0){ //else if both are black
//rep is double black
removeDoubleBlack(rep, visited.size()-1);//remove double black because it is violating red black tree property
}
jTabbedPane.addTab("Balance ", getTreePanel()); //add tree (with balance) in tabbed pane
visited = null; //make visited null
lastNode = null;//make last node null
}
private void removeDoubleBlack(Node db, int index){
//if db is not root then solve problem else return
if (db != getRoot()) { //db is not root
Node parent = visited.get(index-1); //parent node
Node sibling = getSibling(parent, db); //sibling of rep node
if(sibling != null && nodeColors.get(sibling) == 0) { // if sibling is black
boolean isLeftRed = (sibling.left != null && nodeColors.get(sibling.left) == 1);
boolean isRightRed = (sibling.right != null && nodeColors.get(sibling.right) == 1);
if (isLeftRed || isRightRed) {//if any child of sibling is red
Node redChild = null;
//find red child of sibling
if (isLeftRed) redChild = sibling.left;
else redChild = sibling.right;
Node n = null;
//perform rotation and recolor it
if(parent.right == sibling){
if(sibling.left == redChild) { //R-L rotation
swapColor(sibling, redChild);
parent.right = rotateRight(sibling);
swapColor(parent, parent.right);
n = rotateLeft(parent);
nodeColors.put(sibling, 0);
}
else { //R-R rotation
swapColor(parent, sibling);
n = rotateLeft(parent);
nodeColors.put(redChild, 0);
}
}
else{
if(sibling.right == redChild) { //L-R rotation
swapColor(sibling, redChild);
parent.left = rotateLeft(sibling);
n = rotateRight(parent);
nodeColors.put(sibling, 0);
}
else { //L-L rotation
swapColor(parent, sibling);
n = rotateRight(parent);
nodeColors.put(redChild, 0);
}
}
if(index-2 <0){ //if we get new root after rotation so update root
setRoot(n);
}
else{ //else update hierarchy
Node grandParent = visited.get(index-2);
if (grandParent.left == parent){
grandParent.left = n;
}
else{
grandParent.right = n;
}
}
}
else{ //if both child of sibling is black
nodeColors.put(sibling, 1); //color sibling red
//color parent black
if(nodeColors.get(parent) == 1)
nodeColors.put(parent, 0);
else
removeDoubleBlack(parent, index-1); //if parent was alreday black
}
}
else if(sibling != null && nodeColors.get(sibling) == 1){ // if sibling is red
swapColor(parent, sibling); //swap parent and sibling color
Node n = null;
//perform suitable rotation on parent
if(parent.left == sibling){
n = rotateRight(parent);
}
else{
n = rotateLeft(parent);
}
//if we get new root update it
if (index-2 <0){
setRoot(n);
}
else { //else update tree hierarchy
Node grandParent = visited.get(index-2);
if (grandParent.left == parent)
grandParent.left = n;
else
grandParent.right = n;
}
visited.add(index-1, n); //add new parent in visited list
removeDoubleBlack(db, index+1); //and again apply cases on double black node
}
}
}
/**
*
* @param node1
* @param node2
*
* swap colors of two nodes
*/
private void swapColor(Node node1, Node node2){
int color = nodeColors.get(node1);
nodeColors.put(node1, nodeColors.get(node2));
nodeColors.put(node2, color);
}
/**
*
* @param node
* @param index
*
* balance tree, perform rotation and recoloring
*/
private void balance(Node node, int index){
if(node == getRoot() || index == 0){ //if node is root
nodeColors.put(node, 0); //make it black
return;
}
Node parent = visited.get(index-1); //parent of node
if(nodeColors.get(parent) != 0){ //if parent is red
Node grandParent = visited.get(index-2);
Node uncle = getSibling(grandParent, parent);
if(uncle != null && nodeColors.get(uncle) == 1){ //if uncle node is red
nodeColors.put(parent, 0); //color parent black
nodeColors.put(uncle, 0); //color uncle black
nodeColors.put(grandParent, 1); //color grand parent red
balance(grandParent, index-2); //rebalance grand parent
}
else{ //if uncle is black
Node n = null;
//perform suitable rotation
if(grandParent.right == parent){
if(parent.left == node) { //R-L
grandParent.right = rotateRight(parent);
n = rotateLeft(grandParent);
nodeColors.put(n, 0);
nodeColors.put(n.left, 1);
}
else { //R-R
n = rotateLeft(grandParent);
nodeColors.put(n, 0);
nodeColors.put(n.left, 1);
}
}
else{
if(parent.right == node) { //L-R
grandParent.left = rotateLeft(parent);
n = rotateRight(grandParent);
nodeColors.put(n, 0);
nodeColors.put(n.right, 1);
}
else { //L-L
n = rotateRight(grandParent);
nodeColors.put(n, 0);
nodeColors.put(n.right, 1);
}
}
if(index-3 < 0) //after rotation if we get new root update it
setRoot(n);
else { //else update hierarchy of tree
Node m = visited.get(index - 3);
if(m.right == grandParent)
m.right = n;
else if(m.left == grandParent)
m.left = n;
}
}
}
}
/**
*
* @param node
* @return
*
* rotate left
*/
private Node rotateLeft(Node node){
Node newNode = node.right;
node.right = newNode.left;
newNode.left = node;
return newNode;
}
/**
*
* @param node
* @return
*
* rotate right
*/
private Node rotateRight(Node node){
Node newNode = node.left;
node.left = newNode.right;
newNode.right = node;
return newNode;
}
/**
*
* @param parent
* @param node
* @return
*
* get sibling of node
*/
private Node getSibling(Node parent, Node node){
if(parent.right == node){
return parent.left;
}
return parent.right;
}
/**
* create frame and add tabbed pane
*/
@Override
public void display() {
JFrame frame = new JFrame("Balanced Persistent");
frame.add(jTabbedPane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
*
* @param e
* maintains visited nodes and old version of tree
*/
@Override
public void Visited(EventObject e) {
Node actualNode = ((Node) e.getSource()); //actual node
visited.add(actualNode); //add actual node to visited list
Node cloneNode = null;
try {
cloneNode = (Node)actualNode.clone(); //clone of actual node
} catch (CloneNotSupportedException cloneNotSupportedException) {
cloneNotSupportedException.printStackTrace();
}
if(lastNode == null) { //if last node is null make new tree version and update last node
lastNode = cloneNode;
BinarySearchTree tree1 = new BinarySearchTree(lastNode);
trees.add(tree1);
}
else{
//if actual node is left child of last node then attach its clone to left of last node and update last node
if(lastNode.left == actualNode || (lastNode.left == null && (lastNode.data).compareTo(actualNode.data) > 0)){
lastNode.left = cloneNode;
lastNode = cloneNode;
}
//if actual node is right child of last node then attach its clone to right of last node and update last node
else if(lastNode.right == actualNode || (lastNode.right == null && (lastNode.data).compareTo(actualNode.data) < 0)){
lastNode.right = cloneNode;
lastNode = cloneNode;
}
}
}
}