You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
7.6 KiB
315 lines
7.6 KiB
/*
|
|
@author: leeenx
|
|
@双向链表结构
|
|
*/
|
|
|
|
export default class Chain {
|
|
constructor(arr = []) {
|
|
// 用于存储链表的数组
|
|
this.chain = [];
|
|
this.chain.length = arr.length;
|
|
// 把 arr 转化为 chain
|
|
for(let i = 0, len = arr.length; i < len; ++i) {
|
|
this.chain[i] = {
|
|
index: i,
|
|
prev: i - 1,
|
|
next: i !== len -1 ? i + 1 : -1,
|
|
data: arr[i]
|
|
}
|
|
}
|
|
|
|
// 头指针
|
|
this.HEAD = arr.length ? 0 : -1;
|
|
// 尾指针
|
|
this.TAIL = arr.length ? arr.length - 1 : -1;
|
|
// 定位指针
|
|
this.POINTER = -1;
|
|
// 自由指针
|
|
this.FREE = arr.length;
|
|
// 自由列表 - 回收FREE
|
|
this.FREELIST = [];
|
|
// 链表的长度
|
|
this.length = this.chain.length;
|
|
// 创建一个迭代器
|
|
this[Symbol.iterator] = () => {
|
|
// 指针指向头部
|
|
let that = this, cur = that.chain[this.HEAD];
|
|
return (function* () {
|
|
while(cur !== undefined) {
|
|
yield cur;
|
|
cur = that.chain[cur.next];
|
|
}
|
|
}());
|
|
}
|
|
}
|
|
// 返回链头并删除链头
|
|
shift() {
|
|
// 回收 FREE
|
|
this.collection();
|
|
// FREE 指向被删除的位置
|
|
this.FREE = this.HEAD;
|
|
// 头指头指向下一个位置
|
|
this.HEAD = this.chain[this.HEAD].next;
|
|
// 当前头指针的 prev 指向 -1
|
|
this.HEAD !== -1 && (this.chain[this.HEAD].prev = -1);
|
|
// 链表长度为0时,尾指针指向-1
|
|
--this.length === 0 && (this.TAIL = -1);
|
|
// 返回 FREE
|
|
return this.chain[this.FREE];
|
|
}
|
|
// 插入新的链头
|
|
unshift(item) {
|
|
// 新链表的第二个节点
|
|
let second = this.HEAD;
|
|
// 头指针指向 FREE
|
|
this.HEAD = this.FREE;
|
|
// 创建新的头节点
|
|
this.chain[this.HEAD] = {
|
|
index: this.HEAD,
|
|
prev: -1,
|
|
next: second,
|
|
data: item
|
|
}
|
|
// 旧的头节点 prev 指向当前头节点
|
|
if(second !== -1) {
|
|
this.chain[second].prev = this.HEAD;
|
|
}
|
|
else {
|
|
// 链表里只有一个节点,保证this.TAIL !== -1
|
|
this.TAIL = this.HEAD;
|
|
}
|
|
// 创建一个 FREE
|
|
this.calloc();
|
|
// 链表长度 +1
|
|
++this.length;
|
|
}
|
|
// 返回链尾并删除表尾
|
|
pop() {
|
|
// 回收 FREE
|
|
this.collection();
|
|
// FREE 指向被删除的位置
|
|
this.FREE = this.TAIL;
|
|
// 尾指针指向上一个位置
|
|
this.TAIL = this.chain[this.TAIL].prev;
|
|
// 当前尾指针的 next 指向 -1
|
|
this.TAIL !== -1 && (this.chain[this.TAIL].next = -1);
|
|
// 链表长度为0时,头指针指向-1
|
|
--this.length === 0 && (this.HEAD = -1);
|
|
// 返回 FREE
|
|
return this.chain[this.FREE];
|
|
}
|
|
// 插入新的链尾
|
|
push(item) {
|
|
// 新链表的倒数第二个节点
|
|
let penultimate = this.TAIL;
|
|
// 尾指针指向 FREE
|
|
this.TAIL = this.FREE;
|
|
// 创建新的尾节点
|
|
this.chain[this.TAIL] = {
|
|
index: this.TAIL,
|
|
prev: penultimate,
|
|
next: -1,
|
|
data: item
|
|
}
|
|
|
|
// 旧的尾节点 next 指向当前尾节点
|
|
if(penultimate !== -1) {
|
|
this.chain[penultimate].next = this.TAIL;
|
|
}
|
|
else {
|
|
// 链表里只有一个节点,保证this.HEAD !== -1
|
|
this.HEAD = this.TAIL;
|
|
}
|
|
// 创建一个 FREE
|
|
this.calloc();
|
|
// 链表长度 +1
|
|
++this.length;
|
|
}
|
|
// 返回指定索引的元素
|
|
at(index = 0) {
|
|
if(index < 0 || index >= this.length) return;
|
|
let cur;
|
|
if(index < this.length / 2) {
|
|
// 从头部开始
|
|
cur = this.chain[this.HEAD];
|
|
for(let i = 0; i !== index; ++i) {
|
|
cur = this.chain[cur.next];
|
|
this.POINTER = cur.index;
|
|
}
|
|
} else {
|
|
// 从尾部开始
|
|
cur = this.chain[this.TAIL];
|
|
for(let i = this.length - 1; i !== index; --i) {
|
|
cur = this.chain[cur.prev];
|
|
}
|
|
}
|
|
return cur;
|
|
}
|
|
// 返回指定指针的元素
|
|
pointerAt(addr) {
|
|
// 指针地址索引在 0 ~ this.lenght,为合法地址
|
|
if(addr >= 0 && addr < this.length) {
|
|
return this.chain[addr];
|
|
}
|
|
}
|
|
// 返回第一个元素
|
|
first() {
|
|
return this.chain[this.HEAD];
|
|
}
|
|
// 返回最后一个元素
|
|
last() {
|
|
return this.chain[this.TAIL];
|
|
}
|
|
// 返回当前元素,并把 POINTER 指向上一个元素
|
|
prev() {
|
|
// 当前节点
|
|
let cur = this.curr();
|
|
// POINTER 指向上一个,如果指向 -1 则重置为 this.HEAD
|
|
this.POINTER !== -1 ? (this.POINTER = this.chain[this.POINTER].prev) : (this.POINTER = this.HEAD);
|
|
return cur;
|
|
}
|
|
// 返回前当元素,并把 POINTER 指向下一个元素
|
|
next() {
|
|
// 当前节点
|
|
let cur = this.curr();
|
|
// POINTER 指向下一个,如果指向 -1 则重置为 this.TAIL
|
|
this.POINTER !== -1 ? (this.POINTER = this.chain[this.POINTER].next) : (this.POINTER = this.TAIL);
|
|
return cur;
|
|
}
|
|
// 返回当前元素
|
|
curr() {
|
|
return this.chain[this.POINTER];
|
|
}
|
|
// 定位指针
|
|
setPointer(addr = this.POINTER) {
|
|
// 指针地址索引在 0 ~ this.lenght,为合法地址
|
|
if(addr >= 0 && addr < this.length) {
|
|
this.POINTER = addr;
|
|
return true;
|
|
}
|
|
}
|
|
// 克隆
|
|
clone() {
|
|
let copy = new Chain();
|
|
for(let key of ["HEAD", "TAIL", "FREE", "length"]) {
|
|
copy[key] = this[key];
|
|
}
|
|
copy.chain.length = copy.length;
|
|
// 链表数据拷贝
|
|
for(let i = 0, len = copy.length; i<len; ++i) {
|
|
copy.chain[i] = Object.create(this.chain[i]);
|
|
}
|
|
// FREELIST
|
|
copy.FREELIST = [...this.FREELIST];
|
|
return copy;
|
|
}
|
|
// 删除指定位置的元素
|
|
remove(index) {
|
|
// 数组范围之外
|
|
if(index<0 || index>=this.length) return ;
|
|
// 数组索引内
|
|
if(index === 0) {
|
|
// 指向表头
|
|
return this.shift();
|
|
} else if(index === this.length - 1) {
|
|
// 指向表尾
|
|
return this.pop();
|
|
} else {
|
|
// 当前节点
|
|
let cur = this.at(index);
|
|
// 上一个节点
|
|
let prev = this.chain[cur.prev];
|
|
// 下一个节点
|
|
let next = this.chain[cur.next];
|
|
// 回收 FREE
|
|
this.collection();
|
|
// FREE 指向被删除的位置
|
|
this.FREE = cur.index;
|
|
// 删除当前节点
|
|
[prev.next, next.prev] = [next.index, prev.index];
|
|
// 链表长度 -1
|
|
--this.length;
|
|
// 返回 FREE
|
|
return cur;
|
|
}
|
|
}
|
|
// 在指定索引前插入元素
|
|
insertBefore(index, item) {
|
|
// 数组范围之外
|
|
if(index < 0 || index >= this.length) return ;
|
|
// 当前节点
|
|
let cur = this.at(index);
|
|
// 上一个节点
|
|
let prev = this.chain[cur.prev] || {index: -1};
|
|
// 下一个节点
|
|
let next = cur;
|
|
// 插入新节点
|
|
cur = this.chain[this.FREE] = {
|
|
index: this.FREE,
|
|
prev: prev.index,
|
|
next: next.index,
|
|
data: item
|
|
}
|
|
next.prev = cur.index;
|
|
// 上一个节点存在
|
|
if(prev.index !== -1) {
|
|
prev.next = cur.index;
|
|
}
|
|
// 插入的是头节点
|
|
else {
|
|
this.HEAD = cur.index;
|
|
}
|
|
// 创建一个 FREE
|
|
this.calloc();
|
|
// 链表长度 +1
|
|
++this.length;
|
|
}
|
|
// 在指定索引后插入元素,与 insertBefore 做对就
|
|
insertAfter(index, item) {
|
|
// 数组范围之外
|
|
if(index < 0 || index >= this.length) return ;
|
|
// 当前节点
|
|
let cur = this.at(index);
|
|
// 下一个节点
|
|
let next = this.chain[cur.next] || {index: -1};
|
|
// 上一个节点
|
|
let prev = cur;
|
|
// 插入新节点
|
|
cur = this.chain[this.FREE] = {
|
|
index: this.FREE,
|
|
prev: prev.index,
|
|
next: next.index,
|
|
data: item
|
|
}
|
|
prev.next = cur.index;
|
|
// 下一个节点存在
|
|
if(next.index !== -1) {
|
|
next.prev = cur.index;
|
|
}
|
|
// 插入的是尾节点
|
|
else {
|
|
this.TAIL = cur.index;
|
|
}
|
|
// 创建一个 FREE
|
|
this.calloc();
|
|
// 链表长度 +1
|
|
++this.length;
|
|
}
|
|
// 清空链表
|
|
clean() {
|
|
// 清空数组
|
|
this.length = this.chain.length = this.FREELIST.length = 0;
|
|
this.POINTER = this.HEAD = this.TAIL = -1;
|
|
this.FREE = 0;
|
|
}
|
|
// 动态分配 FREE
|
|
calloc() {
|
|
// FREE 指向新位置
|
|
this.FREE = this.FREELIST.length ? this.FREELIST.pop() : this.chain.length;
|
|
}
|
|
// 回收 FREE
|
|
collection() {
|
|
// 把 FREE 加入到 FREELIST
|
|
this.FREELIST.push(this.FREE);
|
|
}
|
|
}
|