node-interval-tree
Advanced tools
Comparing version 1.3.3 to 2.0.1
197
index.ts
@@ -9,8 +9,12 @@ // An augmented AVL Tree where each node maintains a list of records and their search intervals. | ||
export interface Interval { | ||
readonly low: number | ||
readonly high: number | ||
export interface Interval<N extends number | bigint = number> { | ||
readonly low: N | ||
readonly high: N | ||
} | ||
function height<T extends Interval>(node?: Node<T>) { | ||
function max<N extends number | bigint>(a: N, b: N): N { | ||
return a < b ? b : a | ||
} | ||
function height<T extends Interval<N>, N extends number | bigint = number>(node?: Node<T, N>) { | ||
if (node === undefined) { | ||
@@ -23,12 +27,12 @@ return -1 | ||
export class Node<T extends Interval> { | ||
public key: number | ||
public max: number | ||
export class Node<T extends Interval<N>, N extends number | bigint = number> { | ||
public key: N | ||
public max: N | ||
public records: T[] = [] | ||
public parent?: Node<T> | ||
public parent?: Node<T, N> | ||
public height = 0 | ||
public left?: Node<T> | ||
public right?: Node<T> | ||
public left?: Node<T, N> | ||
public right?: Node<T, N> | ||
constructor(public intervalTree: IntervalTree<T>, record: T) { | ||
constructor(public intervalTree: IntervalTree<T, N>, record: T) { | ||
this.key = record.low | ||
@@ -56,3 +60,3 @@ this.max = record.high | ||
public updateHeight() { | ||
this.height = Math.max(height(this.left), height(this.right)) + 1 | ||
this.height = max(height(this.left), height(this.right)) + 1 | ||
} | ||
@@ -70,7 +74,7 @@ | ||
if (this.left !== undefined && this.right !== undefined) { | ||
this.max = Math.max(Math.max(this.left.max, this.right.max), thisHigh) | ||
this.max = max(max(this.left.max, this.right.max), thisHigh) | ||
} else if (this.left !== undefined && this.right === undefined) { | ||
this.max = Math.max(this.left.max, thisHigh) | ||
this.max = max(this.left.max, thisHigh) | ||
} else if (this.left === undefined && this.right !== undefined) { | ||
this.max = Math.max(this.right.max, thisHigh) | ||
this.max = max(this.right.max, thisHigh) | ||
} else { | ||
@@ -109,15 +113,14 @@ this.max = thisHigh | ||
private _updateMaxAfterRightRotate() { | ||
const parent = this.parent as Node<T> | ||
const left = parent.left as Node<T> | ||
const parent = this.parent! | ||
const left = parent.left! | ||
// Update max of left sibling (x in first case, y in second) | ||
const thisParentLeftHigh = left.getNodeHigh() | ||
if (left.left === undefined && left.right !== undefined) { | ||
left.max = Math.max(thisParentLeftHigh, left.right.max) | ||
left.max = max(thisParentLeftHigh, left.right.max) | ||
} else if (left.left !== undefined && left.right === undefined) { | ||
left.max = Math.max(thisParentLeftHigh, left.left.max) | ||
left.max = max(thisParentLeftHigh, left.left.max) | ||
} else if (left.left === undefined && left.right === undefined) { | ||
left.max = thisParentLeftHigh | ||
} else { | ||
left.max = Math.max(Math.max((left.left as Node<T>).max, | ||
(left.right as Node<T>).max), thisParentLeftHigh) | ||
left.max = max(max(left.left!.max, left.right!.max), thisParentLeftHigh) | ||
} | ||
@@ -128,14 +131,13 @@ | ||
if (this.left === undefined && this.right !== undefined) { | ||
this.max = Math.max(thisHigh, this.right.max) | ||
this.max = max(thisHigh, this.right.max) | ||
} else if (this.left !== undefined && this.right === undefined) { | ||
this.max = Math.max(thisHigh, this.left.max) | ||
this.max = max(thisHigh, this.left.max) | ||
} else if (this.left === undefined && this.right === undefined) { | ||
this.max = thisHigh | ||
} else { | ||
this.max = Math.max(Math.max((this.left as Node<T>).max, (this.right as Node<T>).max), thisHigh) | ||
this.max = max(max(this.left!.max, this.right!.max), thisHigh) | ||
} | ||
// Update max of parent (y in first case, x in second) | ||
parent.max = Math.max(Math.max((parent.left as Node<T>).max, (parent.right as Node<T>).max), | ||
parent.getNodeHigh()) | ||
parent.max = max(max(parent.left!.max, parent.right!.max), parent.getNodeHigh()) | ||
} | ||
@@ -167,15 +169,14 @@ | ||
private _updateMaxAfterLeftRotate() { | ||
const parent = this.parent as Node<T> | ||
const right = parent.right as Node<T> | ||
const parent = this.parent! | ||
const right = parent.right! | ||
// Update max of right sibling (x in first case, y in second) | ||
const thisParentRightHigh = right.getNodeHigh() | ||
if (right.left === undefined && right.right !== undefined) { | ||
right.max = Math.max(thisParentRightHigh, (right.right as Node<T>).max) | ||
right.max = max(thisParentRightHigh, right.right.max) | ||
} else if (right.left !== undefined && right.right === undefined) { | ||
right.max = Math.max(thisParentRightHigh, (right.left as Node<T>).max) | ||
right.max = max(thisParentRightHigh, right.left.max) | ||
} else if (right.left === undefined && right.right === undefined) { | ||
right.max = thisParentRightHigh | ||
} else { | ||
right.max = Math.max(Math.max((right.left as Node<T>).max, | ||
(right.right as Node<T>).max), thisParentRightHigh) | ||
right.max = max(max(right.left!.max, right.right!.max), thisParentRightHigh) | ||
} | ||
@@ -186,18 +187,17 @@ | ||
if (this.left === undefined && this.right !== undefined) { | ||
this.max = Math.max(thisHigh, (this.right as Node<T>).max) | ||
this.max = max(thisHigh, this.right.max) | ||
} else if (this.left !== undefined && this.right === undefined) { | ||
this.max = Math.max(thisHigh, (this.left as Node<T>).max) | ||
this.max = max(thisHigh, this.left.max) | ||
} else if (this.left === undefined && this.right === undefined) { | ||
this.max = thisHigh | ||
} else { | ||
this.max = Math.max(Math.max((this.left as Node<T>).max, (this.right as Node<T>).max), thisHigh) | ||
this.max = max(max(this.left!.max, this.right!.max), thisHigh) | ||
} | ||
// Update max of parent (y in first case, x in second) | ||
parent.max = Math.max(Math.max((parent.left as Node<T>).max, right.max), | ||
parent.getNodeHigh()) | ||
parent.max = max(max(parent.left!.max, right.max), parent.getNodeHigh()) | ||
} | ||
private _leftRotate() { | ||
const rightChild = this.right as Node<T> | ||
const rightChild = this.right! | ||
rightChild.parent = this.parent | ||
@@ -208,6 +208,6 @@ | ||
} else { | ||
if ((rightChild.parent as Node<T>).left === this) { | ||
(rightChild.parent as Node<T>).left = rightChild | ||
} else if ((rightChild.parent as Node<T>).right === this) { | ||
(rightChild.parent as Node<T>).right = rightChild | ||
if (rightChild.parent.left === this) { | ||
rightChild.parent.left = rightChild | ||
} else if (rightChild.parent.right === this) { | ||
rightChild.parent.right = rightChild | ||
} | ||
@@ -227,3 +227,3 @@ } | ||
private _rightRotate() { | ||
const leftChild = this.left as Node<T> | ||
const leftChild = this.left! | ||
leftChild.parent = this.parent | ||
@@ -255,3 +255,3 @@ | ||
if (height(this.left) >= 2 + height(this.right)) { | ||
const left = this.left as Node<T> | ||
const left = this.left! | ||
if (height(left.left) >= height(left.right)) { | ||
@@ -268,3 +268,3 @@ // Left-Left case | ||
} else if (height(this.right) >= 2 + height(this.left)) { | ||
const right = this.right as Node<T> | ||
const right = this.right! | ||
if (height(right.right) >= height(right.left)) { | ||
@@ -315,3 +315,3 @@ // Right-Right case | ||
private _getOverlappingRecords(currentNode: Node<T>, low: number, high: number) { | ||
private _getOverlappingRecords(currentNode: Node<T, N>, low: N, high: N) { | ||
if (currentNode.key <= high && low <= currentNode.getNodeHigh()) { | ||
@@ -330,3 +330,3 @@ // Nodes are overlapping, check if individual records in the node are overlapping | ||
public search(low: number, high: number) { | ||
public search(low: N, high: N) { | ||
// Don't search nodes that don't exist | ||
@@ -371,3 +371,3 @@ if (this === undefined) { | ||
// Searches for a node by a `key` value | ||
public searchExisting(low: number): Node<T> | undefined { | ||
public searchExisting(low: N): Node<T, N> | undefined { | ||
if (this === undefined) { | ||
@@ -393,3 +393,3 @@ return undefined | ||
// Returns the smallest node of the subtree | ||
private _minValue(): Node<T> { | ||
private _minValue(): Node<T, N> { | ||
if (this.left === undefined) { | ||
@@ -402,4 +402,4 @@ return this | ||
public remove(node: Node<T>): Node<T> | undefined { | ||
const parent = this.parent as Node<T> | ||
public remove(node: Node<T, N>): Node<T, N> | undefined { | ||
const parent = this.parent! | ||
@@ -459,7 +459,10 @@ if (node.key < this.key) { | ||
} | ||
// Make linter happy | ||
return undefined | ||
} | ||
} | ||
export class IntervalTree<T extends Interval> { | ||
public root?: Node<T> | ||
export class IntervalTree<T extends Interval<N>, N extends number | bigint = number> { | ||
public root?: Node<T, N> | ||
public count = 0 | ||
@@ -511,3 +514,3 @@ | ||
public search(low: number, high: number) { | ||
public search(low: N, high: N) { | ||
if (this.root === undefined) { | ||
@@ -546,7 +549,7 @@ // Tree is empty; return empty array | ||
if (node.left !== undefined && node.right !== undefined) { | ||
node.max = Math.max(Math.max(node.left.max, node.right.max), nodeHigh) | ||
node.max = max(max(node.left.max, node.right.max), nodeHigh) | ||
} else if (node.left !== undefined && node.right === undefined) { | ||
node.max = Math.max(node.left.max, nodeHigh) | ||
node.max = max(node.left.max, nodeHigh) | ||
} else if (node.left === undefined && node.right !== undefined) { | ||
node.max = Math.max(node.right.max, nodeHigh) | ||
node.max = max(node.right.max, nodeHigh) | ||
} else { | ||
@@ -572,3 +575,3 @@ node.max = nodeHigh | ||
// root's parent role | ||
const rootParent = new Node<T>(this, { low: record.low, high: record.low} as T) | ||
const rootParent = new Node<T, N>(this, { low: record.low, high: record.low } as T) | ||
rootParent.left = this.root | ||
@@ -618,18 +621,22 @@ this.root.parent = rootParent | ||
export interface DataInterval<T> extends Interval { | ||
export interface DataInterval<T, N extends number | bigint = number> extends Interval<N> { | ||
data: T | ||
} | ||
export default class DataIntervalTree<T> { | ||
private tree = new IntervalTree<DataInterval<T>>() | ||
/** | ||
* The default export just wraps the `IntervalTree`, while providing a simpler API. Check out the | ||
* README for description on how to use each. | ||
*/ | ||
export default class DataIntervalTree<T, N extends number | bigint = number> { | ||
private tree = new IntervalTree<DataInterval<T, N>, N>() | ||
public insert(low: number, high: number, data: T) { | ||
return this.tree.insert({ low, high, data}) | ||
public insert(low: N, high: N, data: T) { | ||
return this.tree.insert({ low, high, data }) | ||
} | ||
public remove(low: number, high: number, data: T) { | ||
return this.tree.remove({ low, high, data}) | ||
public remove(low: N, high: N, data: T) { | ||
return this.tree.remove({ low, high, data }) | ||
} | ||
public search(low: number, high: number) { | ||
public search(low: N, high: N) { | ||
return this.tree.search(low, high).map(v => v.data) | ||
@@ -651,9 +658,11 @@ } | ||
export class InOrder<T extends Interval> implements IterableIterator<T> { | ||
private stack: Node<T>[] = [] | ||
export class InOrder<T extends Interval<N>, N extends number | bigint = number> | ||
implements IterableIterator<T> | ||
{ | ||
private stack: Node<T, N>[] = [] | ||
private currentNode?: Node<T> | ||
private currentNode?: Node<T, N> | ||
private i: number | ||
constructor(startNode?: Node<T>) { | ||
constructor(startNode?: Node<T, N>) { | ||
if (startNode !== undefined) { | ||
@@ -664,2 +673,6 @@ this.push(startNode) | ||
[Symbol.iterator]() { | ||
return this | ||
} | ||
public next(): IteratorResult<T> { | ||
@@ -682,5 +695,7 @@ // Will only happen if stack is empty and pop is called | ||
if (this.currentNode.right !== undefined) { // Can we go right? | ||
if (this.currentNode.right !== undefined) { | ||
// Can we go right? | ||
this.push(this.currentNode.right) | ||
} else { // Otherwise go up | ||
} else { | ||
// Otherwise go up | ||
// Might pop the last and set this.currentNode = undefined | ||
@@ -692,3 +707,3 @@ this.pop() | ||
private push(node: Node<T>) { | ||
private push(node: Node<T, N>) { | ||
this.currentNode = node | ||
@@ -709,21 +724,18 @@ this.i = 0 | ||
// Only define `Symbol.iterator` in compatible environments. | ||
export interface InOrder<T extends Interval> { | ||
[Symbol.iterator](): IterableIterator<T> | ||
} | ||
export class PreOrder<T extends Interval<N>, N extends number | bigint = number> | ||
implements IterableIterator<T> | ||
{ | ||
private stack: Node<T, N>[] = [] | ||
if (typeof Symbol === 'function') { | ||
InOrder.prototype[Symbol.iterator] = function() { return this } | ||
} | ||
private currentNode?: Node<T, N> | ||
private i = 0 | ||
export class PreOrder<T extends Interval> implements IterableIterator<T> { | ||
private stack: Node<T>[] = [] | ||
private currentNode?: Node<T> | ||
private i: number = 0 | ||
constructor(startNode?: Node<T>) { | ||
constructor(startNode?: Node<T, N>) { | ||
this.currentNode = startNode | ||
} | ||
[Symbol.iterator]() { | ||
return this | ||
} | ||
public next(): IteratorResult<T> { | ||
@@ -757,3 +769,3 @@ // Will only happen if stack is empty and pop is called, | ||
private push(node: Node<T>) { | ||
private push(node: Node<T, N>) { | ||
this.stack.push(node) | ||
@@ -767,10 +779,1 @@ } | ||
} | ||
// Only define `Symbol.iterator` in compatible environments. | ||
export interface PreOrder<T extends Interval> { | ||
[Symbol.iterator](): IterableIterator<T> | ||
} | ||
if (typeof Symbol === 'function') { | ||
PreOrder.prototype[Symbol.iterator] = function() { return this } | ||
} |
@@ -1,74 +0,74 @@ | ||
export interface Interval { | ||
readonly low: number; | ||
readonly high: number; | ||
export interface Interval<N extends number | bigint = number> { | ||
readonly low: N; | ||
readonly high: N; | ||
} | ||
export declare class Node<T extends Interval> { | ||
intervalTree: IntervalTree<T>; | ||
key: number; | ||
max: number; | ||
export declare class Node<T extends Interval<N>, N extends number | bigint = number> { | ||
intervalTree: IntervalTree<T, N>; | ||
key: N; | ||
max: N; | ||
records: T[]; | ||
parent?: Node<T>; | ||
parent?: Node<T, N>; | ||
height: number; | ||
left?: Node<T>; | ||
right?: Node<T>; | ||
constructor(intervalTree: IntervalTree<T>, record: T); | ||
getNodeHigh(): number; | ||
left?: Node<T, N>; | ||
right?: Node<T, N>; | ||
constructor(intervalTree: IntervalTree<T, N>, record: T); | ||
getNodeHigh(): N; | ||
updateHeight(): void; | ||
updateMaxOfParents(): void; | ||
private _updateMaxAfterRightRotate(); | ||
private _updateMaxAfterLeftRotate(); | ||
private _leftRotate(); | ||
private _rightRotate(); | ||
private _rebalance(); | ||
private _updateMaxAfterRightRotate; | ||
private _updateMaxAfterLeftRotate; | ||
private _leftRotate; | ||
private _rightRotate; | ||
private _rebalance; | ||
insert(record: T): void; | ||
private _getOverlappingRecords(currentNode, low, high); | ||
search(low: number, high: number): T[]; | ||
searchExisting(low: number): Node<T> | undefined; | ||
private _minValue(); | ||
remove(node: Node<T>): Node<T> | undefined; | ||
private _getOverlappingRecords; | ||
search(low: N, high: N): T[]; | ||
searchExisting(low: N): Node<T, N> | undefined; | ||
private _minValue; | ||
remove(node: Node<T, N>): Node<T, N> | undefined; | ||
} | ||
export declare class IntervalTree<T extends Interval> { | ||
root?: Node<T>; | ||
export declare class IntervalTree<T extends Interval<N>, N extends number | bigint = number> { | ||
root?: Node<T, N>; | ||
count: number; | ||
insert(record: T): boolean; | ||
search(low: number, high: number): T[]; | ||
search(low: N, high: N): T[]; | ||
remove(record: T): boolean; | ||
inOrder(): InOrder<T>; | ||
preOrder(): PreOrder<T>; | ||
inOrder(): InOrder<T, N>; | ||
preOrder(): PreOrder<T, N>; | ||
} | ||
export interface DataInterval<T> extends Interval { | ||
export interface DataInterval<T, N extends number | bigint = number> extends Interval<N> { | ||
data: T; | ||
} | ||
export default class DataIntervalTree<T> { | ||
/** | ||
* The default export just wraps the `IntervalTree`, while providing a simpler API. Check out the | ||
* README for description on how to use each. | ||
*/ | ||
export default class DataIntervalTree<T, N extends number | bigint = number> { | ||
private tree; | ||
insert(low: number, high: number, data: T): boolean; | ||
remove(low: number, high: number, data: T): boolean; | ||
search(low: number, high: number): T[]; | ||
inOrder(): InOrder<DataInterval<T>>; | ||
preOrder(): PreOrder<DataInterval<T>>; | ||
readonly count: number; | ||
insert(low: N, high: N, data: T): boolean; | ||
remove(low: N, high: N, data: T): boolean; | ||
search(low: N, high: N): T[]; | ||
inOrder(): InOrder<DataInterval<T, N>, N>; | ||
preOrder(): PreOrder<DataInterval<T, N>, N>; | ||
get count(): number; | ||
} | ||
export declare class InOrder<T extends Interval> implements IterableIterator<T> { | ||
export declare class InOrder<T extends Interval<N>, N extends number | bigint = number> implements IterableIterator<T> { | ||
private stack; | ||
private currentNode?; | ||
private i; | ||
constructor(startNode?: Node<T>); | ||
constructor(startNode?: Node<T, N>); | ||
[Symbol.iterator](): this; | ||
next(): IteratorResult<T>; | ||
private push(node); | ||
private pop(); | ||
private push; | ||
private pop; | ||
} | ||
export interface InOrder<T extends Interval> { | ||
[Symbol.iterator](): IterableIterator<T>; | ||
} | ||
export declare class PreOrder<T extends Interval> implements IterableIterator<T> { | ||
export declare class PreOrder<T extends Interval<N>, N extends number | bigint = number> implements IterableIterator<T> { | ||
private stack; | ||
private currentNode?; | ||
private i; | ||
constructor(startNode?: Node<T>); | ||
constructor(startNode?: Node<T, N>); | ||
[Symbol.iterator](): this; | ||
next(): IteratorResult<T>; | ||
private push(node); | ||
private pop(); | ||
private push; | ||
private pop; | ||
} | ||
export interface PreOrder<T extends Interval> { | ||
[Symbol.iterator](): IterableIterator<T>; | ||
} |
@@ -8,3 +8,7 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.PreOrder = exports.InOrder = exports.IntervalTree = exports.Node = void 0; | ||
var isSame = require("shallowequal"); | ||
function max(a, b) { | ||
return a < b ? b : a; | ||
} | ||
function height(node) { | ||
@@ -40,3 +44,3 @@ if (node === undefined) { | ||
Node.prototype.updateHeight = function () { | ||
this.height = Math.max(height(this.left), height(this.right)) + 1; | ||
this.height = max(height(this.left), height(this.right)) + 1; | ||
}; | ||
@@ -52,9 +56,9 @@ // Updates the max value of all the parents after inserting into already existing node, as well as | ||
if (this.left !== undefined && this.right !== undefined) { | ||
this.max = Math.max(Math.max(this.left.max, this.right.max), thisHigh); | ||
this.max = max(max(this.left.max, this.right.max), thisHigh); | ||
} | ||
else if (this.left !== undefined && this.right === undefined) { | ||
this.max = Math.max(this.left.max, thisHigh); | ||
this.max = max(this.left.max, thisHigh); | ||
} | ||
else if (this.left === undefined && this.right !== undefined) { | ||
this.max = Math.max(this.right.max, thisHigh); | ||
this.max = max(this.right.max, thisHigh); | ||
} | ||
@@ -96,6 +100,6 @@ else { | ||
if (left.left === undefined && left.right !== undefined) { | ||
left.max = Math.max(thisParentLeftHigh, left.right.max); | ||
left.max = max(thisParentLeftHigh, left.right.max); | ||
} | ||
else if (left.left !== undefined && left.right === undefined) { | ||
left.max = Math.max(thisParentLeftHigh, left.left.max); | ||
left.max = max(thisParentLeftHigh, left.left.max); | ||
} | ||
@@ -106,3 +110,3 @@ else if (left.left === undefined && left.right === undefined) { | ||
else { | ||
left.max = Math.max(Math.max(left.left.max, left.right.max), thisParentLeftHigh); | ||
left.max = max(max(left.left.max, left.right.max), thisParentLeftHigh); | ||
} | ||
@@ -112,6 +116,6 @@ // Update max of itself (z) | ||
if (this.left === undefined && this.right !== undefined) { | ||
this.max = Math.max(thisHigh, this.right.max); | ||
this.max = max(thisHigh, this.right.max); | ||
} | ||
else if (this.left !== undefined && this.right === undefined) { | ||
this.max = Math.max(thisHigh, this.left.max); | ||
this.max = max(thisHigh, this.left.max); | ||
} | ||
@@ -122,6 +126,6 @@ else if (this.left === undefined && this.right === undefined) { | ||
else { | ||
this.max = Math.max(Math.max(this.left.max, this.right.max), thisHigh); | ||
this.max = max(max(this.left.max, this.right.max), thisHigh); | ||
} | ||
// Update max of parent (y in first case, x in second) | ||
parent.max = Math.max(Math.max(parent.left.max, parent.right.max), parent.getNodeHigh()); | ||
parent.max = max(max(parent.left.max, parent.right.max), parent.getNodeHigh()); | ||
}; | ||
@@ -156,6 +160,6 @@ /* | ||
if (right.left === undefined && right.right !== undefined) { | ||
right.max = Math.max(thisParentRightHigh, right.right.max); | ||
right.max = max(thisParentRightHigh, right.right.max); | ||
} | ||
else if (right.left !== undefined && right.right === undefined) { | ||
right.max = Math.max(thisParentRightHigh, right.left.max); | ||
right.max = max(thisParentRightHigh, right.left.max); | ||
} | ||
@@ -166,3 +170,3 @@ else if (right.left === undefined && right.right === undefined) { | ||
else { | ||
right.max = Math.max(Math.max(right.left.max, right.right.max), thisParentRightHigh); | ||
right.max = max(max(right.left.max, right.right.max), thisParentRightHigh); | ||
} | ||
@@ -172,6 +176,6 @@ // Update max of itself (z) | ||
if (this.left === undefined && this.right !== undefined) { | ||
this.max = Math.max(thisHigh, this.right.max); | ||
this.max = max(thisHigh, this.right.max); | ||
} | ||
else if (this.left !== undefined && this.right === undefined) { | ||
this.max = Math.max(thisHigh, this.left.max); | ||
this.max = max(thisHigh, this.left.max); | ||
} | ||
@@ -182,6 +186,6 @@ else if (this.left === undefined && this.right === undefined) { | ||
else { | ||
this.max = Math.max(Math.max(this.left.max, this.right.max), thisHigh); | ||
this.max = max(max(this.left.max, this.right.max), thisHigh); | ||
} | ||
// Update max of parent (y in first case, x in second) | ||
parent.max = Math.max(Math.max(parent.left.max, right.max), parent.getNodeHigh()); | ||
parent.max = max(max(parent.left.max, right.max), parent.getNodeHigh()); | ||
}; | ||
@@ -433,2 +437,4 @@ Node.prototype._leftRotate = function () { | ||
} | ||
// Make linter happy | ||
return undefined; | ||
}; | ||
@@ -504,4 +510,6 @@ return Node; | ||
else if (node.records.length > 1) { | ||
var removedRecord = void 0; | ||
var removedRecord | ||
// Node with this key has 2 or more records. Find the one we need and remove it | ||
= void 0; | ||
// Node with this key has 2 or more records. Find the one we need and remove it | ||
for (var i = 0; i < node.records.length; i++) { | ||
@@ -520,9 +528,9 @@ if (isSame(node.records[i], record)) { | ||
if (node.left !== undefined && node.right !== undefined) { | ||
node.max = Math.max(Math.max(node.left.max, node.right.max), nodeHigh); | ||
node.max = max(max(node.left.max, node.right.max), nodeHigh); | ||
} | ||
else if (node.left !== undefined && node.right === undefined) { | ||
node.max = Math.max(node.left.max, nodeHigh); | ||
node.max = max(node.left.max, nodeHigh); | ||
} | ||
else if (node.left === undefined && node.right !== undefined) { | ||
node.max = Math.max(node.right.max, nodeHigh); | ||
node.max = max(node.right.max, nodeHigh); | ||
} | ||
@@ -600,2 +608,6 @@ else { | ||
exports.IntervalTree = IntervalTree; | ||
/** | ||
* The default export just wraps the `IntervalTree`, while providing a simpler API. Check out the | ||
* README for description on how to use each. | ||
*/ | ||
var DataIntervalTree = /** @class */ (function () { | ||
@@ -624,3 +636,3 @@ function DataIntervalTree() { | ||
}, | ||
enumerable: true, | ||
enumerable: false, | ||
configurable: true | ||
@@ -638,2 +650,5 @@ }); | ||
} | ||
InOrder.prototype[Symbol.iterator] = function () { | ||
return this; | ||
}; | ||
InOrder.prototype.next = function () { | ||
@@ -655,5 +670,7 @@ // Will only happen if stack is empty and pop is called | ||
if (this.currentNode.right !== undefined) { | ||
// Can we go right? | ||
this.push(this.currentNode.right); | ||
} | ||
else { | ||
// Otherwise go up | ||
// Might pop the last and set this.currentNode = undefined | ||
@@ -679,5 +696,2 @@ this.pop(); | ||
exports.InOrder = InOrder; | ||
if (typeof Symbol === 'function') { | ||
InOrder.prototype[Symbol.iterator] = function () { return this; }; | ||
} | ||
var PreOrder = /** @class */ (function () { | ||
@@ -689,2 +703,5 @@ function PreOrder(startNode) { | ||
} | ||
PreOrder.prototype[Symbol.iterator] = function () { | ||
return this; | ||
}; | ||
PreOrder.prototype.next = function () { | ||
@@ -725,5 +742,2 @@ // Will only happen if stack is empty and pop is called, | ||
exports.PreOrder = PreOrder; | ||
if (typeof Symbol === 'function') { | ||
PreOrder.prototype[Symbol.iterator] = function () { return this; }; | ||
} | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "node-interval-tree", | ||
"version": "1.3.3", | ||
"version": "2.0.1", | ||
"description": "Implementation of interval tree data structure.", | ||
@@ -8,3 +8,3 @@ "main": "./lib/index.js", | ||
"engines": { | ||
"node": ">= 7.6.0" | ||
"node": ">= 14.0.0" | ||
}, | ||
@@ -15,5 +15,5 @@ "scripts": { | ||
"clean": "rimraf lib", | ||
"lint": "tslint '**/*.ts' --exclude \"**/lib/**\" --exclude \"**/node_modules/**\" --exclude \"**/typings/**\"", | ||
"lint": "eslint --ext .js,.ts ./", | ||
"prepublishOnly": "npm run lint && npm run clean && npm run test && npm run build", | ||
"test": "mocha -R spec --compilers ts:ts-node/register test/*.ts" | ||
"test": "ts-mocha -R spec test/**.ts" | ||
}, | ||
@@ -37,3 +37,3 @@ "repository": { | ||
"dependencies": { | ||
"shallowequal": "^1.0.2" | ||
"shallowequal": "^1.1.0" | ||
}, | ||
@@ -47,14 +47,18 @@ "files": [ | ||
"devDependencies": { | ||
"@types/chai": "^4.0.5", | ||
"@types/cuid": "^1.3.0", | ||
"@types/mocha": "^2.2.44", | ||
"@types/shallowequal": "^0.2.1", | ||
"chai": "^4.1.2", | ||
"cuid": "^1.3.8", | ||
"mocha": "^4.0.1", | ||
"rimraf": "^2.6.2", | ||
"ts-node": "^3.3.0", | ||
"tslint": "^5.8.0", | ||
"typescript": "^2.6.1" | ||
"@types/chai": "^4.3.1", | ||
"@types/mocha": "^9.1.1", | ||
"@types/shallowequal": "^1.1.1", | ||
"@typescript-eslint/eslint-plugin": "^5.30.7", | ||
"@typescript-eslint/parser": "^5.30.7", | ||
"chai": "^4.3.6", | ||
"cuid": "^2.1.8", | ||
"eslint": "^8.20.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"mocha": "^10.0.0", | ||
"prettier": "^2.7.1", | ||
"rimraf": "^3.0.2", | ||
"ts-mocha": "^10.0.0", | ||
"typescript": "^4.7.4" | ||
} | ||
} |
@@ -9,31 +9,31 @@ # node-interval-tree | ||
## Usage | ||
```JavaScript | ||
```ts | ||
import IntervalTree from 'node-interval-tree' | ||
const intervalTree = new IntervalTree() | ||
const intervalTree = new IntervalTree<string>() | ||
``` | ||
### Insert | ||
```JavaScript | ||
intervalTree.insert(low, high, data) | ||
```ts | ||
intervalTree.insert(low, high, 'foo') | ||
``` | ||
Insert an interval with associated data into the tree. Intervals with the same low and high value can be inserted, as long as their data is different. | ||
Data can be any JS primitive or object. | ||
`low` and `high` have to be numbers where `low <= high` (also the case for all other operations with `low` and `high`). | ||
Data can be any JS primitive or object. | ||
`low` and `high` have to be numbers where `low <= high` (also the case for all other operations with `low` and `high`). | ||
Returns true if successfully inserted, false if nothing inserted. | ||
### Search | ||
```JavaScript | ||
```ts | ||
intervalTree.search(low, high) | ||
``` | ||
Search all intervals that overlap low and high arguments, both of them inclusive. Low and high values don't need to be in the tree themselves. | ||
Search all intervals that overlap low and high arguments, both of them inclusive. Low and high values don't need to be in the tree themselves. | ||
Returns an array of all data objects of the intervals in the range [low, high]; doesn't return the intervals themselves. | ||
### Remove | ||
```JavaScript | ||
intervalTree.remove(low, high, data) | ||
```ts | ||
intervalTree.remove(low, high, 'foo') | ||
``` | ||
Remove an interval from the tree. To remove an interval, all arguments must match the one in the tree. | ||
Remove an interval from the tree. To remove an interval, all arguments must match the one in the tree. | ||
Returns true if successfully removed, false if nothing removed. | ||
@@ -44,33 +44,31 @@ | ||
`exports.IntervalTree` operate on `Interval` directly, giving you access to the `low` and `high` values in the results. | ||
You can attach extra properties to `Interval` but they should not be modified after insertion as objects in the tree are compared according to shallow equality. | ||
You can attach extra properties to `Interval` but they should not be modified after insertion as objects in the tree are compared according to shallow equality. | ||
```TypeScript | ||
interface Interval { | ||
readonly low: number | ||
readonly high: number | ||
```ts | ||
import { Interval, IntervalTree } from 'node-interval-tree' | ||
interface StringInterval extends Interval { | ||
name: string | ||
} | ||
``` | ||
```JavaScript | ||
import { IntervalTree } from 'node-interval-tree' | ||
const intervalTree = new IntervalTree() | ||
const intervalTree = new IntervalTree<StringInterval>() | ||
``` | ||
### Insert | ||
```JavaScript | ||
```ts | ||
intervalTree.insert({ low, high }) | ||
intervalTree.insert({ low, high, name: 'foo' }) | ||
``` | ||
Insert an interval into the tree. Intervals are compared according to shallow equality and only inserted if unique. | ||
Insert an interval into the tree. Intervals are compared according to shallow equality and only inserted if unique. | ||
Returns true if successfully inserted, false if nothing inserted. | ||
### Search | ||
```JavaScript | ||
```ts | ||
intervalTree.search(low, high) | ||
``` | ||
Search all intervals that overlap low and high arguments, both of them inclusive. Low and high values don't need to be in the tree themselves. | ||
Search all intervals that overlap low and high arguments, both of them inclusive. Low and high values don't need to be in the tree themselves. | ||
Returns an array of all intervals in the range [low, high]. | ||
### Remove | ||
```JavaScript | ||
```ts | ||
intervalTree.remove({ low, high }) | ||
@@ -80,9 +78,31 @@ intervalTree.remove({ low, high, name: 'foo' }) | ||
Remove an interval from the tree. Intervals are compared according to shallow equality and only removed if all properties match. | ||
Remove an interval from the tree. Intervals are compared according to shallow equality and only removed if all properties match. | ||
Returns true if successfully removed, false if nothing removed. | ||
## BigInt support | ||
The `low` and `high` values of the interval are of type `number` by default. However, the library | ||
offers support to use `bigint` type for interval keys instead. | ||
With default export: | ||
```ts | ||
import IntervalTree from 'node-interval-tree' | ||
const intervalTree = new IntervalTree<string, bigint>() | ||
``` | ||
With advanced export: | ||
```ts | ||
import { Interval, IntervalTree } from 'node-interval-tree' | ||
interface StringInterval extends Interval<bigint> { | ||
name: string | ||
} | ||
const intervalTree = new IntervalTree<StringInterval, bigint>() | ||
``` | ||
## Example | ||
```javascript | ||
```ts | ||
import IntervalTree from 'node-interval-tree' | ||
const intervalTree = new IntervalTree() | ||
const intervalTree = new IntervalTree<string>() | ||
intervalTree.insert(10, 15, 'foo') // -> true | ||
@@ -99,3 +119,3 @@ intervalTree.insert(35, 50, 'baz') // -> true | ||
More examples can be found in the demo folder | ||
More examples can be found in the demo folder. | ||
@@ -102,0 +122,0 @@ ## License |
Sorry, the diff of this file is not supported yet
1447
121
79123
15
Updatedshallowequal@^1.1.0