LinkedList源码详解(常用方法源码分析)及 手动实现LinkedList

一、LinkedList详解

特点:
  • 元素可以重复
  • 元素可以为null
  • 数据插入有序
JDK1.8源码分析:
  • 继承关系

    继承AbstractSequentialList类,实现了List,Deque,Cloneable,Serializable接口。

public class LinkedList<E>extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  • 底层数据结构

    双向链表(源码中有表示)↓↓

 private static class Node<E> {   
        E item; 
        Node<E> next; //节点的后继
        Node<E> prev;//节点的前驱
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;  
            this.prev = prev; 
        }
    }
  • 基本属性
    transient int size = 0;   //集合中元素个数
    transient Node<E> first;  //头结点
    transient Node<E> last; //尾节点
  • 默认值
  • 构造函数(2个)
  public LinkedList() { //无参构造
    }
  public LinkedList(Collection<? extends E> c) {  //有参构造函数
        this();
        addAll(c);
    }
  • 增长方式

    无限增长(因为底层是双向链表,所以它的容量不受限制)

  • CRUD方法研究

1、添加元素:add(E e)(默认尾插方式)
  public boolean add(E e) {  
        linkLast(e); //调用linklast()
        return true;
    }
   void linkLast(E e) {  //尾插法
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);//调用节点类的构造函数实例化一个新的节点
        last = newNode; //将newNode重置为尾节点
        if (l == null)  //如果链表为空,直接把新节点置为头结点
            first = newNode;
        else 
            l.next = newNode;//链表不为空,新节点插在尾节点之后(尾插)
        size++; //容量+1
        modCount++; //版本号+1
    }
2、删除元素:remove(Object o) 
 public boolean remove(Object o) {
        if (o == null) {   //判断删除的对象是否为空
            for (Node<E> x = first; x != null; x = x.next) {
             //删除元素是从前往后删,重复元素只删除第一个出现的
                if (x.item == null) {
                    unlink(x);  //调用unlink()方法 ↓↓↓
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }
E unlink(Node<E> x) {   
		final E element = x.item;
		final Node<E> next = x.next; 
		final Node<E> prev = x.prev;
		//前驱分为两种情况
		if (prev == null) {  //头结点first
			first = next;   //令first代表的是删除的节点的下一个节点
		} else { //非头结点
			prev.next = next;
			x.prev = null;
		}
		//后继分为两种情况
		if (next == null) { //尾节点
			last = prev;  //令last代表删除的节点的上一个节点
		} else {  //非尾节点 
			next.prev = prev;
			x.next = null;
		}
 
		x.item = null;   //把当前要删除的节点置为空
		size--;  //容量-1
		modCount++;//版本号+1
 		return element; //返回删除的节点
	}
手动实现LinkedList
//我只是简单的谢了LinkedList的添加、获取和删除元素的三个方法,
//其他方法通过理解源码也可以很容易的用双向链表来实现

public class LinkedListSelf2202<T>  {

    class Entry{  //内部类表示及节点
        private int data; //节点个数
        private Entry next;

        public Entry(){
           this.next = null;
        }
        public Entry(Integer val){
            this.data = val;
            this.next = null;
        }
    }
     int size = 0; //链表的节点个数

    private Entry head = null;

     public LinkedListSelf2202(){
         this.head = new Entry(); //得到头节点的引用
     }
    //添加
    public void add(int val){
        Entry cur = this.head;
        while (cur.next != null) {
            cur = cur.next;  //cur++
        }
        Entry entry = new Entry(val);
        cur.next = entry;
        size ++;
    }
    //查找
    public Entry search(Integer val){
         Entry cur = this.head;
         while(cur.next != null){
             if(cur.next.data == val) {
                 return cur;
             }cur = cur.next;
         }return null;
    }
    //获取
    public int get(int index){
         Entry entry = this.head;
        if(index>=0 && index<size){
            for (int i = 0; i <= index; i++) {
                entry = entry.next;
            }
        }
        return entry.data;
    }
    //删除
    public boolean remove(int key){
       Entry cur = search(key); //先查找要删除的元素是否存在
       if(cur == null){
           //待删除元素在集合中不存在
           return false;
       }
       Entry del = cur.next;
       cur.next = del.next;
       size--;
       return true;
    }
    //打印
    public void show() {
        Entry cur = this.head.next;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        LinkedListSelf2202 linkedListSelf2202 = new LinkedListSelf2202();
        linkedListSelf2202.add(22);
        linkedListSelf2202.add(33);
        linkedListSelf2202.add(44);
     
        linkedListSelf2202.show();
        Integer integer = linkedListSelf2202.get(0);
        System.out.println(integer);

        linkedListSelf2202.remove(22);
        linkedListSelf2202.show();
    }
}
执行结果:

在这里插入图片描述

ArrayList和LinkedList异同点,各自的优势(应用场景)?

  1. 相同点
    继承关系:都是List接口下的实现类具有List提供的方法
    有序性:数据都是插入有序
    重复性:集合中元素是可以重复的
    null值:都可以存储null值
    安全性:都是非线程安全的集合(都可能会出现并发性异常ConcurrentModificationException())

  2. 不同点
    数据结构:ArrayList底层是数组。LinkedList底层是双向链表
    特有方法:LinkedList因为实现了Deque双向队列接口,具有特有的方法:例如addFirst() 、 addLast()
    效率: ArrayList访问效率高,移动、删除效率低, LinkedList 插入、删除效率高,访问效率低
    (ArrayList查询时间复杂度O(1)、LinkedList插入时间复杂度O(1))
    3.应用场景
    根据两者的效率来看:
    ArrayList在查询较高的业务场景优先考虑,
    LinkedList在修改、添加等操作较多的场景下优先考虑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值