双链表简介
在单链表中,有了next 指针,这就使得我们要查找下一结点的时间复杂度为0(1)。可若想查找上一结点的话,那最坏的时间复杂度就是o(n)了,因为每次都要从头开始遍历查找。
为了克服单向性这一缺点,便有了双向链表。双向链表( double linked list)是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。
所以,双向链表既可以从前往后查找,也可以从后往前。
示意图如下:
双链表的几种操作
一、遍历
方法和单链表一样,只是多了一个可以向前查找。
public void list() {
// 先判断链表是否为空
if (head.next == null) {
System.out.println("链表为空~");
return;
}
// 因为头节点不能动,因此我们需要一个辅助变量来遍历
HeroNode2 temp = head.next;
while (true) {
// 判断是否到链表最后
if (temp == null) {
break;
}
// 输出节点的信息
System.out.println(temp);
// 将temp后移,一定记住
temp = temp.next;
}
}
二、添加
1、在双向链表的尾部添加
public void add(HeroNode2 heroNode) {
// 因为head节点不能动,因此我们需要一个辅助遍历 temp
HeroNode2 temp = head;
// 遍历链表,找到最后
while (true) {
if (temp.next == null) {
break;
}
// 若没有找到最后,将temp后移
temp = temp.next;
}
// 当退出while 循环时,tmep就指向了链表的最后
// 形成一个双向链表
temp.next = heroNode;
heroNode.pre = temp;
}
2、按编号顺序添加节点的方法
示意图及注意点如下:
public void addByOrder(HeroNode2 heroNode) {
// 因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置。
HeroNode2 temp = head;
boolean flag = false;// flag标志添加的编号是否存在,默认为false
while (true) {
if (temp.next == null) {
// 说明temp已经在链表的最后
break;
}
// 如果temp指向的节点大于要插入的节点,说明找到了插入的位置
if (temp.next.no > heroNode.no) {
break;
} else if (temp.next.no == heroNode.no) {
// 说明希望添加的heroNode的编号已然存在
flag = true;// 说明编号存在
break;
}
temp = temp.next;// 后移,遍历当前链表
}
// 判断flag 的值
if (flag) {
// 不能添加,说明编号存在
System.out.printf("准备插入的英雄的编号 %d 已经存在了,不能加入\n", heroNode.no);
} else {
// 插入到链表中
heroNode.pre = temp;
heroNode.next = temp.next;
if (temp.next != null) {
// 避免空指针null.pre的情况
temp.next.pre = heroNode;
}
temp.next = her