mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-07-07 01:44:52 +08:00
Use Map for node meta data.
This commit is contained in:
@ -3,14 +3,15 @@ import Comparator from '../../utils/comparator/Comparator';
|
|||||||
export default class BinaryTreeNode {
|
export default class BinaryTreeNode {
|
||||||
/**
|
/**
|
||||||
* @param {*} [value] - node value.
|
* @param {*} [value] - node value.
|
||||||
* @param {Object} meta - any meta information that needs to be attached to the node.
|
|
||||||
*/
|
*/
|
||||||
constructor(value = null, meta = {}) {
|
constructor(value = null) {
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.right = null;
|
this.right = null;
|
||||||
this.parent = null;
|
this.parent = null;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.meta = meta;
|
|
||||||
|
// Any node related meta information may be stored here.
|
||||||
|
this.meta = new Map();
|
||||||
|
|
||||||
// This comparator is used to compare binary tree nodes with each other.
|
// This comparator is used to compare binary tree nodes with each other.
|
||||||
this.nodeComparator = new Comparator();
|
this.nodeComparator = new Comparator();
|
||||||
@ -157,29 +158,6 @@ export default class BinaryTreeNode {
|
|||||||
return traverse;
|
return traverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} property
|
|
||||||
* @param {*} value
|
|
||||||
* @return {BinaryTreeNode}
|
|
||||||
*/
|
|
||||||
setMeta(property, value) {
|
|
||||||
this.meta[property] = value;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param property
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
getMeta(property) {
|
|
||||||
if (!this.meta || !Object.prototype.hasOwnProperty.call(this.meta, property)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.meta[property];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
|
@ -198,29 +198,13 @@ describe('BinaryTreeNode', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be possible to attach meta information to the node', () => {
|
it('should be possible to attach meta information to the node', () => {
|
||||||
const redNode = new BinaryTreeNode(1, { color: 'red' });
|
const redNode = new BinaryTreeNode(1);
|
||||||
const blackNode = new BinaryTreeNode(2, { color: 'black' });
|
const blackNode = new BinaryTreeNode(2);
|
||||||
|
|
||||||
expect(redNode.meta.color).toBe('red');
|
redNode.meta.set('color', 'red');
|
||||||
expect(blackNode.meta.color).toBe('black');
|
blackNode.meta.set('color', 'black');
|
||||||
});
|
|
||||||
|
|
||||||
it('should be possible to use get/set methods to change node meta information', () => {
|
expect(redNode.meta.get('color')).toBe('red');
|
||||||
const redNode = new BinaryTreeNode(1, { color: 'red' });
|
expect(blackNode.meta.get('color')).toBe('black');
|
||||||
const blackNode = new BinaryTreeNode(2, { color: 'black' });
|
|
||||||
|
|
||||||
expect(redNode.getMeta('color')).toBe('red');
|
|
||||||
expect(blackNode.getMeta('color')).toBe('black');
|
|
||||||
|
|
||||||
redNode.setMeta('size', 8);
|
|
||||||
|
|
||||||
expect(redNode.getMeta('size')).toBe(8);
|
|
||||||
expect(redNode.getMeta('color')).toBe('red');
|
|
||||||
expect(redNode.getMeta('not_existing')).toBeNull();
|
|
||||||
|
|
||||||
// It must also be possible to override meta information.
|
|
||||||
redNode.setMeta('color', 'blue');
|
|
||||||
expect(redNode.getMeta('size')).toBe(8);
|
|
||||||
expect(redNode.getMeta('color')).toBe('blue');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@ export default class BinarySearchTree {
|
|||||||
* @param {function} [nodeValueCompareFunction]
|
* @param {function} [nodeValueCompareFunction]
|
||||||
*/
|
*/
|
||||||
constructor(nodeValueCompareFunction) {
|
constructor(nodeValueCompareFunction) {
|
||||||
this.root = new BinarySearchTreeNode(null, null, nodeValueCompareFunction);
|
this.root = new BinarySearchTreeNode(null, nodeValueCompareFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,11 +4,10 @@ import Comparator from '../../../utils/comparator/Comparator';
|
|||||||
export default class BinarySearchTreeNode extends BinaryTreeNode {
|
export default class BinarySearchTreeNode extends BinaryTreeNode {
|
||||||
/**
|
/**
|
||||||
* @param {*} [value] - node value.
|
* @param {*} [value] - node value.
|
||||||
* @param {Object} [meta] - any meta information that is attached to the node.
|
|
||||||
* @param {function} [compareFunction] - comparator function for node values.
|
* @param {function} [compareFunction] - comparator function for node values.
|
||||||
*/
|
*/
|
||||||
constructor(value = null, meta = null, compareFunction = undefined) {
|
constructor(value = null, compareFunction = undefined) {
|
||||||
super(value, meta);
|
super(value);
|
||||||
|
|
||||||
// This comparator is used to compare node values with each other.
|
// This comparator is used to compare node values with each other.
|
||||||
this.compareFunction = compareFunction;
|
this.compareFunction = compareFunction;
|
||||||
@ -17,13 +16,11 @@ export default class BinarySearchTreeNode extends BinaryTreeNode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
* @param {Object} [meta]
|
|
||||||
* @return {BinarySearchTreeNode}
|
* @return {BinarySearchTreeNode}
|
||||||
*/
|
*/
|
||||||
insert(value, meta = null) {
|
insert(value) {
|
||||||
if (this.nodeValueComparator.equal(this.value, null)) {
|
if (this.nodeValueComparator.equal(this.value, null)) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.meta = meta;
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -31,17 +28,23 @@ export default class BinarySearchTreeNode extends BinaryTreeNode {
|
|||||||
if (this.nodeValueComparator.lessThan(value, this.value)) {
|
if (this.nodeValueComparator.lessThan(value, this.value)) {
|
||||||
// Insert to the left.
|
// Insert to the left.
|
||||||
if (this.left) {
|
if (this.left) {
|
||||||
this.left.insert(value, meta);
|
return this.left.insert(value);
|
||||||
} else {
|
|
||||||
this.setLeft(new BinarySearchTreeNode(value, meta, this.compareFunction));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newNode = new BinarySearchTreeNode(value, this.compareFunction);
|
||||||
|
this.setLeft(newNode);
|
||||||
|
|
||||||
|
return newNode;
|
||||||
} else if (this.nodeValueComparator.greaterThan(value, this.value)) {
|
} else if (this.nodeValueComparator.greaterThan(value, this.value)) {
|
||||||
// Insert to the right.
|
// Insert to the right.
|
||||||
if (this.right) {
|
if (this.right) {
|
||||||
this.right.insert(value, meta);
|
return this.right.insert(value);
|
||||||
} else {
|
|
||||||
this.setRight(new BinarySearchTreeNode(value, meta, this.compareFunction));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newNode = new BinarySearchTreeNode(value, this.compareFunction);
|
||||||
|
this.setRight(newNode);
|
||||||
|
|
||||||
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -78,6 +81,7 @@ export default class BinarySearchTreeNode extends BinaryTreeNode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
|
* @return {BinarySearchTreeNode}
|
||||||
*/
|
*/
|
||||||
remove(value) {
|
remove(value) {
|
||||||
const nodeToRemove = this.find(value);
|
const nodeToRemove = this.find(value);
|
||||||
@ -115,6 +119,8 @@ export default class BinarySearchTreeNode extends BinaryTreeNode {
|
|||||||
parent.replaceChild(nodeToRemove, nodeToRemove.right);
|
parent.replaceChild(nodeToRemove, nodeToRemove.right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nodeToRemove;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,14 +20,16 @@ describe('BinarySearchTreeNode', () => {
|
|||||||
|
|
||||||
it('should insert nodes in correct order', () => {
|
it('should insert nodes in correct order', () => {
|
||||||
const bstNode = new BinarySearchTreeNode(2);
|
const bstNode = new BinarySearchTreeNode(2);
|
||||||
bstNode.insert(1);
|
const insertedNode1 = bstNode.insert(1);
|
||||||
|
|
||||||
|
expect(insertedNode1.value).toBe(1);
|
||||||
expect(bstNode.toString()).toBe('1,2');
|
expect(bstNode.toString()).toBe('1,2');
|
||||||
expect(bstNode.contains(1)).toBeTruthy();
|
expect(bstNode.contains(1)).toBeTruthy();
|
||||||
expect(bstNode.contains(3)).toBeFalsy();
|
expect(bstNode.contains(3)).toBeFalsy();
|
||||||
|
|
||||||
bstNode.insert(3);
|
const insertedNode2 = bstNode.insert(3);
|
||||||
|
|
||||||
|
expect(insertedNode2.value).toBe(3);
|
||||||
expect(bstNode.toString()).toBe('1,2,3');
|
expect(bstNode.toString()).toBe('1,2,3');
|
||||||
expect(bstNode.contains(3)).toBeTruthy();
|
expect(bstNode.contains(3)).toBeTruthy();
|
||||||
expect(bstNode.contains(4)).toBeFalsy();
|
expect(bstNode.contains(4)).toBeFalsy();
|
||||||
@ -80,20 +82,24 @@ describe('BinarySearchTreeNode', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be possible to attach meta information to binary search tree nodes', () => {
|
it('should be possible to attach meta information to binary search tree nodes', () => {
|
||||||
const node = new BinarySearchTreeNode(10, { value: 10 });
|
const node = new BinarySearchTreeNode(10);
|
||||||
|
|
||||||
node.insert(20, { value: 20 });
|
node.insert(20);
|
||||||
node.insert(30, { value: 30 });
|
const node1 = node.insert(30);
|
||||||
node.insert(5, { value: 5 });
|
node.insert(5);
|
||||||
node.insert(40, { value: 40 });
|
node.insert(40);
|
||||||
node.insert(1, { value: 1 });
|
const node2 = node.insert(1);
|
||||||
|
|
||||||
expect(node.meta.value).toBe(10);
|
node.meta.set('color', 'red');
|
||||||
|
node1.meta.set('color', 'black');
|
||||||
|
node2.meta.set('color', 'white');
|
||||||
|
|
||||||
|
expect(node.meta.get('color')).toBe('red');
|
||||||
|
|
||||||
expect(node.findMin()).not.toBeNull();
|
expect(node.findMin()).not.toBeNull();
|
||||||
expect(node.findMin().value).toBe(1);
|
expect(node.findMin().value).toBe(1);
|
||||||
expect(node.findMin().meta.value).toBe(1);
|
expect(node.findMin().meta.get('color')).toBe('white');
|
||||||
expect(node.find(30).meta.value).toBe(30);
|
expect(node.find(30).meta.get('color')).toBe('black');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should find node', () => {
|
it('should find node', () => {
|
||||||
@ -205,7 +211,7 @@ describe('BinarySearchTreeNode', () => {
|
|||||||
const obj2 = { key: 'obj2', value: 2, toString: () => 'obj2' };
|
const obj2 = { key: 'obj2', value: 2, toString: () => 'obj2' };
|
||||||
const obj3 = { key: 'obj3', value: 3, toString: () => 'obj3' };
|
const obj3 = { key: 'obj3', value: 3, toString: () => 'obj3' };
|
||||||
|
|
||||||
const bstNode = new BinarySearchTreeNode(obj2, null, nodeValueComparatorCallback);
|
const bstNode = new BinarySearchTreeNode(obj2, nodeValueComparatorCallback);
|
||||||
bstNode.insert(obj1);
|
bstNode.insert(obj1);
|
||||||
|
|
||||||
expect(bstNode.toString()).toBe('obj1,obj2');
|
expect(bstNode.toString()).toBe('obj1,obj2');
|
||||||
|
Reference in New Issue
Block a user