import {
throwError,
ErrorEnum,
ERROR_SUBSCRIPT_OUT_OF_BOUNDS,
ANY_OBJ,
ELEMENT_NOT_FOUNT,
} from '@/shared';
export interface ISingleLinkedList<T> {
size: number;
add(element: T, index?: number): void;
get(index: number): T;
set(index: number, element: T): T;
delete(index: number): T;
find(element: T): number;
}
export class SingleLinkedListNode<T> {
constructor(public val: T, public next: SingleLinkedListNode<T> | null = null) {}
}
export class SingleLinkedList<T> implements ISingleLinkedList<T> {
private dummyHead = new SingleLinkedListNode(ANY_OBJ);
private _size: number = 0;
get size() {
return this._size;
}
add(element: T, index: number = this.size): void {
this.checkAddRange(index) || throwError(ERROR_SUBSCRIPT_OUT_OF_BOUNDS, ErrorEnum.range);
let p = this.dummyHead;
while (index--) p = p.next!;
const newNode = new SingleLinkedListNode(element, p.next);
p.next = newNode;
this._size++;
}
set(index: number, element: T): T {
this.checkRange(index) || throwError(ERROR_SUBSCRIPT_OUT_OF_BOUNDS, ErrorEnum.range);
let p = this.dummyHead;
while (index--) p = p.next!;
const val = p.next!.val;
p.next!.val = element;
return val;
}
delete(index: number): T {
this.checkRange(index) || throwError(ERROR_SUBSCRIPT_OUT_OF_BOUNDS, ErrorEnum.range);
let p = this.dummyHead;
while (index--) p = p.next!;
const val = p.next!.val;
p.next = p.next!.next;
this._size--;
return val;
}
get(index: number): T {
this.checkRange(index) || throwError(ERROR_SUBSCRIPT_OUT_OF_BOUNDS, ErrorEnum.range);
let p = this.dummyHead;
while (index--) p = p.next!;
return p.next!.val;
}
find(element: T): number {
let p = this.dummyHead;
let index = 0;
while (p.next !== null && p.next.val !== element) {
p = p.next!;
index++;
}
return p.next ? index : ELEMENT_NOT_FOUNT;
}
private checkAddRange(index: number): boolean {
return this.checkRange(index) || index === this.size;
}
private checkRange(index: number): boolean {
return index >= 0 && index < this._size;
}
}