-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpersistent-bst.ts
More file actions
116 lines (89 loc) · 3.38 KB
/
persistent-bst.ts
File metadata and controls
116 lines (89 loc) · 3.38 KB
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
import Stack from './Stack'
/*
PURPOSE: to bring persistance in data structures
IMPLEMENTATION: using the tree method to keep track of history
EXPLANATION: Consider a persistent set S with the operations INSERT,DELETE,
and SEARCH, which we implement using binary search trees.
We maintain a separate root for every version of the set
REFERENCES: http://courses.csail.mit.edu/6.854/06/scribe/s2-persistent.pdf
https://en.wikipedia.org/wiki/Persistent_data_structure
https://walkccc.github.io/CLRS/Chap13/Problems/13-1/
FUTURE ROAD MAP: to implement this using 'Sleator, Tarjan et al' method which is more efficient in time and space than the present algorithm.
*/
class BSTTreeNode<T> {
public left: BSTTreeNode<T>;
public right: BSTTreeNode<T>;
public value: T;
constructor() {
this.left = null;
this.right = null;
this.value = null;
}
}
class BSTTree<T>{
private root: BSTTreeNode<T>;
private historyStack: persistanceTree<T>;
constructor() {
this.root = null;
this.historyStack = new persistanceTree();
}
insert(value: T) {
const node = new BSTTreeNode<T>();
node.value = value;
this.root = this.historyStack.insert(node);
}
}
class persistanceTree<T> {
private versionStack: Stack<BSTTreeNode<T>>;
constructor() {
this.versionStack = new Stack();
}
/**
*inserts node into bst by adding a new root to version stack
*
* @param {BSTTreeNode<T>} newNode
* @returns
* @memberof persistanceTree
*/
insert(newNode: BSTTreeNode<T>) {
// gets the old tree
const oldTreeRoot: BSTTreeNode<T> = this.versionStack.pop();
this.versionStack.revert();
// make a copy thereby creating new root
let newTreeRoot: BSTTreeNode<T> = { ...oldTreeRoot };
// to create new nodes in the traverse path
let newTreeTraverser: BSTTreeNode<T> = newTreeRoot;
// to track the tree
let traversalPointer: BSTTreeNode<T> = oldTreeRoot;
// to keep track of the node to which new node gets attached
let insertionPointer: BSTTreeNode<T>;
// stops either if tree doesn't have any nodes or the traversal has come to an end
while (traversalPointer) {
insertionPointer = newTreeTraverser;
if (newNode.value < traversalPointer.value) {
// making new copy as this path is getting affected
newTreeTraverser.left = { ...traversalPointer.left };
newTreeTraverser = newTreeTraverser.left;
traversalPointer = traversalPointer.left;
} else {
newTreeTraverser.right = { ...traversalPointer.right };
newTreeTraverser = newTreeTraverser.right;
traversalPointer = traversalPointer.right;
}
}
// if no elements in tree
if (!insertionPointer) {
newTreeRoot = newNode;
}
// else add either to left or right child
else if (newNode.value < insertionPointer.value) {
insertionPointer.left = newNode;
}
else {
insertionPointer.right = newNode;
}
// add this new tree to version stack and return
this.versionStack.push(newTreeRoot);
return newTreeRoot;
}
}