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

Posted 结构化思维wz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恋上数据结构 双向链表(JDK-LinkedList底层)相关的知识,希望对你有一定的参考价值。

三、LinkedList(双向链表)

Gitee同步更新


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

实现双向链表

package 链式结构.BidirectionalLinkedList;


/**
 * @ClassName: BidirectionalLinkedList
 * @Description: 双向链表(仅有与单向链表不同的代码部分)
 * @author: wangz48
 * @date: 2021-12-28 14:07
 */

public  class BidirectionalLinkedList<E> 
    /*==============成员变量================*/
    static final int ELEMENT_NOT_FOUND = -1;
    /**
     * 链表长度
     */
    private int size;
    private Node<E> first;
    private Node<E> last;

    private static class Node<E> 
        E element;
        Node<E> prev;
        Node<E> next;
        public Node(Node<E> prev, E element, Node<E> 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<E> 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<E> oldLast = last;
            last = new Node<>(oldLast, element, null);
            if (oldLast == null)  // 这是链表添加的第一个元素
                first = last;
             else 
                oldLast.next = last;
            
         else 
            Node<E> next = node(index);
            Node<E> prev = next.prev;
            Node<E> 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<E> node = node(index);
        Node<E> prev = node.prev;
        Node<E> 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<E> node = first;
            for (int i = 0; i < size; i++) 
                if (node.element == null) return i;

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

                node = node.next;
            
        
        return ELEMENT_NOT_FOUND;
    

    /**
     * 获取index位置对应的节点对象
     * @param index
     * @return
     */
    private Node<E> node(int index) 
        rangeCheck(index);

        if (index < (size >> 1)) 
            Node<E> node = first;
            for (int i = 0; i < index; i++) 
                node = node.next;
            
            return node;
         else 
            Node<E> 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<E> 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);
        
    
    /**
     * add检查索引越界
     */
    private void rangeCheckForAdd(int index)
        if (index < 0 || index > size)
            outOfBounds(index);
        
    


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

对比动态数组:

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

源码分析

四、循环链表

实现单向循环列表

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

if(index == 0)
    first = new Node<>(element,first);
    //最后一个节点
    Node<E> last = (size == 0) ? first : node(size -1);
    last.next = first;

双向循环链表

以上是关于恋上数据结构 双向链表(JDK-LinkedList底层)的主要内容,如果未能解决你的问题,请参考以下文章

恋上数据结构队列 Queue

恋上数据结构 链表(手写LinkedList+练习)

❤️数据结构入门❤️(1 - 4)- 双向链表

数据结构(链表——双向链表的实现)

数据结构之带头结点的循环双向链表详细图片+文字讲解

Python数据结构与算法(2.4)——双向链表