Add Stack.

This commit is contained in:
Oleksii Trekhleb 2018-03-28 17:01:46 +03:00
parent 159d489e52
commit 8da6754523
9 changed files with 189 additions and 48 deletions

View File

@ -4,9 +4,9 @@
## Data Structures
- [Linked List](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/linked-list)
- [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table)
- [Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue)
1. [Linked List](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/linked-list)
2. [Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue)
3. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table)
## Running Tests

View File

@ -160,6 +160,23 @@ export default class LinkedList {
return deletedTail;
}
deleteHead() {
if (!this.head) {
return null;
}
const deletedHead = this.head;
if (this.head.next) {
this.head = this.head.next;
} else {
this.head = null;
this.tail = null;
}
return deletedHead;
}
findByKey(key) {
let currentNode = this.head;

View File

@ -43,6 +43,8 @@ describe('LinkedList', () => {
it('should delete node by value from linked list', () => {
const linkedList = new LinkedList();
expect(linkedList.deleteByValue(5)).toBeNull();
linkedList.append({ value: 1 });
linkedList.append({ value: 2 });
linkedList.append({ value: 3 });
@ -80,55 +82,103 @@ describe('LinkedList', () => {
expect(linkedList.tail.toString()).toBe('2');
});
it('should delete node by key from linked list', () => {
const linkedList = new LinkedList();
expect(linkedList.deleteByKey('key')).toBeNull();
linkedList.append({ value: 1, key: 'test1' });
linkedList.append({ value: 2, key: 'test2' });
linkedList.append({ value: 3, key: 'test3' });
linkedList.append({ value: 4, key: 'test4' });
const deletedNode1 = linkedList.deleteByKey('test2');
expect(deletedNode1.key).toBe('test2');
expect(linkedList.toString()).toBe('test1:1,test3:3,test4:4');
const deletedNode2 = linkedList.deleteByKey('test1');
expect(deletedNode2.key).toBe('test1');
expect(linkedList.toString()).toBe('test3:3,test4:4');
const deletedNode3 = linkedList.deleteByKey('test4');
expect(deletedNode3.key).toBe('test4');
expect(linkedList.toString()).toBe('test3:3');
});
it('should delete linked list tail', () => {
const linkedList = new LinkedList();
linkedList.append({ value: 1 });
linkedList.append({ value: 2 });
linkedList.append({ value: 3 });
expect(linkedList.head.toString()).toBe('1');
expect(linkedList.tail.toString()).toBe('3');
const deletedNode1 = linkedList.deleteTail();
expect(deletedNode1.value).toBe(3);
expect(linkedList.toString()).toBe('1,2');
expect(linkedList.head.toString()).toBe('1');
expect(linkedList.tail.toString()).toBe('2');
const deletedNode2 = linkedList.deleteTail();
expect(deletedNode2.value).toBe(2);
expect(linkedList.toString()).toBe('1');
expect(linkedList.head.toString()).toBe('1');
expect(linkedList.tail.toString()).toBe('1');
const deletedNode3 = linkedList.deleteTail();
expect(deletedNode3.value).toBe(1);
expect(linkedList.toString()).toBe('');
expect(linkedList.head).toBeNull();
expect(linkedList.tail).toBeNull();
});
it('should delete linked list head', () => {
const linkedList = new LinkedList();
expect(linkedList.deleteHead()).toBeNull();
linkedList.append({ value: 1 });
linkedList.append({ value: 2 });
expect(linkedList.head.toString()).toBe('1');
expect(linkedList.tail.toString()).toBe('2');
const deletedNode1 = linkedList.deleteTail();
const deletedNode1 = linkedList.deleteHead();
expect(deletedNode1.value).toBe(2);
expect(linkedList.toString()).toBe('1');
expect(linkedList.head.toString()).toBe('1');
expect(linkedList.tail.toString()).toBe('1');
expect(deletedNode1.value).toBe(1);
expect(linkedList.toString()).toBe('2');
expect(linkedList.head.toString()).toBe('2');
expect(linkedList.tail.toString()).toBe('2');
const deletedNode2 = linkedList.deleteTail();
const deletedNode2 = linkedList.deleteHead();
expect(deletedNode2.value).toBe(1);
expect(deletedNode2.value).toBe(2);
expect(linkedList.toString()).toBe('');
expect(linkedList.head).toBeNull();
expect(linkedList.tail).toBeNull();
});
it('should delete node by key from linked list', () => {
const linkedList = new LinkedList();
linkedList.append({ value: 1, key: 'test1' });
linkedList.append({ value: 2, key: 'test2' });
linkedList.append({ value: 3, key: 'test3' });
const deletedNode = linkedList.deleteByKey('test2');
expect(deletedNode.key).toBe('test2');
expect(linkedList.toString()).toBe('test1:1,test3:3');
});
it('should append unique nodes', () => {
const linkedList = new LinkedList();
linkedList.appendUnique({ value: 1, key: 'test1' });
linkedList.appendUnique({ value: 2, key: 'test2' });
linkedList.appendUnique({ value: 3, key: 'test2' });
linkedList.appendUnique({ value: 5, key: 'test1' });
expect(linkedList.toString()).toBe('test1:1,test2:3');
expect(linkedList.toString()).toBe('test1:5,test2:3');
});
it('should find node by its key', () => {
const linkedList = new LinkedList();
expect(linkedList.findByKey('test')).toBeNull();
linkedList.appendUnique({ value: 1, key: 'test1' });
linkedList.appendUnique({ value: 2, key: 'test2' });
linkedList.appendUnique({ value: 3, key: 'test3' });

View File

@ -10,19 +10,19 @@ export default class Queue {
}
peek() {
if (!this.linkedList.tail) {
if (!this.linkedList.head) {
return null;
}
return this.linkedList.tail.value;
return this.linkedList.head.value;
}
add(value) {
enqueue(value) {
this.linkedList.append({ value });
}
remove() {
const removedTail = this.linkedList.deleteTail();
return removedTail ? removedTail.value : null;
dequeue() {
const removedHead = this.linkedList.deleteHead();
return removedHead ? removedHead.value : null;
}
}

View File

@ -1,8 +1,2 @@
# Queue
|Operation |Complexity |
|---------------------------|-------------------|
|Find |O() |
|Insert/delete at beginning |O() |
|Insert/delete in middle |O() |
|Insert/delete at end |O() |

View File

@ -7,11 +7,11 @@ describe('Queue', () => {
expect(queue.linkedList).not.toBeNull();
});
it('should add data to queue', () => {
it('should enqueue data to queue', () => {
const queue = new Queue();
queue.add(1);
queue.add(2);
queue.enqueue(1);
queue.enqueue(2);
expect(queue.linkedList.toString()).toBe('1,2');
});
@ -21,11 +21,11 @@ describe('Queue', () => {
expect(queue.peek()).toBeNull();
queue.add(1);
queue.add(2);
queue.enqueue(1);
queue.enqueue(2);
expect(queue.peek()).toBe(2);
expect(queue.peek()).toBe(2);
expect(queue.peek()).toBe(1);
expect(queue.peek()).toBe(1);
});
it('should check if queue is empty', () => {
@ -33,19 +33,19 @@ describe('Queue', () => {
expect(queue.isEmpty()).toBeTruthy();
queue.add(1);
queue.enqueue(1);
expect(queue.isEmpty()).toBeFalsy();
});
it('should remove from empty', () => {
it('should dequeue from queue in FIFO order', () => {
const queue = new Queue();
queue.add(1);
queue.add(2);
queue.enqueue(1);
queue.enqueue(2);
expect(queue.remove()).toBe(2);
expect(queue.remove()).toBe(1);
expect(queue.dequeue()).toBe(1);
expect(queue.dequeue()).toBe(2);
expect(queue.isEmpty()).toBeTruthy();
});
});

View File

@ -0,0 +1 @@
# Queue

View File

@ -0,0 +1,28 @@
import LinkedList from '../linked-list/LinkedList';
export default class Stack {
constructor() {
this.linkedList = new LinkedList();
}
isEmpty() {
return !this.linkedList.tail;
}
peek() {
if (!this.linkedList.tail) {
return null;
}
return this.linkedList.tail.value;
}
push(value) {
this.linkedList.append({ value });
}
pop() {
const removedTail = this.linkedList.deleteTail();
return removedTail ? removedTail.value : null;
}
}

View File

@ -0,0 +1,51 @@
import Stack from '../Stack';
describe('Stack', () => {
it('should create empty stack', () => {
const stack = new Stack();
expect(stack).not.toBeNull();
expect(stack.linkedList).not.toBeNull();
});
it('should stack data to stack', () => {
const stack = new Stack();
stack.push(1);
stack.push(2);
expect(stack.linkedList.toString()).toBe('1,2');
});
it('should peek data from stack', () => {
const stack = new Stack();
expect(stack.peek()).toBeNull();
stack.push(1);
stack.push(2);
expect(stack.peek()).toBe(2);
expect(stack.peek()).toBe(2);
});
it('should check if stack is empty', () => {
const stack = new Stack();
expect(stack.isEmpty()).toBeTruthy();
stack.push(1);
expect(stack.isEmpty()).toBeFalsy();
});
it('should pop data from stack', () => {
const stack = new Stack();
stack.push(1);
stack.push(2);
expect(stack.pop()).toBe(2);
expect(stack.pop()).toBe(1);
expect(stack.isEmpty()).toBeTruthy();
});
});