什么是双向链表
- 结构类似于单向链表,但是每个节点多了一个pre用于指向前一个结点,这样的特性使得双向链表可以向前或者向后查找节点,而单链表的查找只能有向一个方向查找。
- 单链表笔记
- 其逻辑结构如下图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210221091411867.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTk2OTQ2,size_16,color_FFFFFF,t_70)
双向链表增删改查
添加节点
- 添加节点的操作和单链表差不多,但是除了链表最后一个节点的next指向新节点外,增加了一个新节点的pre指向前一个结点的操作。
- 代码如下
// 直接插入到链表尾部
public void add(Node2 node) {
Node2 temp = Head;
while (true) {// 查找单链表尾部,如果为null说明到达尾部,跳出循环
if (temp.getNext() == null) {
break;
}
temp = temp.getNext();// 否则令temp指向下一个节点
}
temp.setNext(node);
node.setPre(temp);
// 找到尾部后,向尾部插入节点
}
遍历链表
public void show() {// 头的数据不能展示,展示的是头之后的节点的数据
Node2 temp = Head.getNext();// 将头之后的第一个节点赋值给辅助变量
while (true) {
if (temp == null) {// 如果该节点为null说明到尾部了
break;
}
System.out.println(temp.toString());
// 不为null,说明有数据,输出该节点的数据
temp = temp.getNext();
// 令辅助变量指向下一个节点
}
}
修改结点数据
- 从头节点开始向后遍历的代码和单链表基本一样
- 代码如下
public void update(Node2 node) {
Node2 temp = Head.getNext();
boolean flag = false;
while (true) {
if (temp == null) {// 链表为null或者没找到,跳出循环
break;
}
if (temp.getNo() == node.getNo()) {// 找到了,跳出循环
flag = true;
break;
}
// 没找到继续往后遍历
temp = temp.getNext();
}
if (flag) {
temp.setData(node.getData());
} else {
if (temp == Head.getNext()) {
System.out.println("链表为空");
} else {
System.out.printf("未在链表中找到no=%d的节点\n", node.getNo());
}
}
}
删除节点
- 相比单链表,因为多了一个pre用于指向前一个结点,所以双链表不需要找到需要删除的节点的前一个结点,而是直接可以让需要删除的节点自我删除。
- 代码如下
public void delete(Node2 node) {//双向链表的删除不依靠前一个节点,可以进行自我删除
Node2 temp = Head.getNext();
boolean flag = false;
while (true) {
if (temp== null) {// 链表为null或者没找到,跳出循环
break;
}
if (temp.getNo() == node.getNo()) {
flag = true;
break;
}
temp = temp.getNext();
}
if (flag) {
temp.getPre().setNext(temp.getNext());//让目标节点的前一个节点的next指向目标节点的后一个节点
if(temp.getNext()!=null) {//判断目标节点是不是最后一个节点
temp.getNext().setPre(temp.getPre());//不是则让目标节点的后一个节点的pre指向目标节点的前一个结点
}
temp.setPre(null);//让目标节点的pre指向null,彻底和链分离
} else {
if (temp == Head) {
System.out.println("链表为空");
} else {
System.out.printf("链表中不存在为%d的节点\n", node.getNo());
}
}
}
完整代码
public class Node2 {
private Node2 pre;
private int no;
private String data;
private Node2 next;
public Node2(int no, String data) {
this.no = no;
this.data = data;
}
public Node2 getPre() {
return pre;
}
public void setPre(Node2 pre) {
this.pre = pre;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node2 getNext() {
return next;
}
public void setNext(Node2 next) {
this.next = next;
}
public String toString() {
return "no:" + no + " data:" + data;
}
}
public class DoubleLinkedList {
private Node2 Head=new Node2(0, "");
public void show() {// 头的数据不能展示,展示的是头之后的节点的数据
Node2 temp = Head.getNext();// 将头之后的第一个节点赋值给辅助变量
while (true) {
if (temp == null) {// 如果该节点为null说明到尾部了
break;
}
System.out.println(temp.toString());
// 不为null,说明有数据,输出该节点的数据
temp = temp.getNext();
// 令辅助变量指向下一个节点
}
}
// 直接插入数据
public void add(Node2 node) {
Node2 temp = Head;
while (true) {// 查找单链表尾部,如果为null说明到达尾部,跳出循环
if (temp.getNext() == null) {
break;
}
temp = temp.getNext();// 否则令temp指向下一个节点
}
temp.setNext(node);
node.setPre(temp);
// 找到尾部后,向尾部插入节点
}
// 通过no修改节点
public void update(Node2 node) {
Node2 temp = Head.getNext();
boolean flag = false;
while (true) {
if (temp == null) {// 链表为null或者没找到,跳出循环
break;
}
if (temp.getNo() == node.getNo()) {// 找到了,跳出循环
flag = true;
break;
}
// 没找到继续往后遍历
temp = temp.getNext();
}
if (flag) {
temp.setData(node.getData());
} else {
if (temp == Head.getNext()) {
System.out.println("链表为空");
} else {
System.out.printf("未在链表中找到no=%d的节点\n", node.getNo());
}
}
}
public void delete(Node2 node) {//双向链表的删除不依靠前一个节点,可以进行自我删除
Node2 temp = Head.getNext();
boolean flag = false;
while (true) {
if (temp== null) {// 链表为null或者没找到,跳出循环
break;
}
if (temp.getNo() == node.getNo()) {
flag = true;
break;
}
temp = temp.getNext();
}
if (flag) {
temp.getPre().setNext(temp.getNext());//让目标节点的前一个节点的next指向目标节点的后一个节点
if(temp.getNext()!=null) {//判断目标节点是不是最后一个节点
temp.getNext().setPre(temp.getPre());//不是则让目标节点的后一个节点的pre指向目标节点的前一个结点
}
temp.setPre(null);//让目标节点的pre指向null,彻底和链分离
} else {
if (temp == Head) {
System.out.println("链表为空");
} else {
System.out.printf("链表中不存在为%d的节点\n", node.getNo());
}
}
}
public static void main(String[] args) {
DoubleLinkedList dll=new DoubleLinkedList();
Node2 n1=new Node2(1, "1号");
Node2 n2=new Node2(2, "2号");
Node2 n3=new Node2(3, "3号");
dll.add(n1);
dll.add(n3);
dll.add(n2);
dll.show();
n3.setData("三号");
dll.update(n3);
System.out.println("修改后");
dll.show();
dll.delete(n2);
System.out.println("删除n2后");
dll.show();
}
}
no:1 data:1号
no:3 data:3号
no:2 data:2号
修改后
no:1 data:1号
no:3 data:三号
no:2 data:2号
删除n2后
no:1 data:1号
no:3 data:三号