队列经常用,先进先出。一头进,另一头出。
双向队列,就是一头进,另一头出;另一头进,一头出。
这里要介绍的是连续双向队列。
最初是为了解决流体(液体或气体)在导管中流动的问题。
导管中的流体可以正着流,也可以反向流,所以就需要双向队列,一段流体的长度是连续的,不确定的,所以需要连续双向队列。但是管子的总长度是固定的。
代码如下(typescript):
class Cdeque<T> {
private item0: CdequeItem<T>; // 队首元素
private item1: CdequeItem<T>; // 队尾元素
private length: number; // 队列长度
private lastRemoveArr: CdequeItem<T>[] = [];
private lastAddedArr: CdequeItem<T>[] = [];
constructor(length: number, data: T) {
this.length = length;
this.item0 = new CdequeItem(this.length, data);
this.item1 = this.item0;
}
public getLength(): number {
return this.length;
}
public destroy(): void {
this.forEach((item: CdequeItem<T>) => {
item.destroy();
});
this.item0 = null;
this.item1 = null;
this.lastRemoveArr = null;
}
public resize(length: number, data: T): void {
if (length > this.length) {
const d: number = length - this.length;
this.length = length;
this.unshift(d, data);
} else if (length < this.length) {
this.length = length;
this.tryRemoveFromFront();
}
}
/**
* 获取最近一次移除的。
*/
public getLastRemoveArr(): CdequeItem<T>[] {
return this.lastRemoveArr;
}
/**
* 获取最后一次添加的
*/
public getLastAddedArr(): CdequeItem<T>[] {
return this.lastAddedArr;
}
/**
* 是否能合并。
* @param data0
* @param data1
* @return boolean
*/
public canMerge(data0: T, data1: T): boolean {
return data0 === data1;
}
/**
* 正向遍历
* @param callBack
*/
public forEach(callBack: (item: CdequeItem<T>) => void): void {
let item: CdequeItem<T> = this.item0;
let next: CdequeItem<T>;
while (item !== this.item1) {
next = item.next;
callBack(item);
item = next;
}
callBack(this.item1);
}
/**
* 反向遍历
* @param callBack
*/
public reverseForEach(callBack: (item: CdequeItem<T>) => void): void {
let item: CdequeItem<T> = this.item1;
let prev: CdequeItem<T>;
while (item !== this.item0) {
prev = item.prev;
callBack(item);
item = prev;
}
callBack(this.item0);
}
/**
* 在队列头部添加
* @param length
* @param data
*/
public unshift(length: number, data: T): CdequeItem<T>[] {
this.lastAddedArr = [];
this.lastAddedArr.push(new CdequeItem(length, data));
if (this.canMerge(data, this.item0.data)) {
this.item0.length += length;
} else {
const item: CdequeItem<T> = new CdequeItem(length, data);
item.next = this.item0;
this.item0.prev = item;
this.item0 = item;
}
this.tryRemoveFromEnd();
return this.lastRemoveArr;
}
/**
* 在队列尾部添加
* @param length
* @param data
*/
public push(length: number, data: T): CdequeItem<T>[] {
this.lastAddedArr = [];
this.lastAddedArr.push(new CdequeItem(length, data));
if (this.canMerge(data, this.item1.data)) {
this.item1.length += length;
} else {
const item: CdequeItem<T> = new CdequeItem(length, data);
item.prev = this.item1;
this.item1.next = item;
this.item1 = item;
}
this.tryRemoveFromFront();
return this.lastRemoveArr;
}
private tryRemoveFromEnd(): void {
this.lastRemoveArr = [];
this.updatePrevLength();
this.cutOff();
}
private updatePrevLength(): void {
let item: CdequeItem<T> = this.item0;
item.prevLength = 0;
while (item !== this.item1) {
item.next.prevLength = item.prevLength + item.length;
item = item.next;
}
}
private cutOff(): void {
while (this.item1.prevLength >= this.length) {
this.remove();
}
if (this.item1.length + this.item1.prevLength > this.length) {
this.lastRemoveArr.push(new CdequeItem<T>(this.item1.length + this.item1.prevLength - this.length, this.item1.data));
this.item1.length = this.length - this.item1.prevLength;
}
}
private remove(): void {
this.lastRemoveArr.push(new CdequeItem<T>(this.item1.length, this.item1.data));
this.item1 = this.item1.prev;
this.item1.next.destroy();
this.item1.next = this.item1;
}
private tryRemoveFromFront(): void {
this.lastRemoveArr = [];
this.updateNextLength();
this.reverseCutOff();
}
private updateNextLength(): void {
let item: CdequeItem<T> = this.item1;
item.nextLength = 0;
while (item !== this.item0) {
item.prev.nextLength = item.nextLength + item.length;
item = item.prev;
}
}
private reverseCutOff(): void {
while (this.item0.nextLength >= this.length) {
this.reverseRemove();
}
if (this.item0.length + this.item0.nextLength > this.length) {
this.lastRemoveArr.push(new CdequeItem<T>(this.item0.length + this.item0.nextLength - this.length, this.item0.data));
this.item0.length = this.length - this.item0.nextLength;
}
}
private reverseRemove(): void {
this.lastRemoveArr.push(new CdequeItem<T>(this.item0.length, this.item0.data));
this.item0 = this.item0.next;
this.item0.prev.destroy();
this.item0.prev = this.item0;
}
}一段流体柱的定义,如下:
class CdequeItem<T> {
public length: number;
public data: T;
public next: CdequeItem<T>;
public prev: CdequeItem<T>;
public prevLength: number;
public nextLength: number;
constructor(length: number, data: T) {
this.length = length;
this.data = data;
this.next = this;
this.prev = this;
this.prevLength = 0;
this.nextLength = 0;
}
public destroy(): void {
this.next = null;
this.prev = null;
this.data = null;
}
public clone(): CdequeItem<T> {
return new CdequeItem<T>(this.length, this.data);
}
}
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。