npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@calcaware/data-structures

v1.0.0

Published

A collection of useful data structures. Array, linked list, stack, queue, deque, hash map, hash set, tree, heap, binary search tree, graph, bloom filter, disjoint set, trie, and LRU cache.

Readme

data-structures

A collection of production-quality data structure implementations in pure JavaScript with no dependencies. Each data structure is its own class with a consistent, ergonomic API. All classes implement [Symbol.iterator] so they work with for...of, spread, and destructuring.

Installation

npm install @calcaware/data-structures

Note: requires Node.js 12+ for ESM interop (index.mjs).

Or clone and use locally:

git clone https://github.com/calcaware/data-structures.git
npm install

Usage

CommonJS

const { LinkedList, Stack, HashMap } = require('@calcaware/data-structures');

ES Modules

import { LinkedList, Stack, HashMap } from '@calcaware/data-structures';

Individual files

const LinkedList = require('@calcaware/data-structures/src/linked-list');

Data Structures

DynamicArray

A resizable array backed by a fixed buffer that doubles on overflow and halves on underuse.

const { DynamicArray } = require('@calcaware/data-structures');

const a = new DynamicArray();
a.push(1).push(2).push(3);
a.insert(1, 99);   // [1, 99, 2, 3]
a.remove(1);       // removes 99 → [1, 2, 3]
a.get(0);          // 1
a.set(0, 10);
a.pop();           // 3
a.indexOf(2);      // 1
a.contains(10);    // true
a.toArray();       // [10, 2]
a.size;            // 2
a.capacity;        // current buffer size

LinkedList

Doubly linked list with O(1) head/tail operations and O(n/2) index access.

const { LinkedList } = require('@calcaware/data-structures');

const l = new LinkedList();
l.append(1).append(2).append(3);
l.prepend(0);         // [0, 1, 2, 3]
l.insertAt(2, 99);    // [0, 1, 99, 2, 3]
l.removeAt(2);        // removes 99
l.get(1);             // 1
l.set(1, 10);
l.indexOf(2);         // 2
l.contains(3);        // true
l.toArray();          // [0, 10, 2, 3]
l.size;               // 4
for (const v of l) console.log(v);

Stack

LIFO stack backed by a native array.

const { Stack } = require('@calcaware/data-structures');

const s = new Stack();
s.push(1).push(2).push(3);
s.peek();    // 3
s.pop();     // 3
s.size;      // 2
s.isEmpty(); // false
s.toArray(); // [2, 1]  (top to bottom)
for (const v of s) console.log(v); // top to bottom

Queue

FIFO queue using a circular buffer for O(1) enqueue and dequeue.

const { Queue } = require('@calcaware/data-structures');

const q = new Queue();
q.enqueue(1).enqueue(2).enqueue(3);
q.peek();     // 1
q.dequeue();  // 1
q.size;       // 2
q.isEmpty();  // false
q.toArray();  // [2, 3]

Deque

Double-ended queue backed by a doubly linked list. O(1) push/pop on both ends.

const { Deque } = require('@calcaware/data-structures');

const d = new Deque();
d.pushBack(2).pushFront(1).pushBack(3); // [1, 2, 3]
d.peekFront();  // 1
d.peekBack();   // 3
d.popFront();   // 1
d.popBack();    // 3
d.size;         // 1

HashMap

Hash table with separate chaining and automatic resizing at 75% load.

const { HashMap } = require('@calcaware/data-structures');

const m = new HashMap();
m.set('name', 'Alice').set('age', 30);
m.get('name');    // 'Alice'
m.has('age');     // true
m.delete('age');
m.size;           // 1
m.keys();         // ['name']
m.values();       // ['Alice']
m.entries();      // [['name', 'Alice']]
for (const [k, v] of m) console.log(k, v);

HashSet

Set backed by HashMap. O(1) average add, lookup, and delete.

const { HashSet } = require('@calcaware/data-structures');

const s = new HashSet();
s.add(1).add(2).add(2); // duplicates ignored
s.has(1);     // true
s.delete(2);
s.size;       // 1
s.values();   // [1]
for (const v of s) console.log(v);

Heap

Binary heap with a user-supplied comparator. Default is min-heap.

const { Heap } = require('@calcaware/data-structures');

// Min-heap (default)
const minH = new Heap();
[5, 3, 8, 1].forEach(v => minH.push(v));
minH.peek();  // 1
minH.pop();   // 1

// Max-heap
const maxH = new Heap((a, b) => b - a);
[5, 3, 8, 1].forEach(v => maxH.push(v));
maxH.pop();   // 8

minH.size;
minH.isEmpty();

BinarySearchTree

BST with optional custom comparator. Iterates in sorted (in-order) sequence.

const { BinarySearchTree } = require('@calcaware/data-structures');

const bst = new BinarySearchTree();
[5, 3, 7, 1, 4].forEach(v => bst.insert(v));
bst.contains(4);  // true
bst.min();        // 1
bst.max();        // 7
bst.inOrder();    // [1, 3, 4, 5, 7]
bst.preOrder();   // [5, 3, 1, 4, 7]
bst.postOrder();  // [1, 4, 3, 7, 5]
bst.remove(3);
bst.size;         // 4
for (const v of bst) console.log(v); // sorted

Tree

General N-ary tree with BFS and DFS traversal.

const { Tree } = require('@calcaware/data-structures');

const t = new Tree('root');
const a = t.root.addChild('a');
const b = t.root.addChild('b');
a.addChild('c');

t.bfs((value, node) => console.log(value)); // root, a, b, c
t.dfs((value, node) => console.log(value)); // root, a, c, b

const node = t.find('c'); // TreeNode
node.isLeaf();  // true
node.isRoot();  // false

t.root.removeChild(b);
t.toArray(); // ['root', 'a', 'c']

Graph

Adjacency-list graph supporting directed and undirected modes, BFS, DFS, and cycle detection.

const { Graph } = require('@calcaware/data-structures');

// Undirected (default)
const g = new Graph();
g.addEdge('A', 'B').addEdge('B', 'C');
g.hasEdge('A', 'B');    // true
g.hasEdge('B', 'A');    // true (undirected)
g.neighbors('B');       // ['A', 'C']
g.vertices();           // ['A', 'B', 'C']
g.hasCycle();           // false

const bfsOrder = [];
g.bfs('A', v => bfsOrder.push(v));

const dfsOrder = [];
g.dfs('A', v => dfsOrder.push(v));

g.removeEdge('A', 'B');
g.removeVertex('C');

// Directed graph
const dg = new Graph(true);
dg.addEdge('A', 'B').addEdge('B', 'C').addEdge('C', 'A');
dg.hasEdge('A', 'B');  // true
dg.hasEdge('B', 'A');  // false
dg.hasCycle();         // true

BloomFilter

Probabilistic set membership. No false negatives; controllable false positive rate.

const { BloomFilter } = require('@calcaware/data-structures');

// new BloomFilter(bitArraySize, hashFunctionCount)
const bf = new BloomFilter(10000, 4);
bf.add('apple').add('banana');
bf.has('apple');   // true  (definitely in set)
bf.has('cherry');  // false (definitely NOT in set)
bf.has('xyz');     // false or true (possible false positive)

bf.estimatedFalsePositiveRate; // e.g. 0.0002

DisjointSet

Union-Find with path compression and union by rank. O(α(n)) ≈ O(1) amortized.

const { DisjointSet } = require('@calcaware/data-structures');

const ds = new DisjointSet();
[1, 2, 3, 4, 5].forEach(v => ds.makeSet(v));
ds.union(1, 2);
ds.union(3, 4);
ds.connected(1, 2);  // true
ds.connected(1, 3);  // false
ds.union(2, 3);
ds.connected(1, 4);  // true (transitive)
ds.componentCount;   // 2
ds.find(1);          // root representative of 1's component

Trie

Prefix tree for string storage and lookup.

const { Trie } = require('@calcaware/data-structures');

const t = new Trie();
['apple', 'app', 'application', 'banana'].forEach(w => t.insert(w));
t.search('app');        // true
t.search('appl');       // false
t.startsWith('app');    // true
t.words('app');         // ['app', 'apple', 'application']
t.words();              // all words
t.delete('app');
t.size;                 // 3
for (const word of t) console.log(word);

LRUCache

Least Recently Used cache with O(1) get and put, backed by a doubly linked list + hash map.

const { LRUCache } = require('@calcaware/data-structures');

const cache = new LRUCache(3); // capacity = 3
cache.put('a', 1).put('b', 2).put('c', 3);
cache.get('a');       // 1  ('a' is now most recently used)
cache.put('d', 4);    // evicts 'b' (least recently used)
cache.has('b');       // false
cache.has('a');       // true
cache.size;           // 3
cache.capacity;       // 3
cache.keys();         // MRU → LRU order
for (const [key, value] of cache) console.log(key, value);

Running tests

npm test

License

ISC © Calcaware