diff --git a/src/index.ts b/src/index.ts index d3dfea6..e50adf7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,245 +1,250 @@ export class LinkedList { - private _head: LinkedListItem; - private _tail: LinkedListItem; - private _length: number; + private _head: LinkedListItem; + private _tail: LinkedListItem; + private _length: number; - constructor(...values: T[]) { + constructor(...values: T[]) { - this._head = this._tail = null; - this._length = 0; + this._head = this._tail = null; + this._length = 0; - if (values.length > 0) { - values.forEach((value) => { - this.append(value); - }); + if (values.length > 0) { + values.forEach((value) => { + this.append(value); + }); + } } - } - *iterator(): IterableIterator { - let currentItem = this._head; + * iterator(): IterableIterator { + let currentItem = this._head; - while(currentItem) { - yield currentItem.value - currentItem = currentItem.next + while (currentItem) { + yield currentItem.value + currentItem = currentItem.next + } } - } - - [Symbol.iterator]() { - return this.iterator(); - } - - get head(): T { - return this._head ? this._head.value : null; - } - get tail(): T { - return this._tail ? this._tail.value : null; - } + [Symbol.iterator]() { + return this.iterator(); + } - get length(): number { - return this._length; - } + get head(): T { + return this._head ? this._head.value : null; + } - // Adds the element at a specific position inside the linked list - insert(val: T, previousItem: T, checkDuplicates: boolean = false): boolean { + get tail(): T { + return this._tail ? this._tail.value : null; + } - if (checkDuplicates && this.isDuplicate(val)) { - return false; + get length(): number { + return this._length; } - let newItem: LinkedListItem = new LinkedListItem(val); - let currentItem: LinkedListItem = this._head; + // Adds the element at a specific position inside the linked list + insert(val: T, previousItem: T, checkDuplicates: boolean = false): boolean { - if (!currentItem) { - return false; - } else { - while (true) { - if (currentItem.value === previousItem) { - newItem.next = currentItem.next; - newItem.prev = currentItem; - currentItem.next = newItem; + if (checkDuplicates && this.isDuplicate(val)) { + return false; + } - if (newItem.next) { - newItem.next.prev = newItem; - } else { - this._tail = newItem; - } - this._length++; - return true; - } else { - if (currentItem.next) { - currentItem = currentItem.next; - } - else { - // can't locate previousItem + let newItem: LinkedListItem = new LinkedListItem(val); + let currentItem: LinkedListItem = this._head; + + if (!currentItem) { return false; - } + } else { + while (true) { + if (currentItem.value === previousItem) { + newItem.next = currentItem.next; + newItem.prev = currentItem; + currentItem.next = newItem; + + if (newItem.next) { + newItem.next.prev = newItem; + } else { + this._tail = newItem; + } + this._length++; + return true; + } else { + if (currentItem.next) { + currentItem = currentItem.next; + } else { + // can't locate previousItem + return false; + } + } + } } - } } - } - // Adds the element at the end of the linked list - append(val: T, checkDuplicates: boolean = false): boolean { + // Adds the element at the end of the linked list + append(val: T, checkDuplicates: boolean = false): boolean { - if (checkDuplicates && this.isDuplicate(val)) { - return false; - } + if (checkDuplicates && this.isDuplicate(val)) { + return false; + } - let newItem = new LinkedListItem(val); + let newItem = new LinkedListItem(val); - if (!this._tail) { - this._head = this._tail = newItem; - } else { - this._tail.next = newItem; - newItem.prev = this._tail; - this._tail = newItem; + if (!this._tail) { + this._head = this._tail = newItem; + } else { + this._tail.next = newItem; + newItem.prev = this._tail; + this._tail = newItem; + } + + this._length++; + return true; } - this._length++; - return true; - } + // Add the element at the beginning of the linked list + prepend(val: T, checkDuplicates: boolean = false): boolean { - // Add the element at the beginning of the linked list - prepend(val: T, checkDuplicates: boolean = false): boolean { + if (checkDuplicates && this.isDuplicate(val)) { + return false; + } - if (checkDuplicates && this.isDuplicate(val)) { - return false; - } - - let newItem = new LinkedListItem(val); + let newItem = new LinkedListItem(val); - if (!this._head) { - this._head = this._tail = newItem; - } else { - newItem.next = this._head; - this._head.prev = newItem; - this._head = newItem; - } - - this._length++; - return true; - } + if (!this._head) { + this._head = this._tail = newItem; + } else { + newItem.next = this._head; + this._head.prev = newItem; + this._head = newItem; + } - remove(val: T): T { - let currentItem = this._head; + this._length++; + return true; + } - if (!currentItem) { - return; + clear(): void { + this._head = null; + this._tail = null; + this._length = 0; } - if (currentItem.value === val) { - this._head = currentItem.next; - this._head.prev = null; - currentItem.next = currentItem.prev = null; - this._length--; - return currentItem.value; + remove(val: T): T { + let currentItem = this._head; + + if (!currentItem) { + return; + } - } else { - while (true) { if (currentItem.value === val) { - if (currentItem.next) { // special case for last element - currentItem.prev.next = currentItem.next; - currentItem.next.prev = currentItem.prev; - currentItem.next = currentItem.prev = null; - } else { - currentItem.prev.next = null; - this._tail = currentItem.prev; + this._head = currentItem.next; + this._head.prev = null; currentItem.next = currentItem.prev = null; - } - this._length--; - return currentItem.value; + this._length--; + return currentItem.value; + } else { - if (currentItem.next) { - currentItem = currentItem.next; - } else { - return; - } + while (true) { + if (currentItem.value === val) { + if (currentItem.next) { // special case for last element + currentItem.prev.next = currentItem.next; + currentItem.next.prev = currentItem.prev; + currentItem.next = currentItem.prev = null; + } else { + currentItem.prev.next = null; + this._tail = currentItem.prev; + currentItem.next = currentItem.prev = null; + } + this._length--; + return currentItem.value; + } else { + if (currentItem.next) { + currentItem = currentItem.next; + } else { + return; + } + } + } } - } } - } - removeHead(): T { - let currentItem = this._head; + removeHead(): T { + let currentItem = this._head; - // empty list - if (!currentItem) { - return; - } + // empty list + if (!currentItem) { + return; + } + + // single item list + if (!this._head.next) { + this._head = null; + this._tail = null; + + // full list + } else { + this._head.next.prev = null; + this._head = this._head.next; + currentItem.next = currentItem.prev = null; + } - // single item list - if (!this._head.next) { - this._head = null; - this._tail = null; - - // full list - } else { - this._head.next.prev = null; - this._head = this._head.next; - currentItem.next = currentItem.prev = null; + this._length--; + return currentItem.value; } - this._length--; - return currentItem.value; - } + removeTail(): T { + let currentItem = this._tail; - removeTail(): T { - let currentItem = this._tail; + // empty list + if (!currentItem) { + return; + } - // empty list - if (!currentItem) { - return; - } + // single item list + if (!this._tail.prev) { + this._head = null; + this._tail = null; - // single item list - if (!this._tail.prev) { - this._head = null; - this._tail = null; - - // full list - } else { - this._tail.prev.next = null; - this._tail = this._tail.prev; - currentItem.next = currentItem.prev = null; - } + // full list + } else { + this._tail.prev.next = null; + this._tail = this._tail.prev; + currentItem.next = currentItem.prev = null; + } - this._length--; - return currentItem.value; - } + this._length--; + return currentItem.value; + } - first(num: number): T[] { - let iter = this.iterator(); - let result = []; + first(num: number): T[] { + let iter = this.iterator(); + let result = []; - let n = Math.min(num, this.length); + let n = Math.min(num, this.length); - for (let i = 0; i < n; i++) { - let val = iter.next(); - result.push(val.value); + for (let i = 0; i < n; i++) { + let val = iter.next(); + result.push(val.value); + } + return result; } - return result; - } - toArray(): T[] { - return [...this]; - } + toArray(): T[] { + return [...this]; + } - private isDuplicate(val: T): boolean { - let set = new Set(this.toArray()); - return set.has(val); - } + private isDuplicate(val: T): boolean { + let set = new Set(this.toArray()); + return set.has(val); + } } export class LinkedListItem { - value: T; - next: LinkedListItem; - prev: LinkedListItem; - - constructor(val: T) { - this.value = val; - this.next = null; - this.prev = null; - } + value: T; + next: LinkedListItem; + prev: LinkedListItem; + + constructor(val: T) { + this.value = val; + this.next = null; + this.prev = null; + } } \ No newline at end of file diff --git a/test/LinkedListTest.ts b/test/LinkedListTest.ts index c7fa67d..235f9eb 100644 --- a/test/LinkedListTest.ts +++ b/test/LinkedListTest.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { LinkedList } from '../src/index' class Foo { - private val: number; + private readonly val: number; constructor(val: number) { this.val = val; } @@ -74,7 +74,6 @@ describe('Linked-List Tests', () => { it('should support deconstruction', () => { let values: number[] = [0, 1, 2] let list = new LinkedList(...values); - let count = 0; let [a, b, c] = list; expect(a).to.equal(values[0]); expect(b).to.equal(values[1]); @@ -228,6 +227,16 @@ describe('Linked-List Tests', () => { expect(result).to.be.false; }); + it('should clear the list', () => { + let values: number[] = [1, 2, 3] + let list = new LinkedList(...values); + expect(list.length).to.equal(3); + list.clear() + expect(list.length).to.be.equal(0); + expect(list.head).to.be.null; + expect(list.tail).to.be.null; + }) + it('should remove the first value in the list', () => { let values: number[] = [4, 5, 6] let list = new LinkedList(...values);