Skip to content

Commit 0725446

Browse files
authored
Merge pull request #56 from datastructures-js/find_key
allow finding nodes by key
2 parents 4cbaa21 + 5e23eca commit 0725446

File tree

6 files changed

+97
-13
lines changed

6 files changed

+97
-13
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ Binary Search Tree & AVL Tree (Self Balancing Tree) implementation in javascript
1515
* [constructor](#constructor)
1616
* [insert](#insert)
1717
* [has](#has)
18+
* [hasKey](#haskey)
1819
* [find](#find)
20+
* [findKey](#findkey)
1921
* [min](#min)
2022
* [max](#max)
2123
* [lowerBound (floor)](#lowerbound-floor)
@@ -70,6 +72,8 @@ the compare function must return a number for the 3 cases:
7072

7173
There is already a default compare function for primitive values (number, string).
7274

75+
constructor also accepts an options param, where the comparison key prob name can be passed for object types in order to search by that key directly using findKey and hasKey.
76+
7377
##### JS
7478
###### BinarySearchTree
7579
```js
@@ -80,7 +84,7 @@ const employees = new BinarySearchTree((a, b) => a.id - b.id);
8084
###### AvlTree
8185
```js
8286
const nums = new AvlTree();
83-
const employees = new AvlTree((a, b) => a.id - b.id);
87+
const employees = new AvlTree((a, b) => a.id - b.id, { key: 'id' });
8488
```
8589

8690
##### TS
@@ -93,13 +97,13 @@ interface IEmployee {
9397
###### BinarySearchTree
9498
```js
9599
const nums = new BinarySearchTree<number>();
96-
const employees = new BinarySearchTree<IEmployee>((a, b) => a.id - b.id);
100+
const employees = new BinarySearchTree<IEmployee>((a, b) => a.id - b.id, { key: 'id' });
97101
```
98102

99103
###### AvlTree
100104
```js
101105
const nums = new AvlTree<number>();
102-
const employees = new AvlTree<IEmployee>((a, b) => a.id - b.id);
106+
const employees = new AvlTree<IEmployee>((a, b) => a.id - b.id, { key: 'id' });
103107
```
104108

105109
### insert
@@ -140,6 +144,16 @@ employees.has({ id: 50 }); // true
140144
employees.has({ id: 100 }); // false
141145
```
142146

147+
### hasKey
148+
O(log(n))
149+
150+
checks if a value exists by its key if the node's key prob is provided in the constructor.
151+
152+
```js
153+
employees.has(50); // true
154+
employees.has(100); // false
155+
```
156+
143157
### find
144158
O(log(n))
145159

@@ -153,6 +167,16 @@ employees.find({ id: 60 }).getValue(); // { id: 60 }
153167
employees.find({ id: 100 }); // null
154168
```
155169

170+
### findKey
171+
O(log(n))
172+
173+
finds a node by its key if the node's key prob is provided in the constructor.
174+
175+
```js
176+
employees.findKey(60).getValue(); // { id: 60 }
177+
employees.find(100); // null
178+
```
179+
156180
### min
157181
O(log(n))
158182

src/avlTree.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { BinarySearchTree } from './binarySearchTree';
22
import { AvlTreeNode } from './avlTreeNode';
33

44
export class AvlTree<T> extends BinarySearchTree<T> {
5-
constructor(compare?: (a: T, b: T) => number);
5+
constructor(compare?: (a: T, b: T) => number, options?: { key: string });
66
insert(value: T): AvlTree<T>;
77
find(value: T): AvlTreeNode<T> | null;
8+
findKey(key: number|string): AvlTreeNode<T> | null;
89
max(node?: AvlTreeNode<T>): AvlTreeNode<T> | null;
910
min(node?: AvlTreeNode<T>): AvlTreeNode<T> | null;
1011
lowerBound(value: T, includeEqual?: boolean): AvlTreeNode<T> | null;

src/avlTree.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ const { AvlTreeNode } = require('./avlTreeNode');
1212
* @extends BinarySearchTree
1313
*/
1414
class AvlTree extends BinarySearchTree {
15-
constructor(compare) {
15+
constructor(compare, options) {
1616
if (compare && typeof compare !== 'function') {
1717
throw new Error('AvlTree constructor expects a compare function');
1818
}
1919

20-
super(compare);
20+
super(compare, options);
2121
}
2222

2323
/**

src/binarySearchTree.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { BinarySearchTreeNode } from './binarySearchTreeNode';
22

33
export class BinarySearchTree<T> {
4-
constructor(compare?: (a: T, b: T) => number);
4+
constructor(compare?: (a: T, b: T) => number, options?: { key: string });
55
insert(value: T): BinarySearchTree<T>;
66
has(value: T): boolean;
7+
hasKey(key: number|string): boolean;
78
find(value: T): BinarySearchTreeNode<T> | null;
9+
findKey(key: number|string): BinarySearchTreeNode<T> | null;
810
max(node?: BinarySearchTreeNode<T>): BinarySearchTreeNode<T> | null;
911
min(node?: BinarySearchTreeNode<T>): BinarySearchTreeNode<T> | null;
1012
lowerBound(value: T, includeEqual?: boolean): BinarySearchTreeNode<T> | null;

src/binarySearchTree.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ const defaultCompare = (a, b) => {
1515
* @class BinarySearchTree
1616
*/
1717
class BinarySearchTree {
18-
constructor(compare) {
18+
constructor(compare, options) {
1919
if (compare && typeof compare !== 'function') {
2020
throw new Error('BinarySearchTree constructor expects a compare function');
2121
}
2222

2323
this._compare = compare || defaultCompare;
24+
this._options = options || {};
2425
this._root = null;
2526
this._count = 0;
2627
}
@@ -65,9 +66,9 @@ class BinarySearchTree {
6566
}
6667

6768
/**
68-
* Checks if a value exists in the tree by its key
69+
* Checks if a value exists in the tree by its value
6970
* @public
70-
* @param {number|string} key
71+
* @param {number|string|object} value
7172
* @return {boolean}
7273
*/
7374
has(value) {
@@ -84,9 +85,22 @@ class BinarySearchTree {
8485
}
8586

8687
/**
87-
* Finds a node by its key
88+
* Checks if a value exists in the tree by its key
8889
* @public
8990
* @param {number|string} key
91+
* @return {boolean}
92+
*/
93+
hasKey(key) {
94+
if (this._options.key === undefined || this._options.key === null) {
95+
throw new Error('Missing key prop name in constructor options');
96+
}
97+
return this.has({ [this._options.key]: key });
98+
}
99+
100+
/**
101+
* Finds a node by its value
102+
* @public
103+
* @param {number|string|object} value
90104
* @return {BinarySearchTreeNode}
91105
*/
92106
find(value) {
@@ -102,6 +116,19 @@ class BinarySearchTree {
102116
return findRecursive(this._root);
103117
}
104118

119+
/**
120+
* Finds a node by its key
121+
* @public
122+
* @param {number|string} key
123+
* @return {BinarySearchTreeNode}
124+
*/
125+
findKey(key) {
126+
if (this._options.key === undefined || this._options.key === null) {
127+
throw new Error('Missing key prop name in constructor options');
128+
}
129+
return this.find({ [this._options.key]: key });
130+
}
131+
105132
/**
106133
* Finds the node with max key (most right) in the tree
107134
* @public

test/binarySearchTree.test.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('BinarySearchTree tests', () => {
3636
});
3737

3838
describe('.has(value)', () => {
39-
it('checks if a node exists by key', () => {
39+
it('checks if a node exists by value', () => {
4040
expect(bst.has(50)).to.equal(true);
4141
expect(bst.has(80)).to.equal(true);
4242
expect(bst.has(30)).to.equal(true);
@@ -48,8 +48,23 @@ describe('BinarySearchTree tests', () => {
4848
});
4949
});
5050

51+
describe('.has(key)', () => {
52+
it('checks if a node exists by key', () => {
53+
const testTree = new BinarySearchTree((a, b) => a.id - b.id, { key: 'id' });
54+
testTree.insert({ id: 1, name: 'a' });
55+
testTree.insert({ id: 2, name: 'b' });
56+
testTree.insert({ id: 3, name: 'c' });
57+
expect(testTree.has({ id: 1 })).to.equal(true);
58+
expect(testTree.has({ id: 2 })).to.equal(true);
59+
expect(testTree.has({ id: 3 })).to.equal(true);
60+
expect(testTree.hasKey(1)).to.equal(true);
61+
expect(testTree.hasKey(2)).to.equal(true);
62+
expect(testTree.hasKey(3)).to.equal(true);
63+
});
64+
});
65+
5166
describe('.find(value)', () => {
52-
it('should search a node by its key in the tree', () => {
67+
it('should search a node by its value in the tree', () => {
5368
expect(bst.find(50)).to.be.instanceof(BinarySearchTreeNode);
5469
expect(bst.find(80)).to.be.instanceof(BinarySearchTreeNode);
5570
expect(bst.find(30)).to.be.instanceof(BinarySearchTreeNode);
@@ -61,6 +76,21 @@ describe('BinarySearchTree tests', () => {
6176
});
6277
});
6378

79+
describe('.findKey(key)', () => {
80+
it('should search a node by its key in the tree', () => {
81+
const testTree = new BinarySearchTree((a, b) => a.id - b.id, { key: 'id' });
82+
testTree.insert({ id: 1, name: 'a' });
83+
testTree.insert({ id: 2, name: 'b' });
84+
testTree.insert({ id: 3, name: 'c' });
85+
expect(testTree.find({ id: 1 }).getValue()).to.eql({ id: 1, name: 'a' });
86+
expect(testTree.find({ id: 2 }).getValue()).to.eql({ id: 2, name: 'b' });
87+
expect(testTree.find({ id: 3 }).getValue()).to.eql({ id: 3, name: 'c' });
88+
expect(testTree.findKey(1).getValue()).to.eql({ id: 1, name: 'a' });
89+
expect(testTree.findKey(2).getValue()).to.eql({ id: 2, name: 'b' });
90+
expect(testTree.findKey(3).getValue()).to.eql({ id: 3, name: 'c' });
91+
});
92+
});
93+
6494
describe('.max()', () => {
6595
it('get the node with max key', () => {
6696
const max = bst.max();

0 commit comments

Comments
 (0)