Skip to content

Commit

Permalink
feat: ✨ Added Deque implementation (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandy8055 authored Oct 24, 2024
1 parent 73b19aa commit b9dbaab
Show file tree
Hide file tree
Showing 3 changed files with 435 additions and 0 deletions.
141 changes: 141 additions & 0 deletions docs/deque.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Deque

A double-ended queue (deque) implementation that efficiently supports insertion and removal of elements at both ends.

## Usage

```typescript
import { Deque } from 'jsr:@msk/data-structures';

const deque = new Deque<number>();
```

## API Reference

### Properties

- `size: number` - Number of elements in the deque
- `isEmpty(): boolean` - Whether the deque is empty

### Methods

#### Adding Elements

```typescript
// Add to front - O(1)
deque.addFirst(1);

// Add to back - O(1)
deque.addLast(2);
```

#### Removing Elements

```typescript
// Remove from front - O(1)
const first = deque.removeFirst();

// Remove from back - O(1)
const last = deque.removeLast();
```

#### Accessing Elements

```typescript
// Peek at front element - O(1)
const first = deque.peekFirst();

// Peek at back element - O(1)
const last = deque.peekLast();

// Check if element exists - O(n)
const exists = deque.contains(1);
```

#### Iteration

```typescript
// Forward iteration (front to back)
for (const value of deque) {
console.log(value);
}

// Reverse iteration (back to front)
for (const value of deque.reverseIterator()) {
console.log(value);
}
```

#### Other Operations

```typescript
// Remove all elements - O(1)
deque.clear();

// Convert to array - O(n)
const array = deque.toArray();
```

## Examples

### Basic Usage with Both Ends

```typescript
const deque = new Deque<number>();

// Add elements at both ends
deque.addFirst(1); // [1]
deque.addLast(2); // [1, 2]
deque.addFirst(0); // [0, 1, 2]

console.log([...deque]); // [0, 1, 2]
```

### Queue Operations (FIFO)

```typescript
const queue = new Deque<string>();

// Enqueue
queue.addLast('first');
queue.addLast('second');

// Dequeue
const first = queue.removeFirst(); // "first"
const second = queue.removeFirst(); // "second"
```

### Stack Operations (LIFO)

```typescript
const stack = new Deque<number>();

// Push
stack.addFirst(1);
stack.addFirst(2);

// Pop
const top = stack.removeFirst(); // 2
```

## Error Handling

```typescript
try {
const empty = new Deque<number>();
empty.removeFirst(); // Throws EmptyStructureError
} catch (error) {
if (error instanceof EmptyStructureError) {
console.log('Deque is empty!');
}
}
```

## Performance Advantages

Key advantages of Deque:

1. O(1) operations at both ends
2. Can be used as both a queue and a stack
3. Bidirectional iteration support
4. Memory-efficient implementation
160 changes: 160 additions & 0 deletions src/core/deque.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { EmptyStructureError } from '../errors/index.ts';
import { DoublyLinkedList } from './doubly-linked-list.ts';

/**
* A generic double-ended queue (Deque) implementation.
*
* This class provides a deque data structure that allows insertion and removal
* of elements from both ends with O(1) time complexity. It internally uses a
* DoublyLinkedList for efficient operations at both ends.
*
* Features:
* - O(1) insertions at both ends
* - O(1) removals from both ends
* - FIFO (First-In-First-Out) when used from one end
* - LIFO (Last-In-First-Out) when used from one end
* - Bidirectional operations
* - Implements Iterable interface for use in for...of loops
* - Type-safe implementation using generics
*
* @template T The type of elements stored in the deque
*
* @example
* ```typescript
* const deque = new Deque<number>();
* deque.addFirst(1);
* deque.addLast(2);
* deque.addFirst(0);
* console.log(deque.toArray()); // [0, 1, 2]
* console.log(deque.removeFirst()); // 0
* console.log(deque.removeLast()); // 2
* ```
*/
export class Deque<T> implements Iterable<T> {
private list: DoublyLinkedList<T>;

/**
* Creates an empty deque
*/
constructor() {
this.list = new DoublyLinkedList<T>();
}

/**
* Returns the number of elements in the deque
*/
get size(): number {
return this.list.size;
}

/**
* Checks if the deque is empty
* @returns {boolean} true if the deque contains no elements
*/
isEmpty(): boolean {
return this.list.isEmpty();
}

/**
* Adds an element to the front of the deque
* @param value The value to add
*/
addFirst(value: T): void {
this.list.prepend(value);
}

/**
* Adds an element to the end of the deque
* @param value The value to add
*/
addLast(value: T): void {
this.list.append(value);
}

/**
* Removes and returns the first element
* @throws {EmptyStructureError} If the deque is empty
* @returns The first element in the deque
*/
removeFirst(): T {
if (this.isEmpty()) {
throw new EmptyStructureError();
}
return this.list.removeFirst();
}

/**
* Removes and returns the last element
* @throws {EmptyStructureError} If the deque is empty
* @returns The last element in the deque
*/
removeLast(): T {
if (this.isEmpty()) {
throw new EmptyStructureError();
}
return this.list.removeLast();
}

/**
* Returns the first element without removing it
* @throws {EmptyStructureError} If the deque is empty
* @returns The first element in the deque
*/
peekFirst(): T {
if (this.isEmpty()) {
throw new EmptyStructureError();
}
return this.list.get(0);
}

/**
* Returns the last element without removing it
* @throws {EmptyStructureError} If the deque is empty
* @returns The last element in the deque
*/
peekLast(): T {
if (this.isEmpty()) {
throw new EmptyStructureError();
}
return this.list.get(this.size - 1);
}

/**
* Checks if the deque contains the specified element
* @param value The value to check for
* @returns {boolean} true if the element exists in the deque
*/
contains(value: T): boolean {
return this.list.contains(value);
}

/**
* Removes all elements from the deque
*/
clear(): void {
this.list.clear();
}

/**
* Converts the deque to an array
* @returns An array containing all elements in the deque (front to back)
*/
toArray(): T[] {
return this.list.toArray();
}

/**
* Creates a forward iterator for the deque (front to back)
*/
[Symbol.iterator](): Iterator<T> {
return this.list[Symbol.iterator]();
}

/**
* Creates a reverse iterator for the deque (back to front)
* @returns An iterator that traverses the deque from back to front
*/
reverseIterator(): IterableIterator<T> {
return this.list.reverseIterator();
}
}
Loading

0 comments on commit b9dbaab

Please sign in to comment.