数据结构:链表《双链表》

99 阅读4分钟

在上一篇文章 数据结构:链表《概念》中已经介绍了什么是链表以及链表的特性是什么,废话不多说直接上干货如果实现一个双链表。

双向链表与单向链表相比较,双向链表可以从头到尾或从尾到头两个方向来遍历数据。双向链表中的节点分三个部分,分别是指向上一个节点的地址(prev)和数据(data)以及指向下一个节点的地址(next),尾节点(tail)节点的 next 指向 null,头节点(head)的 prev 指向 null,增加和删除节点和单向链表同理,只是增加了修改 prev 地址的操作.

image.png

无头双向非循环链表接实现

 private static class LinkedNode{
        private int key;
        private String value;
        //上一个节点
        private LinkedNode prevNode;
        //下一个节点
        private LinkedNode nextNode;

        public LinkedNode(int key, String value) {
            this.key = key;
            this.value = value;
        }

        public int getKey() {
            return key;
        }

        public void setKey(int key) {
            this.key = key;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public LinkedNode getNextNode() {
            return nextNode;
        }

        public void setNextNode(LinkedNode nextNode) {
            this.nextNode = nextNode;
        }

        @Override
        public String toString() {
            return "LinkedNode{" +
                    "key=" + key +
                    ", value='" + value + ''' +
                    '}';
        }
    }

链表头部插法插入

头插法就是从头部插入节点,使新创建的节点成为新的头结点,这里需要额外考虑一个点,就是头结点是否存在,不光要设置后驱还要注意前驱,这比单链表多一个前驱节点

/**
         * 从链表头部添加
         * @param node
         * @return
         */
        public DoubleLinkedNodeList addLinkedNodeToHead(LinkedNode node) {
            if (Objects.isNull(this.headLinkedNode)) {
                this.tailLinkedNode = node;
            } else {
                node.nextNode = this.headLinkedNode;
                this.headLinkedNode.prevNode = node;
            }
            this.headLinkedNode = node;
            length++;
            return this;
        }

根据头部添加方法执行逻辑图

image.png

image.png

image.png

image.png

image.png

最终形成双链表

image.png

链表尾部插法插入

尾插法和头插法类似,必须先判断链表是否为空,双链表区别于单链表,不用每次遍历来找尾节点,双链表本身就有一个尾节点last,我们只需要找到这个last,然后将新节点插入即可

/**
         * 从链表尾添加
         * @param node
         */
        public DoubleLinkedNodeList addLinkedNodeToTail(LinkedNode node){
            //添加一个新节点,储存要插入的数据的时候判断头节点是否存在
            if (Objects.isNull(this.headLinkedNode)) {
                //判断头节点是否为空,头节点空说明链表为空
                //头节点为null属于第一次插入,直接将头节点尾节点都指向插入节点
                this.headLinkedNode=node;
                this.tailLinkedNode=node;
            }else{
                //将新节点变成原尾节点的后驱,实现尾插
                this.tailLinkedNode.nextNode=node;
                //再将原尾节点变成新插入节点的前驱
                node.prevNode=tailLinkedNode;
                //最后将新插入节点设置成尾节点
                this.tailLinkedNode=node;
            }
            length++;
            return this;
        }

尾部执行逻辑图与头部指向逻辑图查类似就不再画了,下面直接干货上代码。

完整代码

import java.util.Objects;

/**
 * @ClassName DoubleLinkedNodeDemo
 * @Description  双链表
 */
public class DoubleLinkedNodeDemo {


    public static void main(String[] args) {
        LinkedNode node6 = new LinkedNode(6, "A6");
        LinkedNode node1 = new LinkedNode(1, "A1");
        LinkedNode node2 = new LinkedNode(2, "A2");
        LinkedNode node5 = new LinkedNode(5, "A5");
        LinkedNode node3 = new LinkedNode(3, "A3");
        LinkedNode node4 = new LinkedNode(4, "A4");
        LinkedNode node7 = new LinkedNode(7, "A7");

    /*    System.out.println(">>>>>>>>>>>>>>>从头部添加节点");
        DoubleLinkedNodeList  doubleLinkedNodeList = new DoubleLinkedNodeList ();
        doubleLinkedNodeList
                .addLinkedNodeToHead(node6)
                .addLinkedNodeToHead(node1)
                .addLinkedNodeToHead(node2)
                .addLinkedNodeToHead(node5)
                .addLinkedNodeToHead(node3)
                .addLinkedNodeToHead(node4)
                .addLinkedNodeToHead(node7);
        doubleLinkedNodeList.print();*/


        System.out.println(">>>>>>>>>>>>>>>从尾部添加节点");
        DoubleLinkedNodeList  doubleLinkedNodeList = new DoubleLinkedNodeList ();
        doubleLinkedNodeList
                .addLinkedNodeToTail(node6)
                .addLinkedNodeToTail(node1)
                .addLinkedNodeToTail(node2)
                .addLinkedNodeToTail(node5)
                .addLinkedNodeToTail(node3)
                .addLinkedNodeToTail(node4)
                .addLinkedNodeToTail(node7);
        doubleLinkedNodeList.print();

        System.out.println(">>>>>>>>>>>>>>>获取节点");
        LinkedNode linkedNode= doubleLinkedNodeList.getLinkedNode(4);
        System.out.println(linkedNode.toString());

        System.out.println(">>>>>>>>>>>>>>>删除节点");
        doubleLinkedNodeList.removeLinkedNode(node5).print();

        System.out.println(">>>>>>>>>>>>>>>修改节点");
        doubleLinkedNodeList.updateLinkedNode(new LinkedNode(7, "A777777")).print();




        System.out.println(">>>>>>>>>>>>>>>按照顺序添加");
        DoubleLinkedNodeList  doubleLinkedNodeListSort = new DoubleLinkedNodeList ();
        doubleLinkedNodeListSort
                .addLinkedNodeSort(node6)
                .addLinkedNodeSort(node1)
                .addLinkedNodeSort(node2)
                .addLinkedNodeSort(node5)
                .addLinkedNodeSort(node3)
                .addLinkedNodeSort(node4)
                .addLinkedNodeSort(node7);
        doubleLinkedNodeListSort.print();



    }


    private static class DoubleLinkedNodeList{
        //定义链表头部节点

        private LinkedNode headLinkedNode ; //双链表的头部第一个节点
        private LinkedNode tailLinkedNode ; //双链表的尾部最后一个节点

        public DoubleLinkedNodeList() {
            headLinkedNode = null;
            tailLinkedNode = headLinkedNode;
        }


        /**
         * 从链表头部添加
         * @param node
         * @return
         */
        public DoubleLinkedNodeList addLinkedNodeToHead(LinkedNode node) {
            //添加一个新节点,储存要插入的数据的时候判断头节点是否存在
            if (Objects.isNull(this.headLinkedNode)) {
                //判断头节点是否为空,头节点空说明链表为空
                //头节点为null属于第一次插入,直接将头节点尾节点都指向插入节点
                this.tailLinkedNode = node;
                this.headLinkedNode = node;
            } else {
                node.nextNode = this.headLinkedNode;
                this.headLinkedNode.prevNode = node;
                this.headLinkedNode = node;
            }
            return this;
        }




        /**
         * 按照顺序添加
         *
         * @param node
         */
        public DoubleLinkedNodeList addLinkedNodeSort(LinkedNode node) {
            if (Objects.isNull(this.headLinkedNode)) {
                this.headLinkedNode = node;
                this.tailLinkedNode = node;
                return this;
            }

            // node比头节点小,将node设为头节点
            if (this.headLinkedNode.key > node.key) {
                this.headLinkedNode.prevNode = node;
                node.nextNode = this.headLinkedNode;
                this.headLinkedNode = node;
                return this;
            }

            // node比尾节点大,将node设为尾节点
            if (this.tailLinkedNode.key < node.key) {
                this.tailLinkedNode.nextNode = node;
                node.prevNode = this.tailLinkedNode;
                this.tailLinkedNode = node;
                return this;
            }

            LinkedNode temp = this.headLinkedNode.nextNode;
            while (true) {
                if (temp.key > node.key) {
                    node.nextNode = temp;
                    node.prevNode = temp.prevNode;
                    temp.prevNode.nextNode = node;
                    temp.prevNode = node;
                    break;
                }
                temp = temp.nextNode;
            }
            return this;
        }

        /**
         * 从链表尾添加
         * @param node
         */
        public DoubleLinkedNodeList addLinkedNodeToTail(LinkedNode node){
            //添加一个新节点,储存要插入的数据的时候判断头节点是否存在
            if (Objects.isNull(this.headLinkedNode)) {
                //判断头节点是否为空,头节点空说明链表为空
                //头节点为null属于第一次插入,直接将头节点尾节点都指向插入节点
                this.headLinkedNode=node;
                this.tailLinkedNode=node;
            }else{
                //将新节点变成原尾节点的后驱,实现尾插
                this.tailLinkedNode.nextNode=node;
                //再将原尾节点变成新插入节点的前驱
                node.prevNode=tailLinkedNode;
                //最后将新插入节点设置成尾节点
                this.tailLinkedNode=node;
            }
            return this;
        }

        /**
         * 获取节点
         * @param key
         * @return
         */
        public LinkedNode getLinkedNode(int key) {
            if (Objects.isNull(this.headLinkedNode)) {
                return null;
            }
            LinkedNode tempLinkedNode = this.headLinkedNode;
            while (Objects.nonNull(tempLinkedNode.key)) {
                if (tempLinkedNode.key == key) {
                    return tempLinkedNode;
                }
                tempLinkedNode = tempLinkedNode.nextNode;
            }
            return null;
        }

        /**
         * 删除节点
         * @param node
         * @return
         */
        public DoubleLinkedNodeList removeLinkedNode(LinkedNode node) {
            if (Objects.isNull(this.headLinkedNode)) {
                return this;
            }
            // 要移除的是头节点
            if (this.headLinkedNode == node) {
                this.headLinkedNode.nextNode.prevNode = null;
                this.headLinkedNode =  this.headLinkedNode.nextNode;
                return this;
            }
            // 要移除的是尾节点
            if ( this.tailLinkedNode == node) {
                this.tailLinkedNode.prevNode.nextNode = null;
                this.tailLinkedNode =  this.tailLinkedNode.prevNode;
                return this;
            }

            LinkedNode temp = this.headLinkedNode.nextNode;
            while ( Objects.nonNull(temp)) {
                if (temp.key == node.key) {
                    temp.prevNode.nextNode = temp.nextNode;
                    temp.nextNode.prevNode = temp.prevNode;
                    break;
                }
                temp = temp.nextNode;
            }
            return this;
        }


        /**
         * 修改某个节点
         *
         * @param node
         */
        public DoubleLinkedNodeList updateLinkedNode(LinkedNode node) {
            if (Objects.isNull(this.headLinkedNode)) {
                return this;
            }

            LinkedNode temp = this.headLinkedNode;
            while ( Objects.nonNull(temp)) {
                if (temp.key == node.key) {
                    temp.value = node.value;
                    break;
                }
                temp = temp.nextNode;
            }
            return this;
        }

        /**
         * 打印链表节点的数据
         */
        public void print() {
            if ( Objects.isNull(headLinkedNode)) {
                return;
            }
            LinkedNode temp = headLinkedNode;
            while (Objects.nonNull(temp)) {
                System.out.println(temp);
                temp = temp.nextNode;
            }
        }
    }

    private static class LinkedNode{
        private int key;
        private String value;
        //上一个节点
        private LinkedNode prevNode;
        //下一个节点
        private LinkedNode nextNode;

        public LinkedNode(int key, String value) {
            this.key = key;
            this.value = value;
        }

        public int getKey() {
            return key;
        }

        public void setKey(int key) {
            this.key = key;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public LinkedNode getNextNode() {
            return nextNode;
        }

        public void setNextNode(LinkedNode nextNode) {
            this.nextNode = nextNode;
        }

        @Override
        public String toString() {
            return "LinkedNode{" +
                    "key=" + key +
                    ", value='" + value + ''' +
                    '}';
        }
    }
}