单向链表和双向链表的区别:
单向链表查找的方向是单一的,而双向链表既可以向前查找,也可以向后查找;
在删除时,单向链表需要靠辅助节点进行删除操作,而双向链表则不需要。
和单链表一样,首先仍然需要先创建一个头结点
public class Node {
public int no;
public String name;
public Node pre;//指向前一个节点
public Node next;//指向下一个节点
public Node(int no, String name) {
this.no = no;
= name;
}
@Override
public String toString() {
return "Node{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
双向链表的添加,修改,删除以及遍历的代码如下:
public class DoubleLinkedList {
//先初始化一个头结点,头结点不要动,不存放具体数据
private Node head = new Node(0, "");
//添加节点到双向链表(无顺序添加)
public void add(Node node) {
//因为head节点不能动,因此我们需要一个临时变量temp
Node temp = head;
//遍历链表,找到最后节点
while (true) {
//找到链表的最后
if (temp.next == null) {
break;
}
//如果没有找到最后,就将temp后移
temp = temp.next;
}
//当退出while循环时,temp就指向了链表的最后
temp.next = node;//将当前链表最后节点的下一节点指向新节点
node.pre = temp;//将新节点的前一节点指向当前链表的最后节点
}
//添加节点到双向链表(按顺序添加)
public void addByOrder(Node node) {
//因为头结点不能动,所以我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
Node temp = head;
//flag用来判断添加的编号是否存在,默认值为false
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if ( > node.no) {
temp.next.pre = node;//将较大值的前一节点指向较小值
break;
} else if ( == node.no) {
//说明编号存在
flag = true;
break;
}
//指针后移,遍历当前链表
temp = temp.next;
}
//判断flag的值
if (flag) {
//此时不能添加,说明编号已存在
System.out.printf("编号%d已存在,无法添加\n", node.no);
} else {
node.next = temp.next;//将较小值的下一节点指向较大值
node.pre = temp;//将新加入节点的前一节点指向temp
temp.next = node;//将temp的下一节点指向新插入的节点
}
}
//修改节点的信息,根据no编号来修改,即no编号不能改
public void upDate(Node node) {
//判断链表是否为空
if (head.next == null) {
System.out.println("链表为空!");
}
//找到需要修改的节点,根据no编号
//定义一个辅助变量
Node temp = head;
//表示是否找到该节点
boolean flag = false;
while (true) {
if (temp.next == null) {
//表示已经遍历完该链表
break;
}
if (temp.no == node.no) {
//找到该节点
flag = true;
break;
}
temp = temp.next;
}
//根据flag判断是否找到要修改的节点
if (flag) {
= ;
} else {
//没有找到
System.out.printf("没有找到编号为%d的节点,无法修改\n", node.no);
}
}
//删除节点
public void deleteDate(int no) {
if (head.next == null) {
System.out.println("链表为空,无法删除!");
return;
}
Node temp = head.next;
//判断是否找到待删除节点
boolean flag = false;
while (true) {
if (temp == null) {
//说明已经到达链表的尾部
break;
}
if (temp.no == no) {
//找到要删除的节点
flag = true;
break;
}
temp = temp.next;
}
//对flag进行判断
if (flag) {
//删除节点的核心语句
temp.pre.next = temp.next;
//防止要删除的节点是最后一个节点,避免出现空指针异常,作如下判断
if (temp.next != null) {
temp.next.pre = temp.pre;
}
} else {
System.out.printf("要删除的%d节点不存在\n", no);
}
}
//遍历链表
public void list() {
//判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
return;
}
//因为头结点不能动,所以需要一个辅助变量来遍历
Node temp = head.next;
while (true) {
//判断是否到链表最后
if (temp == null) {
break;
}
//输出节点的信息
System.out.println(temp);
//最后要将temp后移,不然会造成死循环
temp = temp.next;
}
}
}
双向链表的遍历以及修改的方式和单链表一样,主要区别在添加和删除操作上。尤其就删除操作而言,相比于单链表,双向链表显得更加灵活。
测试代码如下:
public class DoubleLinkedListTest {
public static void main(String[] args) {
//1、创建节点
Node node1 = new Node(1, "1");
Node node2 = new Node(2, "2");
Node node3 = new Node(3, "3");
Node node4 = new Node(4, "4");
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
DoubleLinkedList doubleLinkedList2 = new DoubleLinkedList();
doubleLinkedList.add(node4);
doubleLinkedList.add(node1);
doubleLinkedList.add(node3);
doubleLinkedList.add(node2);
System.out.println("无顺序添加");
doubleLinkedList.list();
doubleLinkedList2.addByOrder(node4);
doubleLinkedList2.addByOrder(node1);
doubleLinkedList2.addByOrder(node3);
doubleLinkedList2.addByOrder(node2);
System.out.println("有顺序添加");
doubleLinkedList2.list();
//测试修改方法
doubleLinkedList2.upDate(new Node(2,"小红"));
System.out.println("修改之后");
doubleLinkedList2.list();
//测试删除方法
doubleLinkedList2.deleteDate(4);
System.out.println("删除之后");
doubleLinkedList2.list();
}
}