单向链表和双向链表的区别:

单向链表查找的方向是单一的,而双向链表既可以向前查找,也可以向后查找;
在删除时,单向链表需要靠辅助节点进行删除操作,而双向链表则不需要。

和单链表一样,首先仍然需要先创建一个头结点
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();
    }
}