关于LinkedList经验分享(源码分析)
来源:互联网 发布:淘宝上好看的情侣装店 编辑:程序博客网 时间:2024/06/08 09:49
集合的作用就是以一定的方式组织,存储数据。对于LinkedList,我认为需要的关注以下内容:
1.集合的基本存储单元
2.集合的增删改查基本操作的实现
3.存储数据的要求,是否为空,是否允许重复
4.存放与读取是否有序
5.是否线程安全
基本存储单元
LinkedList的源码片段:
transient int size = 0; /** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient Node<E> first; /** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient Node<E> last;
双向链表实现,链表长度size,头指针first,尾指针last。
集合的增删改查基本操作的实现
1.新增元素
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
新建一个l节点指向当前last节点,新建一个newNode节点,将newNode的prev指向l地址,last节点指向newNode,如果链表中无数据,将first节点指向newNode,如果存在数据,将l节点指向newNode节点,这样就实现了l与newNode的双向链接。
public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
插入元素时,当插入的是最后一个元素时(即顺序插入),和add方法一致,这里分析下中间插入。新建一个pred节点指向当前succ节点的上一个位置,新建newNode节点,newNode的prev指向pred,next指向succ,此时newNode节点已经链接了前后节点,接下来需要将前节点的next指向newNode,及将后节点的prev指向newNode,这样,newNode的双向链接就完成了。
2.修改元素
public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
用node方法取出节点,修改val,后面分析node方法。
3.删除元素
E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
先找出当前节点x的前后节点,prev节点及next节点。将prev的next指向next节点,将next的prev指向prev节点,最后将x的prev和next设置为null。
4.寻址
Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
寻址方式比较重要,这里用了位运算,加快速度。当index小于长度的一般,从头开始寻址;反之从尾部开始寻址。
其实链表操作的分析最好在纸上画出来,先找出当前节点的前后节点,更改链接的方向,一目了然。
存储数据的要求,是否为空,是否允许重复
允许为空或者null,允许重复
存放与读取是否有序
底层实现是双向链表,所以有序
是否线程安全
非线程安全,因为所有方法都是不同步的。
LinkedList与ArrayList的比较
LinkdList基于Node数组的实现,每次插入都需new一个Node对象,并维护一些引用地址,所以耗费的空间和时间比ArrayList要大。但是当集合的数据量变大,而且需要中间插入数据的操作变多,ArrayList就需要耗费大量时间和空间去进行数据copy,大大降低了性能,这时LinkedList的优势就显现出来了。总体来说,LinkedList快在维持引用关系,慢在寻址,但ArrayList快在寻址,慢在数组的copy。
再说一下迭代的问题,ArrayList实现了RandomAccess接口,支持快速随机访问,ArrayList在随机或连续访问列表是都有良好的性能,for和foreach的速度都很快。LinkedList在用foreach,即Iteratior迭代器访问时有良好的性能表现,但在普通for循环时,速度会慢的让人发狂。
以下为测试结果,单位ms:
init arrayList : 62init linkedList : 47init finished!test005 ArrayList 普通for循环速度(10W条数据): 1test006 ArrayList Iterator循环速度(10W条数据): 16test007 LinkedList 普通for循环速度(10W条数据): 37781test008 : LinkedList Iterator循环速度(10W条数据)16
- 关于LinkedList经验分享(源码分析)
- 关于ArrayList经验分享(源码分析)
- 关于HashMap经验分享(源码分析)
- LinkedList 源码分析
- LinkedList源码分析
- ArrayList LinkedList 源码分析
- ArrayList,LinkedList源码分析
- 源码分析之LinkedList
- LinkedList源码分析
- LinkedList源码分析
- Java LinkedLIst 源码分析
- LinkedList源码分析
- 【java源码分析】-LinkedList
- LinkedList源码分析
- LinkedList源码分析
- Java LinkedList 源码分析
- LinkedList源码分析(unfinished)
- LinkedList的源码分析
- 量化分析师的Python日记【Q Quant兵器谱之偏微分方程2】
- Linux chmod命令详解
- C++ 用libcurl库进行http通讯网络编程
- web安全————注入(初识篇)
- Spring中的@Transactional深度分析之二
- 关于LinkedList经验分享(源码分析)
- Windows中删除路径太长目录及文件
- xcode处理is missing from working copy警告
- Mac 下的Eclipse因非正常关闭启动未响应的解决方法
- java的一些基础知识总结
- php redis的简单操作实例
- nginx 反向代理 某个目录下 带特定后缀名的文件
- C++使用libcurl做HttpClient
- 加载WEB-INF下的配置文件的工具类