Files
project-inter-server/src/types/CircularQueue.ts

120 lines
2.9 KiB
TypeScript

export class CircularQueue<T> {
private startIndex: number;
private endIndex: number;
private _data: T[];
private _size: number;
private _capacity: number;
constructor(
size: number,
) {
// See the Mozilla documentation on sparse arrays (*not* undefined values)
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays
this._data = new Array<T>(size);
this.startIndex = 0;
this.endIndex = 0;
this._size = 0;
this._capacity = size;
}
size = (): number => this._size;
get = (index: number): T | undefined => {
if (index < 0 || index >= this._size) {
return undefined;
}
const actualIndex = (this.startIndex + index) % this._capacity;
return this._data[actualIndex];
};
appendWithSorting = (
data: T,
sortingCallback: (a: T, b: T) => number
) => {
if (this._size === 0) {
this._data[this.startIndex] = data;
this._size = 1;
this.endIndex = this.startIndex;
return;
}
const lastItem = this.get(this._size - 1);
const isAlreadyInOrder = lastItem && sortingCallback(lastItem, data) <= 0;
if (this._size < this._capacity) {
this.endIndex = (this.endIndex + 1) % this._capacity;
this._data[this.endIndex] = data;
this._size++;
} else {
this.startIndex = (this.startIndex + 1) % this._capacity;
this.endIndex = (this.endIndex + 1) % this._capacity;
this._data[this.endIndex] = data;
}
if (!isAlreadyInOrder) {
this.sortData(sortingCallback);
}
}
popFront = () => {
if (this._size === 0) {
return;
}
this._data[this.startIndex] = undefined as any;
if (this._size === 1) {
this._size = 0;
this.startIndex = 0;
this.endIndex = 0;
} else {
this.startIndex = (this.startIndex + 1) % this._capacity;
this._size--;
}
}
binarySearch = <K>(
searchKey: K,
keyExtractor: (item: T) => K
): T | undefined => {
if (this._size === 0) {
return undefined;
}
let left = 0;
let right = this._size - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
const midItem = this.get(mid)!;
const midKey = keyExtractor(midItem);
if (midKey === searchKey) {
return midItem;
} else if (midKey < searchKey) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return undefined;
}
private sortData = (sortingCallback: (a: T, b: T) => number) => {
const items: T[] = [];
for (let i = 0; i < this._size; i++) {
const item = this.get(i);
if (item !== undefined) {
items.push(item);
}
}
items.sort(sortingCallback);
for (let i = 0; i < items.length; i++) {
const actualIndex = (this.startIndex + i) % this._capacity;
this._data[actualIndex] = items[i];
}
};
}