js版数据结构_04链表(2)
在本篇博文我会总结到:
- 双向链表
1. 双向链表
上一篇我们总结了单链表的实现,体验到了它的灵活性。但是它有一个很大的缺点,相信大家已经体会到了,就是使用它取数据无论取哪一个都得从头节点开始找,并且如果我们目前的位置在链表中的一个节点上我们是没有办法取到它前一个节点的数据。
为了弥补这一不足,双向链表迈着潇洒的步子向我们走过来了。
什么是双向链表呢,还是以c来说(毕竟那是基础嘛)。就是给节点搞两个指针域,一个指向它前面的前驱节点,一个指向它后继。
开始正题:
构建链表类和节点类
class DoubleLNode {
constructor(e) {
this.element = e;
this.pre = null;
this.next = null;
}
}
class DoubleLinkedList {
constructor() {
this.count = 0;
this.head = null;
this.q=null;//记录尾节点
}
}
因为其他方法均与单链表差不多,故这里我们只实现一下insert方法,即指定位置插入
insert(e,index)方法
搞点图吧,其实还是看图清楚
所要考虑的几种情况:(ps:其实本质上我们js也可以说head就是指向头结点,指向不用再打引号的。因为在js中像数组对象这类的复杂数据结构本身就是引用类型,我们所设置的这个变量本身存的就是真正的地址。如果有一丢丢的python基础就非常了然了。毕竟py万物均对象没有一个不是引用型的。。)
正题:
从头部:
从尾部:
从中间:
实现:
//前面我们的insert就用到了这个getElementAt,这里也不例外
getElementAt(index) {
// 判断是否越界
if (index >= 0 && index < this.count) {
let node = this.head;
for (let i = 0; i < index && node != null; i++) {
node = node.next;
}
return node;
} else {
return undefined;
}
}
insert(e, index) {
// 判index是否过界,
if (index >= 0 && index <= this.count) {
let node = new DoubleLNode(e);
// 在头部
if (index === 0) {
if (this.head == null) {
// 真正的第一个
this.head = node;
this.q = node;
} else {
// node节点与这时候的head节点互连
node.next = this.head;
// 此时谁还能拿到刚才的头节点呢,别忘了前面我们将current这个变量也指向了这个对象了
this.head.pre = node;
// 头指头,尾指尾
this.head = node;
// 尾正指向尾呢,因为这种情况是从上面if的情况发生之后出现的
}
// 在尾部
} else if (index === this.count) {
// q指着尾巴呢
this.q.next = node;
node.pre = this.q;
// 让q再指尾巴
this.q = node;
// 在中间
} else {
// 这里和单链表一样找到它的前一个节点,一截两端。链如新节点
let preNode = this.getElementAt(index - 1); //前一个节点
let nextNode = preNode.next; //后半链,此时nextNode指定的后半链的第一个
preNode.next = node;
node.pre = preNode;
node.next = nextNode;
nextNode.pre = node;
}
this.count++;
return true;
}
return false;
}
removeAt(index) 从指定位置移出元素
removeAt(index) {
// index判越界
if (index >= 0 && index < this.count) {
// 头部
if (index === 0) {
this.head = this.head.next; //此时还不能将此时头节点的前驱指针域设置为null,因为不能保证这个节点存不存在
// 如果只有一个节点
if (this.count === 1) {
this.q = null;
} else {
this.head.pre = null;
}
// 尾部
} else if (index === this.count - 1) {
this.q.pre.next = null;
// 中间
} else {
// 拿到要删除节点的前一个和后一个节点
let currentPreNode = this.getElementAt(index).pre;
let currentNextNode = this.getElementAt(index).next;
// 连接节点
currentPreNode.next = currentNextNode;
currentNextNode.pre = currentPreNode;
}
this.count--;
return true;
} else {
return false;
}
}
}
//部分测试代码
let test = new DoubleLinkedList();
test.insert(1, 0);
test.insert(2, 1);
test.insert(3, 2);
test.insert(4, 0)
test.removeAt(0);
console.log(test);