Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8320154

Browse files
change tree node for binary tree node
1 parent 7d88199 commit 8320154

File tree

9 files changed

+240
-263
lines changed

9 files changed

+240
-263
lines changed

‎src/data-structures/sets/set.spec.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ setImplementations.forEach((MySet) => {
5858
expect(set.delete(2)).toBe(true);
5959
expect(Array.from(set.entries())).toEqual([[0, 0], [1, 1], [3, 3]]);
6060
expect(set.delete(0)).toBe(true);
61+
expect(Array.from(set.entries())).toEqual([[1, 1], [3, 3]]);
6162

6263
expect(Array.from(set)).toEqual([1, 3]);
6364
expect(set.size).toBe(2);

‎src/data-structures/trees/binary-search-tree.js‎

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const TreeNode = require('./tree-node');
1+
const BinaryTreeNode = require('./binary-tree-node');
22
const Queue = require('../queues/queue');
33
const Stack = require('../stacks/stack');
44
// tag::snippet[]
@@ -17,16 +17,16 @@ class BinarySearchTree {
1717
* @param {any} value value to insert in the tree
1818
*/
1919
add(value) {
20-
const newNode = new TreeNode(value);
20+
const newNode = new BinaryTreeNode(value);
2121

2222
if (this.root) {
2323
const { found, parent } = this.findNodeAndParent(value); // <1>
2424
if (found) { // duplicated: value already exist on the tree
2525
found.meta.multiplicity = (found.meta.multiplicity || 1) + 1; // <2>
2626
} else if (value < parent.value) {
27-
parent.left=newNode;
27+
parent.setLeftAndUpdateParent(newNode);
2828
} else {
29-
parent.right=newNode;
29+
parent.setRightAndUpdateParent(newNode);
3030
}
3131
} else {
3232
this.root = newNode;
@@ -74,8 +74,8 @@ class BinarySearchTree {
7474

7575
/**
7676
* Get the node with the max value of subtree: the right-most value.
77-
* @param {TreeNode} node subtree's root
78-
* @returns {TreeNode} right-most node (max value)
77+
* @param {BinaryTreeNode} node subtree's root
78+
* @returns {BinaryTreeNode} right-most node (max value)
7979
*/
8080
getRightmost(node = this.root) {
8181
if (!node || !node.right) {
@@ -87,8 +87,8 @@ class BinarySearchTree {
8787
// tag::leftMost[]
8888
/**
8989
* Get the node with the min value of subtree: the left-most value.
90-
* @param {TreeNode} node subtree's root
91-
* @returns {TreeNode} left-most node (min value)
90+
* @param {BinaryTreeNode} node subtree's root
91+
* @returns {BinaryTreeNode} left-most node (min value)
9292
*/
9393
getLeftmost(node = this.root) {
9494
if (!node || !node.left) {
@@ -118,10 +118,11 @@ class BinarySearchTree {
118118
// Replace (root) node to delete with the combined subtree.
119119
this.root = removedNodeChildren;
120120
if (this.root) { this.root.parent = null; } // clearing up old parent
121-
} else { // <6>
122-
const side = nodeToRemove.isParentLeftChild ? 'left' : 'right';
121+
} else if (nodeToRemove.isParentLeftChild) { // <6>
123122
// Replace node to delete with the combined subtree.
124-
parent[side] = removedNodeChildren;
123+
parent.setLeftAndUpdateParent(removedNodeChildren);
124+
} else {
125+
parent.setRightAndUpdateParent(removedNodeChildren);
125126
}
126127

127128
this.size -= 1;
@@ -146,13 +147,13 @@ class BinarySearchTree {
146147
* It takes node 30 left subtree (10 and 15) and put it in the
147148
* leftmost node of the right subtree (40, 35, 50).
148149
*
149-
* @param {TreeNode} node
150-
* @returns {TreeNode} combined subtree
150+
* @param {BinaryTreeNode} node
151+
* @returns {BinaryTreeNode} combined subtree
151152
*/
152153
combineLeftIntoRightSubtree(node) {
153154
if (node.right) {
154155
const leftmost = this.getLeftmost(node.right);
155-
leftmost.left=node.left;
156+
leftmost.setLeftAndUpdateParent(node.left);
156157
return node.right;
157158
}
158159
return node.left;
@@ -171,7 +172,9 @@ class BinarySearchTree {
171172
while (!queue.isEmpty()) {
172173
const node = queue.remove();
173174
yield node;
174-
node.descendents.forEach(child => queue.add(child));
175+
176+
if (node.left) { queue.add(node.left); }
177+
if (node.right) { queue.add(node.right); }
175178
}
176179
}
177180

@@ -188,8 +191,9 @@ class BinarySearchTree {
188191
while (!stack.isEmpty()) {
189192
const node = stack.remove();
190193
yield node;
191-
// reverse array, so left gets removed before right
192-
node.descendents.reverse().forEach(child => stack.add(child));
194+
195+
if (node.right) { stack.add(node.right); }
196+
if (node.left) { stack.add(node.left); }
193197
}
194198
}
195199

@@ -198,19 +202,19 @@ class BinarySearchTree {
198202
*
199203
* If the tree is a BST, then the values will be sorted in ascendent order
200204
*
201-
* @param {TreeNode} node first node to start the traversal
205+
* @param {BinaryTreeNode} node first node to start the traversal
202206
*/
203207
* inOrderTraversal(node = this.root) {
204-
if (node.left) { yield* this.inOrderTraversal(node.left); }
208+
if (node&&node.left) { yield* this.inOrderTraversal(node.left); }
205209
yield node;
206-
if (node.right) { yield* this.inOrderTraversal(node.right); }
210+
if (node&&node.right) { yield* this.inOrderTraversal(node.right); }
207211
}
208212

209213
/**
210214
* Pre-order traversal on a tree: root-left-right.
211215
* Similar results to DFS
212216
*
213-
* @param {TreeNode} node first node to start the traversal
217+
* @param {BinaryTreeNode} node first node to start the traversal
214218
* @see dfs similar results to the breath first search
215219
*/
216220
* preOrderTraversal(node = this.root) {
@@ -222,7 +226,7 @@ class BinarySearchTree {
222226
/**
223227
* Post-order traversal on a tree: left-right-root.
224228
*
225-
* @param {TreeNode} node first node to start the traversal
229+
* @param {BinaryTreeNode} node first node to start the traversal
226230
*/
227231
* postOrderTraversal(node = this.root) {
228232
if (node.left) { yield* this.postOrderTraversal(node.left); }
Lines changed: 158 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,170 @@
1+
const LEFT = Symbol('left');
2+
const RIGHT = Symbol('right');
3+
4+
// tag::snippet[]
15
/**
26
* Binary Tree Node
3-
*@deprecated Use TreeNode instead
7+
*
48
*/
5-
// tag::snippet[]
69
class BinaryTreeNode {
710
constructor(value) {
811
this.value = value;
912
this.left = null;
1013
this.right = null;
14+
this.parent = null;
15+
this.parentSide = null;
16+
this.meta = {};
17+
}
18+
// end::snippet[]
19+
20+
/**
21+
* Set a left node descendents.
22+
* Also, children get associated to parent.
23+
*/
24+
setLeftAndUpdateParent(node) {
25+
this.left = node;
26+
if (node) {
27+
node.parent = this;
28+
node.parentSide = LEFT;
29+
}
30+
}
31+
32+
/**
33+
* Set a right node descendents.
34+
* Also, children get associated to parent.
35+
*/
36+
setRightAndUpdateParent(node) {
37+
this.right = node;
38+
if (node) {
39+
node.parent = this;
40+
node.parentSide = RIGHT;
41+
}
42+
}
43+
44+
/**
45+
* Tell if is parent's left or right child
46+
*
47+
* @returns {string} side (left or right) this node is of its parent
48+
*/
49+
get parentChildSide() {
50+
if (this.parent) {
51+
return this.isParentLeftChild ? 'left' : 'right';
52+
}
53+
54+
return 'root';
55+
}
56+
57+
/**
58+
* Return true if this node is its parent left child
59+
*/
60+
get isParentLeftChild() {
61+
return this.parentSide === LEFT;
62+
}
63+
64+
/**
65+
* Return true if this node is its parent right child
66+
*/
67+
get isParentRightChild() {
68+
return this.parentSide === RIGHT;
69+
}
70+
71+
/**
72+
* Node is leaf is it has no descendents
73+
*/
74+
get isLeaf() {
75+
return !this.left && !this.right;
76+
}
77+
78+
/**
79+
* Get sibling of current node
80+
*/
81+
get sibling() {
82+
const { parent } = this;
83+
if (!parent) return null;
84+
return parent.right === this ? parent.left : parent.right;
85+
}
86+
87+
/**
88+
* Get parent sibling = uncle (duh)
89+
*/
90+
get uncle() {
91+
const { parent } = this;
92+
if (!parent) return null;
93+
return parent.sibling;
94+
}
95+
96+
get grandparent() {
97+
const { parent } = this;
98+
return parent && parent.parent;
99+
}
100+
101+
/**
102+
* Get color
103+
*/
104+
get color() {
105+
return this.meta.color;
106+
}
107+
108+
/**
109+
* Set Color
110+
*/
111+
set color(value) {
112+
this.meta.color = value;
113+
}
114+
115+
/**
116+
* Get the max height of the subtrees.
117+
*
118+
* It recursively goes into each children calculating the height
119+
*
120+
* Height: distance from the deepest leaf to this node
121+
*/
122+
get height() {
123+
return Math.max(this.leftSubtreeHeight, this.rightSubtreeHeight);
124+
}
125+
126+
get leftSubtreeHeight() {
127+
return this.left ? this.left.height + 1 : 0;
128+
}
129+
130+
get rightSubtreeHeight() {
131+
return this.right ? this.right.height + 1 : 0;
132+
}
133+
134+
/**
135+
* Returns the difference the heights on the left and right subtrees
136+
*/
137+
get balanceFactor() {
138+
return this.leftSubtreeHeight - this.rightSubtreeHeight;
139+
}
140+
141+
/**
142+
* Serialize node's values
143+
*/
144+
toValues() {
145+
return {
146+
value: this.value,
147+
left: this.left && this.left.value,
148+
right: this.right && this.right.value,
149+
parent: this.parent && this.parent.value,
150+
parentSide: this.parentSide,
151+
};
152+
}
153+
154+
/**
155+
* Get and Set data value
156+
* @param {any} value (optional) if not provided is a getter, otherwise a setter.
157+
*/
158+
data(value) {
159+
if (value === undefined) {
160+
return this.meta.data;
161+
}
162+
this.meta.data = value;
163+
return this;
11164
}
12165
}
13-
// end::snippet[]
166+
167+
BinaryTreeNode.RIGHT = RIGHT;
168+
BinaryTreeNode.LEFT = LEFT;
14169

15170
module.exports = BinaryTreeNode;

‎src/data-structures/trees/tree-node.spec.js‎ renamed to ‎src/data-structures/trees/binary-tree-node.spec.js‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
const TreeNode = require('./tree-node');
1+
const BinaryTreeNode = require('./binary-tree-node');
22

3-
describe('Tree Node', () => {
3+
describe('Binary Tree Node', () => {
44
let treeNode;
55

66
beforeEach(() => {
7-
treeNode = new TreeNode('hola');
7+
treeNode = new BinaryTreeNode('hola');
88
});
99

1010
it('should start with null parent', () => {
@@ -25,8 +25,8 @@ describe('Tree Node', () => {
2525

2626
it('should set/get left node', () => {
2727
expect(treeNode.left).toBe(null);
28-
const newNode = new TreeNode(1);
29-
treeNode.left=newNode;
28+
const newNode = new BinaryTreeNode(1);
29+
treeNode.setLeftAndUpdateParent(newNode);
3030
expect(treeNode.left.value).toBe(1);
3131

3232
expect(newNode.parent).toBe(treeNode);
@@ -36,8 +36,8 @@ describe('Tree Node', () => {
3636

3737
it('should set/get right node', () => {
3838
expect(treeNode.right).toBe(null);
39-
const newNode = new TreeNode(1);
40-
treeNode.right=newNode;
39+
const newNode = new BinaryTreeNode(1);
40+
treeNode.setRightAndUpdateParent(newNode);
4141

4242
expect(treeNode.right.value).toBe(1);
4343
expect(newNode.parent).toBe(treeNode);
@@ -53,16 +53,16 @@ describe('Tree Node', () => {
5353
let s;
5454

5555
beforeEach(() => {
56-
g = new TreeNode('grandparent');
57-
p = new TreeNode('parent');
58-
u = new TreeNode('uncle');
59-
c = new TreeNode('child');
60-
s = new TreeNode('sibling');
61-
62-
g.right=p;
63-
g.left=u;
64-
p.right=c;
65-
p.left=s;
56+
g = new BinaryTreeNode('grandparent');
57+
p = new BinaryTreeNode('parent');
58+
u = new BinaryTreeNode('uncle');
59+
c = new BinaryTreeNode('child');
60+
s = new BinaryTreeNode('sibling');
61+
62+
g.setRightAndUpdateParent(p);
63+
g.setLeftAndUpdateParent(u);
64+
p.setRightAndUpdateParent(c);
65+
p.setLeftAndUpdateParent(s);
6666
});
6767

6868
it('should set heights', () => {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /