universal-data-structures
v1.0.1
Published
A universal JavaScript library providing extensible data structure classes (LinkedList, DoubleLinkedList, Tree, Graph) for use in any framework
Maintainers
Readme
Universal Data Structures
A comprehensive, framework-agnostic JavaScript library providing extensible data structure classes for use in any JavaScript environment including React, Vue, Angular, and Node.js.
🚀 Features
- Framework Agnostic: Works with React, Vue, Angular, and vanilla JavaScript
- Extensible Classes: All classes are designed to be extended with custom functionality
- TypeScript Support: Full TypeScript declarations included
- Multiple Module Formats: ESM, CommonJS, UMD, and IIFE builds
- Comprehensive API: Rich set of methods for each data structure
- Optimized Performance: Efficient implementations with optimal time complexity
- Well Documented: Complete API documentation with examples
🔧 Extension Examples Included
- UniqueLinkedList: Prevents duplicate entries
- BoundedLinkedList: Size-limited list with events
- LRUCache: Least Recently Used cache using DoubleLinkedList
- FileSystemTree: Hierarchical file system implementation
- SocialNetworkGraph: Friend suggestions and connection paths
- Factory Patterns: Create data structures dynamically
- Event Mixins: Add event capabilities to any structure
All examples show real-world use cases you can adapt for your specific needs!
📦 Installation
npm install universal-data-structuresyarn add universal-data-structurespnpm add universal-data-structures🏁 Quick Start
ES Modules (Recommended)
import { LinkedList, Tree, Graph } from 'universal-data-structures';
const list = new LinkedList();
list.append('item1').append('item2').append('item3');
console.log(list.toArray()); // ['item1', 'item2', 'item3']CommonJS
const { LinkedList, Tree, Graph } = require('universal-data-structures');
const tree = new Tree('root');
tree.addChild('root', 'child1');
tree.addChild('root', 'child2');UMD (Browser)
<script src="node_modules/universal-data-structures/dist/index.umd.js"></script>
<script>
const { LinkedList } = UniversalDataStructures;
const list = new LinkedList();
</script>📚 Data Structures
🔗 LinkedList
A singly linked list implementation with comprehensive methods.
Basic Usage
import { LinkedList } from 'universal-data-structures';
const list = new LinkedList();
// Adding elements
list.append('first')
.append('second')
.prepend('beginning');
// Accessing elements
console.log(list.get(0)); // 'beginning'
console.log(list.indexOf('second')); // 2
// Removing elements
list.remove('first');
list.removeAt(0);
// Utility methods
console.log(list.length()); // 1
console.log(list.toArray()); // ['second']API Reference
| Method | Description | Time Complexity |
|--------|-------------|-----------------|
| append(data) | Add element to the end | O(1) |
| prepend(data) | Add element to the beginning | O(1) |
| insertAt(index, data) | Insert element at specific index | O(n) |
| remove(data) | Remove first occurrence of data | O(n) |
| removeAt(index) | Remove element at index | O(n) |
| get(index) | Get element at index | O(n) |
| indexOf(data) | Find index of element | O(n) |
| contains(data) | Check if element exists | O(n) |
| length() | Get size of list | O(1) |
| isEmpty() | Check if list is empty | O(1) |
| clear() | Remove all elements | O(1) |
| reverse() | Reverse the list | O(n) |
| toArray() | Convert to array | O(n) |
↔️ DoubleLinkedList
A doubly linked list with bidirectional traversal capabilities.
Basic Usage
import { DoubleLinkedList } from 'universal-data-structures';
const dlist = new DoubleLinkedList();
// Adding elements
dlist.append('middle')
.prepend('first')
.append('last');
// Bidirectional access
console.log(dlist.getFirst()); // 'first'
console.log(dlist.getLast()); // 'last'
// Efficient operations at both ends
dlist.removeFirst();
dlist.removeLast();
// Backward traversal
console.log(dlist.toArrayReverse()); // ['middle']
// Iterate backwards
for (const item of dlist.reverseIterator()) {
console.log(item);
}API Reference
All LinkedList methods plus:
| Method | Description | Time Complexity |
|--------|-------------|-----------------|
| removeFirst() | Remove first element | O(1) |
| removeLast() | Remove last element | O(1) |
| getFirst() | Get first element | O(1) |
| getLast() | Get last element | O(1) |
| lastIndexOf(data) | Find last index of element | O(n) |
| toArrayReverse() | Convert to array in reverse order | O(n) |
| reverseIterator() | Iterator for backward traversal | O(1) |
🌳 Tree
A general tree implementation supporting multiple children per node.
Basic Usage
import { Tree } from 'universal-data-structures';
const tree = new Tree('root');
// Building the tree
tree.addChild('root', 'child1');
tree.addChild('root', 'child2');
tree.addChild('child1', 'grandchild1');
tree.addChild('child1', 'grandchild2');
// Traversals
console.log(tree.traverseDepthFirst()); // ['root', 'child1', 'grandchild1', 'grandchild2', 'child2']
console.log(tree.traverseBreadthFirst()); // ['root', 'child1', 'child2', 'grandchild1', 'grandchild2']
// Tree analysis
console.log(tree.getHeight()); // 2
console.log(tree.getLeaves()); // ['grandchild1', 'grandchild2', 'child2']
console.log(tree.getNodesAtLevel(1)); // ['child1', 'child2']API Reference
| Method | Description | Time Complexity |
|--------|-------------|-----------------|
| setRoot(data) | Set tree root | O(1) |
| addChild(parentData, childData) | Add child to parent | O(n) |
| remove(data) | Remove node and descendants | O(n) |
| find(data) | Find node with data | O(n) |
| traverseDepthFirst() | DFS traversal | O(n) |
| traverseBreadthFirst() | BFS traversal | O(n) |
| getHeight() | Get tree height | O(n) |
| getLeaves() | Get all leaf nodes | O(n) |
| getNodesAtLevel(level) | Get nodes at specific level | O(n) |
🌲 BinaryTree
A binary tree implementation with specialized traversal methods.
Basic Usage
import { BinaryTree, BinaryTreeNode } from 'universal-data-structures';
const binaryTree = new BinaryTree('root');
// Manual tree construction
binaryTree.root.left = new BinaryTreeNode('left');
binaryTree.root.right = new BinaryTreeNode('right');
binaryTree.root.left.left = new BinaryTreeNode('left-left');
// Traversals
console.log(binaryTree.inOrder()); // ['left-left', 'left', 'root', 'right']
console.log(binaryTree.preOrder()); // ['root', 'left', 'left-left', 'right']
console.log(binaryTree.postOrder()); // ['left-left', 'left', 'right', 'root']
console.log(binaryTree.levelOrder()); // ['root', 'left', 'right', 'left-left']📊 Graph
A versatile graph implementation supporting both directed and undirected graphs.
Basic Usage
import { Graph } from 'universal-data-structures';
// Create undirected graph
const graph = new Graph(false);
// Add vertices and edges
graph.addVertex('A')
.addVertex('B')
.addVertex('C')
.addEdge('A', 'B', 2)
.addEdge('B', 'C', 3)
.addEdge('C', 'A', 1);
// Traversals
console.log(graph.depthFirstSearch('A')); // ['A', 'B', 'C']
console.log(graph.breadthFirstSearch('A')); // ['A', 'B', 'C']
// Shortest path
const result = graph.dijkstra('A', 'C');
console.log(result.path); // ['A', 'C']
console.log(result.distance); // 1
// Graph analysis
console.log(graph.isConnected()); // true
console.log(graph.hasCycle()); // trueAPI Reference
| Method | Description | Time Complexity |
|--------|-------------|-----------------|
| addVertex(vertex) | Add vertex | O(1) |
| addEdge(from, to, weight) | Add weighted edge | O(1) |
| removeVertex(vertex) | Remove vertex and edges | O(V + E) |
| removeEdge(from, to) | Remove edge | O(1) |
| hasEdge(from, to) | Check if edge exists | O(1) |
| getNeighbors(vertex) | Get adjacent vertices | O(1) |
| depthFirstSearch(start) | DFS traversal | O(V + E) |
| breadthFirstSearch(start) | BFS traversal | O(V + E) |
| dijkstra(start, end) | Shortest path | O((V + E) log V) |
| hasCycle() | Detect cycles | O(V + E) |
| isConnected() | Check connectivity | O(V + E) |
🔧 Framework Integration
React
import React, { useState, useEffect } from 'react';
import { LinkedList } from 'universal-data-structures';
// Custom hook for LinkedList
function useLinkedList(initialItems = []) {
const [list] = useState(() => {
const ll = new LinkedList();
initialItems.forEach(item => ll.append(item));
return ll;
});
const [items, setItems] = useState(list.toArray());
const refresh = () => setItems(list.toArray());
const append = (item) => {
list.append(item);
refresh();
};
return { list, items, append, refresh };
}
function TodoList() {
const { items, append } = useLinkedList(['Initial item']);
const [newItem, setNewItem] = useState('');
const handleAdd = () => {
if (newItem.trim()) {
append(newItem);
setNewItem('');
}
};
return (
<div>
<input
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleAdd()}
/>
<button onClick={handleAdd}>Add</button>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}Vue 3 (Composition API)
<template>
<div>
<input
v-model="newItem"
@keyup.enter="addItem"
placeholder="Add item"
/>
<button @click="addItem">Add</button>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</div>
</template>
<script>
import { ref, computed } from 'vue';
import { LinkedList } from 'universal-data-structures';
// Composable for LinkedList
function useLinkedList(initialItems = []) {
const list = new LinkedList();
initialItems.forEach(item => list.append(item));
const items = ref(list.toArray());
const refresh = () => {
items.value = list.toArray();
};
const append = (item) => {
list.append(item);
refresh();
};
return { list, items, append };
}
export default {
setup() {
const { items, append } = useLinkedList(['Initial item']);
const newItem = ref('');
const addItem = () => {
if (newItem.value.trim()) {
append(newItem.value);
newItem.value = '';
}
};
return {
items,
newItem,
addItem
};
}
};
</script>Angular
import { Injectable, Component } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { LinkedList } from 'universal-data-structures';
@Injectable({
providedIn: 'root'
})
export class DataStructureService {
private list = new LinkedList();
private listSubject = new BehaviorSubject<any[]>([]);
public items$ = this.listSubject.asObservable();
addItem(item: any): void {
this.list.append(item);
this.listSubject.next(this.list.toArray());
}
removeItem(item: any): void {
this.list.remove(item);
this.listSubject.next(this.list.toArray());
}
}
@Component({
selector: 'app-todo',
template: `
<div>
<input [(ngModel)]="newItem" (keyup.enter)="addItem()" />
<button (click)="addItem()">Add</button>
<ul>
<li *ngFor="let item of items$ | async">{{ item }}</li>
</ul>
</div>
`
})
export class TodoComponent {
newItem = '';
items$ = this.dataService.items$;
constructor(private dataService: DataStructureService) {}
addItem(): void {
if (this.newItem.trim()) {
this.dataService.addItem(this.newItem);
this.newItem = '';
}
}
}🔄 Extension Patterns
All data structures in this library are designed to be easily extensible. Here are comprehensive examples showing different extension patterns for real-world use cases:
🔗 Extending LinkedList
Basic Extension - Unique List
import { LinkedList } from 'universal-data-structures';
class UniqueLinkedList extends LinkedList {
append(data) {
if (!this.contains(data)) {
return super.append(data);
}
return this;
}
appendUnique(data) {
return this.append(data);
}
getMiddle() {
if (this.isEmpty()) return null;
let slow = this.head;
let fast = this.head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
return slow.data;
}
}
const uniqueList = new UniqueLinkedList();
uniqueList.append('item1')
.append('item2')
.append('item1'); // Won't be added again
console.log(uniqueList.toArray()); // ['item1', 'item2']
console.log(uniqueList.getMiddle()); // 'item1' or 'item2' depending on implementationAdvanced Extension - Bounded List with Events
class BoundedLinkedList extends LinkedList {
constructor(maxSize = 10) {
super();
this.maxSize = maxSize;
this.listeners = new Map();
}
// Event system
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
return this;
}
emit(event, data) {
const callbacks = this.listeners.get(event) || [];
callbacks.forEach(callback => callback(data));
}
append(data) {
if (this.size >= this.maxSize) {
this.emit('overflow', { item: data, currentSize: this.size });
// Remove oldest item to make room
const removed = this.removeAt(0);
this.emit('evicted', { item: removed });
}
super.append(data);
this.emit('added', { item: data, newSize: this.size });
return this;
}
// Batch operations
appendBatch(items) {
const results = [];
for (const item of items) {
try {
this.append(item);
results.push({ item, success: true });
} catch (error) {
results.push({ item, success: false, error: error.message });
}
}
return results;
}
// Statistical methods
getStats() {
return {
size: this.size,
maxSize: this.maxSize,
utilizationPercent: (this.size / this.maxSize * 100).toFixed(2),
isEmpty: this.isEmpty(),
isFull: this.size >= this.maxSize
};
}
}
// Usage Example
const boundedList = new BoundedLinkedList(3);
boundedList
.on('overflow', (data) => console.log('List overflow!', data))
.on('evicted', (data) => console.log('Item evicted:', data))
.on('added', (data) => console.log('Item added:', data));
boundedList.appendBatch(['a', 'b', 'c', 'd']); // 'd' will cause overflow↔️ Extending DoubleLinkedList
LRU Cache Implementation
import { DoubleLinkedList, DoubleListNode } from 'universal-data-structures';
class LRUCache extends DoubleLinkedList {
constructor(capacity = 100) {
super();
this.capacity = capacity;
this.cache = new Map(); // key -> node mapping
}
get(key) {
if (this.cache.has(key)) {
const node = this.cache.get(key);
// Move to front (most recently used)
this.moveToFront(node);
return node.data.value;
}
return null;
}
put(key, value) {
if (this.cache.has(key)) {
// Update existing
const node = this.cache.get(key);
node.data.value = value;
this.moveToFront(node);
} else {
// Add new
if (this.size >= this.capacity) {
// Remove least recently used (tail)
const lru = this.tail;
this.cache.delete(lru.data.key);
this.removeLast();
}
const data = { key, value };
this.prepend(data);
this.cache.set(key, this.head);
}
}
moveToFront(node) {
if (node === this.head) return; // Already at front
// Remove from current position
if (node.prev) node.prev.next = node.next;
if (node.next) node.next.prev = node.prev;
if (node === this.tail) this.tail = node.prev;
// Add to front
node.prev = null;
node.next = this.head;
if (this.head) this.head.prev = node;
this.head = node;
if (!this.tail) this.tail = node;
}
}
// Usage
const cache = new LRUCache(3);
cache.put('a', 1);
cache.put('b', 2);
cache.put('c', 3);
cache.put('d', 4); // 'a' gets evicted
console.log(cache.get('b')); // 2, moves 'b' to front🌳 Extending Tree
File System Tree
import { Tree, TreeNode } from 'universal-data-structures';
class FileSystemTree extends Tree {
constructor() {
super('/'); // Root directory
this.nodeMap = new Map();
this.nodeMap.set('/', this.root);
}
createFile(path, content = '') {
const parts = path.split('/').filter(p => p);
let currentPath = '';
let currentNode = this.root;
// Create intermediate directories
for (let i = 0; i < parts.length - 1; i++) {
currentPath += '/' + parts[i];
if (!this.nodeMap.has(currentPath)) {
const dirNode = currentNode.addChild({
name: parts[i],
type: 'directory',
path: currentPath
});
this.nodeMap.set(currentPath, dirNode);
this.size++;
}
currentNode = this.nodeMap.get(currentPath);
}
// Create file
const fileName = parts[parts.length - 1];
const filePath = currentPath + '/' + fileName;
const fileNode = currentNode.addChild({
name: fileName,
type: 'file',
path: filePath,
content: content,
size: content.length,
created: new Date()
});
this.nodeMap.set(filePath, fileNode);
this.size++;
return fileNode;
}
readFile(path) {
const node = this.nodeMap.get(path);
if (!node || node.data.type !== 'file') {
throw new Error(`File not found: ${path}`);
}
return node.data.content;
}
listDirectory(path = '/') {
const node = this.nodeMap.get(path);
if (!node) throw new Error(`Directory not found: ${path}`);
return node.children.map(child => ({
name: child.data.name,
type: child.data.type,
size: child.data.size || 0
}));
}
findFiles(pattern) {
const results = [];
const regex = new RegExp(pattern);
for (const [path, node] of this.nodeMap) {
if (node.data.type === 'file' && regex.test(node.data.name)) {
results.push({ path, name: node.data.name });
}
}
return results;
}
}
// Usage
const fs = new FileSystemTree();
fs.createFile('/documents/readme.txt', 'Hello World');
fs.createFile('/documents/projects/app.js', 'console.log("Hello");');
console.log(fs.listDirectory('/documents'));
console.log(fs.findFiles('.*\\.js$')); // Find all JS files📊 Extending Graph - Social Network
Social Network Implementation
import { Graph } from 'universal-data-structures';
class SocialNetworkGraph extends Graph {
constructor() {
super(false); // Undirected for mutual friendships
this.users = new Map();
}
addUser(userId, userData) {
this.addVertex(userId);
this.users.set(userId, {
id: userId,
...userData,
joinedAt: new Date(),
friends: new Set()
});
return this;
}
addFriendship(user1, user2, strength = 1) {
this.addEdge(user1, user2, strength);
this.users.get(user1)?.friends.add(user2);
this.users.get(user2)?.friends.add(user1);
return this;
}
getMutualFriends(user1, user2) {
const friends1 = this.users.get(user1)?.friends || new Set();
const friends2 = this.users.get(user2)?.friends || new Set();
return Array.from(friends1).filter(friend => friends2.has(friend));
}
getFriendSuggestions(userId, limit = 5) {
const user = this.users.get(userId);
if (!user) return [];
const suggestions = new Map();
for (const friendId of user.friends) {
const friendsFriends = this.users.get(friendId)?.friends || new Set();
for (const suggestion of friendsFriends) {
if (suggestion !== userId && !user.friends.has(suggestion)) {
suggestions.set(suggestion, (suggestions.get(suggestion) || 0) + 1);
}
}
}
return Array.from(suggestions.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, limit)
.map(([userId, mutualCount]) => ({
userId,
mutualFriendsCount: mutualCount,
userData: this.users.get(userId)
}));
}
getConnectionPath(user1, user2) {
const result = this.dijkstra(user1, user2);
return {
path: result.path,
degreeOfSeparation: result.path.length - 1
};
}
}
// Usage
const socialNet = new SocialNetworkGraph();
socialNet
.addUser('alice', { name: 'Alice Smith', age: 28 })
.addUser('bob', { name: 'Bob Johnson', age: 32 })
.addUser('charlie', { name: 'Charlie Brown', age: 25 })
.addFriendship('alice', 'bob')
.addFriendship('bob', 'charlie');
console.log(socialNet.getFriendSuggestions('alice'));
console.log(socialNet.getConnectionPath('alice', 'charlie'));🔧 Advanced Patterns
Factory Pattern for Data Structures
class DataStructureFactory {
static create(type, options = {}) {
switch (type) {
case 'uniqueList':
return new UniqueLinkedList();
case 'boundedList':
return new BoundedLinkedList(options.maxSize);
case 'lruCache':
return new LRUCache(options.capacity);
case 'fileSystem':
return new FileSystemTree();
case 'socialNetwork':
return new SocialNetworkGraph();
default:
throw new Error(`Unknown type: ${type}`);
}
}
}
// Usage
const cache = DataStructureFactory.create('lruCache', { capacity: 50 });
const fileSystem = DataStructureFactory.create('fileSystem');Mixin Pattern for Shared Functionality
const EventEmitterMixin = {
initEvents() {
this._listeners = new Map();
},
on(event, callback) {
if (!this._listeners.has(event)) {
this._listeners.set(event, []);
}
this._listeners.get(event).push(callback);
return this;
},
emit(event, data) {
(this._listeners.get(event) || []).forEach(cb => cb(data));
}
};
// Apply to any data structure
class EventLinkedList extends LinkedList {
constructor() {
super();
this.initEvents();
}
append(data) {
super.append(data);
this.emit('itemAdded', { item: data, size: this.size });
return this;
}
}
Object.assign(EventLinkedList.prototype, EventEmitterMixin);These examples demonstrate the flexibility of the Universal Data Structures library. Each base class provides a solid foundation that you can extend with domain-specific functionality while maintaining performance and core behavior.
Extending Graph with Custom Algorithms
import { Graph } from 'universal-data-structures';
class AdvancedGraph extends Graph {
constructor(isDirected = false) {
super(isDirected);
}
// Kruskal's algorithm for minimum spanning tree
minimumSpanningTree() {
if (this.isDirected) {
throw new Error('MST is only for undirected graphs');
}
const edges = this.getAllEdges()
.sort((a, b) => a.weight - b.weight);
const parent = new Map();
const rank = new Map();
// Initialize Union-Find
for (const vertex of this.getVertices()) {
parent.set(vertex, vertex);
rank.set(vertex, 0);
}
const find = (vertex) => {
if (parent.get(vertex) !== vertex) {
parent.set(vertex, find(parent.get(vertex)));
}
return parent.get(vertex);
};
const union = (a, b) => {
const rootA = find(a);
const rootB = find(b);
if (rootA !== rootB) {
if (rank.get(rootA) < rank.get(rootB)) {
parent.set(rootA, rootB);
} else if (rank.get(rootA) > rank.get(rootB)) {
parent.set(rootB, rootA);
} else {
parent.set(rootB, rootA);
rank.set(rootA, rank.get(rootA) + 1);
}
return true;
}
return false;
};
const mst = [];
for (const edge of edges) {
if (union(edge.from, edge.to)) {
mst.push(edge);
if (mst.length === this.getVertexCount() - 1) {
break;
}
}
}
return mst;
}
}🎯 Use Cases
Data Processing Pipeline
import { LinkedList, Tree, Graph } from 'universal-data-structures';
class DataPipeline {
constructor() {
this.stages = new LinkedList();
this.dependencies = new Graph(true); // directed graph
}
addStage(stageName, processor) {
this.stages.append({ name: stageName, processor });
this.dependencies.addVertex(stageName);
return this;
}
addDependency(from, to) {
this.dependencies.addEdge(from, to);
return this;
}
execute(data) {
const executionOrder = this.dependencies.topologicalSort();
let result = data;
for (const stageName of executionOrder) {
const stage = this.stages.toArray()
.find(s => s.name === stageName);
if (stage) {
result = stage.processor(result);
}
}
return result;
}
}
// Usage
const pipeline = new DataPipeline();
pipeline
.addStage('validate', data => ({ ...data, validated: true }))
.addStage('transform', data => ({ ...data, transformed: true }))
.addStage('save', data => ({ ...data, saved: true }))
.addDependency('validate', 'transform')
.addDependency('transform', 'save');
const result = pipeline.execute({ input: 'data' });Navigation System
import { Graph } from 'universal-data-structures';
class NavigationSystem {
constructor() {
this.map = new Graph(false); // undirected for roads
}
addLocation(name) {
this.map.addVertex(name);
return this;
}
addRoad(from, to, distance) {
this.map.addEdge(from, to, distance);
return this;
}
findRoute(start, destination) {
const result = this.map.dijkstra(start, destination);
return {
path: result.path,
totalDistance: result.distance,
directions: this.generateDirections(result.path)
};
}
generateDirections(path) {
const directions = [];
for (let i = 0; i < path.length - 1; i++) {
const from = path[i];
const to = path[i + 1];
const distance = this.map.getEdgeWeight(from, to);
directions.push(`Go from ${from} to ${to} (${distance} km)`);
}
return directions;
}
}🧪 Testing
The library includes comprehensive tests. Run them with:
npm testExample test:
import { LinkedList } from 'universal-data-structures';
describe('LinkedList', () => {
test('should append and retrieve elements', () => {
const list = new LinkedList();
list.append('first').append('second');
expect(list.length()).toBe(2);
expect(list.get(0)).toBe('first');
expect(list.get(1)).toBe('second');
});
test('should handle extension properly', () => {
class ExtendedList extends LinkedList {
appendIfNotExists(item) {
if (!this.contains(item)) {
this.append(item);
}
return this;
}
}
const list = new ExtendedList();
list.appendIfNotExists('item')
.appendIfNotExists('item'); // shouldn't add duplicate
expect(list.length()).toBe(1);
});
});📖 API Documentation
TypeScript Support
The library includes complete TypeScript definitions:
import { LinkedList, Tree, Graph } from 'universal-data-structures';
// Generic types supported
const stringList = new LinkedList<string>();
const numberTree = new Tree<number>(42);
const userGraph = new Graph<User>(false);
// Type-safe operations
stringList.append('hello'); // ✅ OK
stringList.append(123); // ❌ Type error
interface User {
id: number;
name: string;
}
userGraph.addVertex({ id: 1, name: 'Alice' });Performance Characteristics
| Data Structure | Access | Search | Insertion | Deletion | Space | |----------------|--------|--------|-----------|----------|-------| | LinkedList | O(n) | O(n) | O(1) at head/tail | O(n) | O(n) | | DoubleLinkedList | O(n) | O(n) | O(1) at ends | O(1) at ends | O(n) | | Tree | O(h) | O(n) | O(1) with parent ref | O(1) with ref | O(n) | | Graph | O(1) | O(V+E) | O(1) | O(V+E) | O(V+E) |
Where:
- n = number of elements
- h = height of tree
- V = number of vertices
- E = number of edges
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆓 Free to Use
This library is completely free and open source under the MIT License, which means:
✅ Commercial Use: Use in commercial projects without restrictions
✅ Modification: Modify and customize the code for your needs
✅ Distribution: Distribute the original or modified versions
✅ Private Use: Use in private/internal projects
✅ No Attribution Required: While appreciated, not legally required
✅ No Warranty: Provided "as-is" without warranty
MIT License Summary
MIT License
Copyright (c) 2024 Universal Data Structures
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND...You can use this library in any project - personal, commercial, or open source - without any licensing fees or restrictions!
🔗 Links
📊 Bundle Size
| Format | Size (gzipped) | |--------|----------------| | ESM | ~8KB | | CommonJS | ~8KB | | UMD | ~10KB | | IIFE | ~10KB |
🌟 Why Choose Universal Data Structures?
- ✅ Framework Agnostic: Use anywhere JavaScript runs
- ✅ TypeScript Ready: Full type safety out of the box
- ✅ Extensible Design: Easy to extend and customize
- ✅ Performance Optimized: Efficient algorithms and data structures
- ✅ Well Tested: Comprehensive test suite
- ✅ Production Ready: Used in production applications
- ✅ Active Maintenance: Regular updates and bug fixes
- ✅ Great Documentation: Complete API docs with examples
Made with ❤️ for the JavaScript community
