Skip to content

Commit

Permalink
Merge pull request #44 from datastructures-js/development
Browse files Browse the repository at this point in the history
v4.3.0
  • Loading branch information
eyas-ranjous authored Aug 8, 2021
2 parents c325c07 + 2c46860 commit 74e9a83
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 44 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [4.3.0] - 2021-08-09
### Added
- `.floor` & `.ceil` as delegates to `.lowerBound` & `upperBound`.

### Fixed
- `.lowerBound` & `upperBound` now finds the precise bound when multiple ones exist.
- make param (value) optional on `.insert`.

## [4.2.2] - 2021-06-20

### Fixed
- index.d.ts


## [4.2.1] - 2021-06-20

### Fixed
Expand Down
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ Binary Search Tree & AVL Tree (Self Balancing Tree) implementation in javascript
* [.find(key)](#findkey)
* [.min()](#min)
* [.max()](#max)
* [.lowerBound(k)](#lowerboundk)
* [.upperBound(k)](#upperboundk)
* [.lowerBound(k[, includeEqual]) (floor)](#lowerboundk-includeEqual-floor)
* [.upperBound(k[, includeEqual]) (ceil)](#upperboundk-includeEqual-ceil)
* [.root()](#root)
* [.count()](#count)
* [.traverseInOrder(cb)](#traverseinordercb)
Expand Down Expand Up @@ -219,8 +219,8 @@ console.log(max.getKey()); // 90
console.log(max.getValue()); // v4
```

### .lowerBound(k)
finds the node with the biggest key less or equal a given value k.
### .lowerBound(k[, includeEqual]) (.floor)
finds the node with the biggest key less or equal a given value k. You can eliminate equal keys by passing second param as false. `.floor` is a delegate to the same function.

<table>
<tr>
Expand All @@ -229,19 +229,24 @@ finds the node with the biggest key less or equal a given value k.
<th align="center">runtime</th>
</tr>
<tr>
<td>k: T (number | string)</td>
<td>
k: T (number | string)
<br />
includeEqual: boolean
</td>
<td align="center"><a href="#binarysearchtreenodet-u">BinarySearchTreeNode&lt;T, U&gt;</a> | <a href="#avltreenodet-u">AvlTreeNode&lt;T, U&gt;</a></td>
<td align="center">O(log(n))</td>
</tr>
</table>

```js
console.log(bst.lowerBound(60).getKey()); // 50
console.log(bst.lowerBound(60).getKey()); // 60
console.log(bst.lowerBound(60, false).getKey()); // 50
console.log(bst.lowerBound(10)); // null
```

### .upperBound(k)
finds the node with the smallest key bigger than a given value k.
### .upperBound(k[, includeEqual]) (.ceil)
finds the node with the smallest key bigger or equal a given value k. You can eliminate equal keys by passing second param as false. `.ceil` is a delegate to the same function.

<table>
<tr>
Expand All @@ -250,14 +255,20 @@ finds the node with the smallest key bigger than a given value k.
<th align="center">runtime</th>
</tr>
<tr>
<td>k: T (number | string)</td>
<td>
k: T (number | string)
<br />
includeEqual: boolean
</td>
<td align="center"><a href="#binarysearchtreenodet-u">BinarySearchTreeNode&lt;T, U&gt;</a> | <a href="#avltreenodet-u">AvlTreeNode&lt;T, U&gt;</a></td>
<td align="center">O(log(n))</td>
</tr>
</table>

```js
console.log(bst.upperBound(75).getKey()); // 80
console.log(bst.upperBound(80).getKey()); // 80
console.log(bst.upperBound(80, false).getKey()); // 90
console.log(bst.upperBound(110)); // null
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@datastructures-js/binary-search-tree",
"version": "4.2.2",
"version": "4.3.0",
"description": "binary search tree & avl tree (self balancing tree) implementation in javascript",
"main": "index.js",
"scripts": {
Expand Down
8 changes: 5 additions & 3 deletions src/avlTree.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { BinarySearchTree } from './binarySearchTree';
import { AvlTreeNode } from './avlTreeNode';

export class AvlTree<T extends number|string, U = undefined> extends BinarySearchTree<T, U> {
insert(key: T, value: U): AvlTreeNode<T, U>;
insert(key: T, value?: U): AvlTreeNode<T, U>;
find(key: T): AvlTreeNode<T, U>;
max(node?: AvlTreeNode<T, U>): AvlTreeNode<T, U>;
min(node?: AvlTreeNode<T, U>): AvlTreeNode<T, U>;
lowerBound(k: T, node?: AvlTreeNode<T, U>): AvlTreeNode<T, U>;
upperBound(k: T, node?: AvlTreeNode<T, U>): AvlTreeNode<T, U>;
lowerBound(k: T, includeEqual?: boolean): AvlTreeNode<T, U>;
floor(k: T, includeEqual?: boolean): AvlTreeNode<T, U>;
upperBound(k: T, includeEqual?: boolean): AvlTreeNode<T, U>;
ceil(k: T, includeEqual?: boolean): AvlTreeNode<T, U>;
root(): AvlTreeNode<T, U>;
traverseInOrder(cb: (node: AvlTreeNode<T, U>) => void): void;
traversePreOrder(cb: (node: AvlTreeNode<T, U>) => void): void;
Expand Down
8 changes: 5 additions & 3 deletions src/binarySearchTree.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { BinarySearchTreeNode } from './binarySearchTreeNode';

export class BinarySearchTree<T extends number|string, U = undefined> {
insert(key: T, value: U): BinarySearchTreeNode<T, U>;
insert(key: T, value?: U): BinarySearchTreeNode<T, U>;
has(key: T): boolean;
find(key: T): BinarySearchTreeNode<T, U>;
max(node?: BinarySearchTreeNode<T, U>): BinarySearchTreeNode<T, U>;
min(node?: BinarySearchTreeNode<T, U>): BinarySearchTreeNode<T, U>;
lowerBound(k: T, node?: BinarySearchTreeNode<T, U>): BinarySearchTreeNode<T, U>;
upperBound(k: T, node?: BinarySearchTreeNode<T, U>): BinarySearchTreeNode<T, U>;
lowerBound(k: T, includeEqual?: boolean): BinarySearchTreeNode<T, U>;
floor(k: T, includeEqual?: boolean): BinarySearchTreeNode<T, U>;
upperBound(k: T, includeEqual?: boolean): BinarySearchTreeNode<T, U>;
ceil(k: T, includeEqual?: boolean): BinarySearchTreeNode<T, U>;
root(): BinarySearchTreeNode<T, U>;
count(): number;
remove(k: T): boolean;
Expand Down
84 changes: 58 additions & 26 deletions src/binarySearchTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,48 +146,80 @@ class BinarySearchTree {
* Returns the node with the biggest key less or equal to k
* @public
* @param {number|string} k
* @param {boolean} includeEqual
* @return {BinarySearchTreeNode|null}
*/
lowerBound(k, current = this._root) {
if (current === null) {
return null;
}
lowerBound(k, includeEqual = true) {
let lowerBound = null;

if (current.getKey() === k) {
return current;
}
const lowerBoundRecursive = (current) => {
if (current === null) {
return lowerBound;
}

if (current.getKey() > k) {
return this.lowerBound(k, current.getLeft());
}
const currentKey = current.getKey();
if (currentKey < k || (includeEqual && currentKey === k)) {
if (lowerBound === null || lowerBound.getKey() <= currentKey) {
lowerBound = current;
}
return lowerBoundRecursive(current.getRight());
}

if (current.hasRight() && current.getRight().getKey() <= k) {
return this.lowerBound(k, current.getRight());
}
return lowerBoundRecursive(current.getLeft());
};

return current;
return lowerBoundRecursive(this._root);
}

/**
* Returns the node with the smallest key bigger than k
* delegate to lowerBound
* @public
* @param {number|string} k
* @param {boolean} includeEqual
* @return {BinarySearchTreeNode|null}
*/
upperBound(k, current = this._root) {
if (current === null) {
return null;
}
floor(k, includeEqual = true) {
return this.lowerBound(k, includeEqual);
}

if (current.getKey() <= k) {
return this.upperBound(k, current.getRight());
}
/**
* Returns the node with the smallest key bigger or equal k
* @public
* @param {number|string} k
* @param {boolean} includeEqual
* @return {BinarySearchTreeNode|null}
*/
upperBound(k, includeEqual = true) {
let upperBound = null;

if (current.hasLeft() && current.getLeft().getKey() > k) {
return this.upperBound(k, current.getLeft());
}
const upperBoundRecursive = (current) => {
if (current === null) {
return upperBound;
}

return current;
const currentKey = current.getKey();
if (currentKey > k || (includeEqual && currentKey === k)) {
if (upperBound === null || upperBound.getKey() >= currentKey) {
upperBound = current;
}
return upperBoundRecursive(current.getLeft());
}

return upperBoundRecursive(current.getRight());
};

return upperBoundRecursive(this._root);
}

/**
* delegate to upperBound
* @public
* @param {number|string} k
* @param {boolean} includeEqual
* @return {BinarySearchTreeNode|null}
*/
ceil(k, includeEqual = true) {
return this.upperBound(k, includeEqual);
}

/**
Expand Down
24 changes: 23 additions & 1 deletion test/binarySearchTree.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,44 @@ describe('BinarySearchTree tests', () => {

describe('.lowerBound(k)', () => {
it('gets the node with biggest key less or equal k', () => {
expect(bst.lowerBound(60).getKey()).to.equal(50);
expect(bst.lowerBound(60).getKey()).to.equal(60);
expect(bst.lowerBound(60, false).getKey()).to.equal(50);
});

it('returns null when k is less than all tree keys', () => {
expect(bst.lowerBound(10)).to.equal(null);
});

it('returns the biggest lower bound of multiple lower bounds', () => {
const lowerBst = new BinarySearchTree();
lowerBst.insert(20);
lowerBst.insert(7);
lowerBst.insert(15);
lowerBst.insert(9);
expect(lowerBst.floor(10).getKey()).to.equal(9);
});
});

describe('.upperBound(k)', () => {
it('gets the node with smallest key bigger than k', () => {
expect(bst.upperBound(75).getKey()).to.equal(80);
expect(bst.upperBound(80).getKey()).to.equal(80);
expect(bst.upperBound(80, false).getKey()).to.equal(90);
});

it('returns null when k is bigger than all tree keys', () => {
expect(bst.upperBound(110)).to.equal(null);
});

it('returns the smallest upper bound of multiple upper bounds', () => {
const upperBst = new BinarySearchTree();
upperBst.insert(-133195046);
upperBst.insert(-49109668);
upperBst.insert(115062875);
upperBst.insert(-38206732);
upperBst.insert(49311742);
expect(upperBst.ceil(49303013).getKey()).to.equal(49311742);
});
});

describe('.traverseInOrder(cb)', () => {
Expand Down

0 comments on commit 74e9a83

Please sign in to comment.