一、基本介绍
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
对比于单链表
- 单向链表查找的方向只能是一个方向,而双链表可以向前或者向后查找
- 单链表在删除节点时不能自我删除,需要依靠被删除节点的前一个节点来辅助删除,而双链表则可以自我删除。
- 单链表在插入节点时只能在当前节点后插入,双向链表可以在当前节点前或后插入节点。
- 与单链表相比,双链表虽然在使用时比较方便,但需要多定义一个指向前一个节点的指针空间,并且底层的实现和维护相对于单链表都比较繁琐,所以一般在效率相近的情况下,会优先使用单链表。
二、双向链表的基本使用
1、先定义一个双链表结构
class Node2 {
//这里为了方便就将变量修饰为public
public int id;
public int data;
public Node2 next;
public Node2 pre;
//无参构造器
public Node2() {
}
//带参构造器
public Node2(int id, int data) {
this.id = id;
this.data = data;
}
//重写toString方法
@Override
public String toString() {
return "Node2{" + "id=" + id + ", data=" + data + '}';
}
}
2、我们再定义一个类来添加基本的增删改查操作
class DoubleLinkedList1 {
//我们这里使用带头节点的双链表,是否带头节点根据具体需要而定
private Node2 head = new Node2();
//自定义顺序添加节点,默认id唯一,不可重复添加
public void add(Node2 node) {
Node2 temp = head;
boolean flag = false;//判断节点是否已经存在
while (true) {//遍历
if (temp.next == null) {
break;
}
if (node.id == temp.next.id) {//已经存在
flag = true;
break;
}
temp = temp.next;//指针后移
}
if (flag) {
System.out.printf("节点%d已经存在,不可重复添加!\n", node.id);
} else {
temp.next = node;
node.pre = temp;
}
}
public void addByOrder(Node2 node) {
Node2 temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.id > node.id) {
break;
} else if (temp.next.id == node.id) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.println("英雄已经存在,不能重复添加");
} else {
if (temp.next != null) {
temp.next.pre = node;
}
node.next = temp.next;
temp.next = node;
node.pre = temp;
}
}
//删除节点
public void delete(int id) {
if (head.next == null) {
System.out.println("链表为空!");
return;
}
Node2 temp = head.next;
boolean flag = false;//标志是否找到要删除的节点
while (true) {//遍历
if (temp == null) {//遍历到最后一个节点还未找到
break;
}
if (id == temp.id) {//找到要删除的节点
flag = true;
break;
}
temp = temp.next;//指针后移
}
if (flag) {
temp.pre.next = temp.next;
temp.next.pre = temp.pre;
} else {
System.out.printf("未找到id为%d的节点\n",id);
}
}
public void update(Node2 node) {
if (head.next == null) {
System.out.println("链表为空!");
return;
}
Node2 temp = head.next;
boolean flag = false;
while (true) {//遍历
if (temp == null) {
break;
}
if (node.id == temp.id) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.data = node.data;
} else {
System.out.printf("未找到id为%d的节点\n",node.id);
}
}
//遍历
public void list() {
if (head.next == null) {
System.out.println("链表为空!");
return;
}
//辅助节点,用来遍历
Node2 temp = head.next;
while (true) {
if (temp == null) {
break;
}
System.out.println(temp);
temp = temp.next;
}
}
}
3、写一个Demo来测试
/**
* @author dankejun
* @create 2020-04-01 11:20
*/
public class DoubleLinkedListExer {
public static void main(String[] args) {
Node2 node1 = new Node2(1,10);
Node2 node2 = new Node2(2,20);
Node2 node3 = new Node2(3,30);
Node2 node4 = new Node2(4,40);
DoubleLinkedList1 list = new DoubleLinkedList1();
// list.add(node1);
// list.add(node2);
// list.add(node3);
// list.add(node4);
// System.out.println("当前的双链表为:");
// list.list();
list.addByOrder(node1);
list.addByOrder(node4);
list.addByOrder(node3);
list.addByOrder(node2);
System.out.println("当前的双链表为:");
list.list();
Node2 node5 = new Node2(2, 50);
list.update(node5);
System.out.println("修改后的双链表为:");
list.list();
list.delete(3);
System.out.println("删除后的双链表为:");
list.list();
}
}
测试结果:
这里是为了演示临时写的一个不太严谨的代码,可能会存在一些小bug,大家如果在阅读过程中发现有问题欢迎留言告诉我。