栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【恋上数据结构】 双向链表(JDK-LinkedList底层)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【恋上数据结构】 双向链表(JDK-LinkedList底层)

三、linkedList(双向链表)

Gitee同步更新

文章目录
    • 三、linkedList(双向链表)
      • 实现双向链表
      • 源码分析
    • 四、循环链表
      • 实现单向循环列表
      • 双向循环链表

JDK中linkedList就是用双向链表实现的

实现双向链表

package 链式结构.BidirectionallinkedList;




public  class BidirectionallinkedList {
    
    static final int ELEMENT_NOT_FOUND = -1;
    
    private int size;
    private Node first;
    private Node last;

    private static class Node {
        E element;
        Node prev;
        Node next;
        public Node(Node prev, E element, Node next) {
            this.prev = prev;
            this.element = element;
            this.next = next;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();

            if (prev != null) {
                sb.append(prev.element);
            } else {
                sb.append("null");
            }

            sb.append("_").append(element).append("_");

            if (next != null) {
                sb.append(next.element);
            } else {
                sb.append("null");
            }

            return sb.toString();
        }
    }

    public void clear() {
        size = 0;
        first = null;
        last = null;
    }

    public E get(int index) {
        return node(index).element;
    }


    public E set(int index, E element) {
        Node node = node(index);
        E old = node.element;
        node.element = element;
        return old;
    }


    public void add(int index, E element) {
        rangeCheckForAdd(index);

        // size == 0
        // index == 0
        if (index == size) { // 往最后面添加元素
            Node oldLast = last;
            last = new Node<>(oldLast, element, null);
            if (oldLast == null) { // 这是链表添加的第一个元素
                first = last;
            } else {
                oldLast.next = last;
            }
        } else {
            Node next = node(index);
            Node prev = next.prev;
            Node node = new Node<>(prev, element, next);
            next.prev = node;

            if (prev == null) { // index == 0
                first = node;
            } else {
                prev.next = node;
            }
        }

        size++;
    }


    public E remove(int index) {
        rangeCheck(index);

        Node node = node(index);
        Node prev = node.prev;
        Node next = node.next;

        if (prev == null) { // index == 0
            first = next;
        } else {
            prev.next = next;
        }

        if (next == null) { // index == size - 1
            last = prev;
        } else {
            next.prev = prev;
        }

        size--;
        return node.element;
    }


    public int indexOf(E element) {
        if (element == null) {
            Node node = first;
            for (int i = 0; i < size; i++) {
                if (node.element == null) {return i;}

                node = node.next;
            }
        } else {
            Node node = first;
            for (int i = 0; i < size; i++) {
                if (element.equals(node.element)) {return i;}

                node = node.next;
            }
        }
        return ELEMENT_NOT_FOUND;
    }

    
    private Node node(int index) {
        rangeCheck(index);

        if (index < (size >> 1)) {
            Node node = first;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            return node;
        } else {
            Node node = last;
            for (int i = size - 1; i > index; i--) {
                node = node.prev;
            }
            return node;
        }
    }

    @Override
    public String toString() {
        StringBuilder string = new StringBuilder();
        string.append("size=").append(size).append(", [");
        Node node = first;
        for (int i = 0; i < size; i++) {
            if (i != 0) {
                string.append(", ");
            }

            string.append(node);

            node = node.next;
        }
        string.append("]");
        return string.toString();
    }
    

    
    private void outOfBounds(int index){
        throw new IndexOutOfBoundsException("Index"+index+",Size:"+size);
    }
    
    private void rangeCheck(int index){
        if (index < 0 || index >= size){
            outOfBounds(index);
        }
    }
    
    private void rangeCheckForAdd(int index){
        if (index < 0 || index > size){
            outOfBounds(index);
        }
    }
}

总结:双向链表对于单向链表操作数量缩减了一半。

对比动态数组:

  • 动态数组:开辟、销毁内存空间的次数相对较少,但可能造成内存空间的浪费。(可以通过缩容解决)
  • 双向链表:开辟、销毁内存空间的操作次数相对较多,但不会造成内存空间的浪费。

源码分析

四、循环链表 实现单向循环列表

与单向链表的不同: 添加、删除操作需要维护最后一个节点。

if(index == 0){
    first = new Node<>(element,first);
    //最后一个节点
    Node last = (size == 0) ? first : node(size -1);
    last.next = first;
}
双向循环链表

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/684133.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号