与单项链表,双向链表在反向遍历的时候更方便
所以
它不仅有 next域指向下一个节点
还有 pre 域指向前一个节点
class Node {int no;String name;String nickName;// 指向前一个节点Node pre;// 指向下一个节点Node next;public Node(int no, String name, String nickName) {this.no = no;this.name = name;this.nickName = nickName;}@Overridepublic String toString() {return "[HeroNode no=" + no + ", name=" + name + ", nickName=" + nickName + "]";}}
双向链表的基本操作
双向链表的基本操作里只有少许操作发生了变化,其余可参考单链表
list和 update
这两个操作基本没有发生变化
// 遍历双向链表public void list() {if (head.next == null) {System.out.println("当前链表为空");return;}// 这里我们不需要输出头节点,所以我们可以直接让辅助指针指向第一个节点Node temp = head.next;while (true) {// 这里因为我们要输出最后一个元素,所以不能 判断 temp.next == nullif (temp == null) {break;}System.out.println(temp);temp = temp.next;}}// 根据节点的 no进行修改public void update(Node node) {if (head.next == null) {System.out.println("链表为空");return;}Node temp = head.next;// 用来判断是否找到 要修改节点boolean flag = false;// 找到需要修改的节点while (true) {if (temp == null) {// 已经遍历完成break;}if (temp.no == node.no) {// 找到该节点flag = true;break;}temp = temp.next;}if (flag) {temp.name = node.name;temp.nickName = node.nickName;} else {System.out.println("没有找到编号为" + node.no + "节点");}}
add
add 的时候记得要 将 新加入的节点 node 指向前一个节点 temp
也就是
temp.next = node
node.pre = temp
// 向双向链表中添加节点// 向链表中添加新元素public void add(Node node) {// 用一个临时的辅助指针来代替 头指针进行遍历Node temp = head;// 循环遍历到最后一个节点while (true) {// 如果temp.next == null,说明当前节点为最后一个节点if (temp.next == null) {break;}// temp 指针后移,指向下一个节点temp = temp.next;}// 将最后一个节点 next指向新的元素temp.next = node;// 将新节点的 pre 指向前一个节点node.pre = temp;}
delete 变化
delete 变化最大,我们不需要向单链表一样找到被删节点的前一个节点了,
因为在双向链表中,被删节点本身就有前一个节点和后一个节点的信息
所以代码上我们的变化会变得比较大
具体思路为,使用辅助接点temp 找到被删节点node
temp.no == node.no
然后让被删节点的 前一个节点的next 指向 后一个节点
temp.pre.next = temp.next;
并且让后一个节点的pre域指向被删节点的前一个节点,
这里需要判断被删节点是不是最后一个节点
如果不判断的话,当temp是最后一个节点时,会报空指针异常
if (temp.next != null) {
temp.next.pre = temp.pre;
}
// 删除一个节点public void delete(Node node) {if (head.next == null) {System.out.println("链表为空");return;}Node temp = head.next;boolean flag = false;while (true) {// 关于这里是 temp == null// 还是 temp.next == null// 关键看你需不需要对最后一个节点参与循环// temp 是参与循环, temp.next 不参与if (temp == null) {break;}if (temp.no == node.no) {// 找到该节点,不必像单链表那样找到前一个节点flag = true;break;}temp = temp.next;}if (flag) {temp.pre.next = temp.next;// 如果不判断的话,当temp是最后一个节点时,会报空指针异常if (temp.next != null) {temp.next.pre = temp.pre;}} else {System.out.println("没有找到编号为" + node.no + "节点");}}
addByOrder 升序
这个思路也发生变化,之前也是寻找前一个节点,但是现在我们同样可以找到被插入位置的节点
本来是想在 while 循环中就进行 插入
但是有一个问题就是,如果被插入的节点是最后一个节点,那么它不会被循环到,
如果将while的终止条件变成 temp == null 的话,退出循环后又会空指针异常,
所以我这里在最后又判断了一次node.no > temp.no 来保证 最后一个节点也能被插入,
这个代码可能不是最好的,但是代码是前几天实现的,现在有点懒的优化了。
public void addByOrder(Node node) {// 用一个临时的辅助指针来代替 头指针进行遍历Node temp = head;boolean flag = false;// 循环遍历到最后一个节点while (true) {// 如果temp.next == null,说明当前节点为最后一个节点if (temp.next == null) {break;}if (node.no < temp.no) {flag = true;break;}// temp 指针后移,指向下一个节点temp = temp.next;}//正常添加if (flag == false && node.no > temp.no) {// 将最后一个节点 next指向新的元素temp.next = node;// 将新节点的 pre 指向前一个节点node.pre = temp;} else {temp.pre.next = node;node.pre = temp.pre;node.next = temp;temp.pre = node;}}
