分析轮子(六)- LinkedList.java
注:玩的是JDK1.7版本
一:先上类的继承结构图

二:再看一下他的底层实现数据结构

三:然后从源码中找点好玩的东西
1)双向链表的结构构成元素,头指针、尾指针、节点信息(前向指针、后向指针、节点信息)
/**
* 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;
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;
}
}
2)在链表尾部添加新节点,只需要改变链表尾指针的指针指向就可了,所以,性能相对 ArrayList.java 的数组拷贝会好很多
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* Links e as last element.
*/
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++;
}
3)根据索引位置,获取节点,会遍历链表性能相对会差一些,并且我们也能看到遍历的时候也有一个优化,通过索引位置和链表长度的一半比较,决定从头遍历还是从尾遍历,这样能通过减少遍历长度加快遍历速度的作用,不过当索引位置在中间的时候,就不好玩了,无论从头或从尾遍历性能不会比较差
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
/**
* Returns the (non-null) Node at the specified element index.
*/
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;
}
}
4)根据节点信息获取索引位置的方法,可以看到节点信息是允许为null的
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @return the index of the first occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
5)下面的三个方法,是根据索引位置,修改、删除索引位置的节点,都会遍历链表,所以,性能相对会差一些,ArrayListljava 是通过数组的索引位置直接操作的
/**
* Replaces the element at the specified position in this list with the
* specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
/**
* Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
checkPositionIndex(index); if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
6)双向链表也可以当做双向队列使用

分析轮子(六)- LinkedList.java的更多相关文章
- java集合源码分析(六):HashMap
概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...
- 分析轮子(五)- Vector.java
注:玩的是JDK1.7版本 一: 先上类图,从类图上看和 ArrayList.java 非常相像,可查看 分析轮子(一)-ArrayList.java 二:然后看源码,发现和 ArrayList.ja ...
- 分析轮子(四)- 我也玩一把 Serializable.java
前言:在写 分析轮子(一)-ArrayList.java 的时候曾经下过一个结论 “实现Serializable接口,表示ArrayList是可序列化的”,这个结论是以往学习的经验所得,并且平时在编程 ...
- 一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要
一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要 liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.什么 ...
- 分析轮子(二)- << ,>>,>> (左移、右移、无符号右移)
前言:写 分析轮子(一)-ArrayList.java 的时候看到源码中有 int newCapacity = oldCapacity + (oldCapacity >> 1); 这样的代 ...
- JVM 内部原理(六)— Java 字节码基础之一
JVM 内部原理(六)- Java 字节码基础之一 介绍 版本:Java SE 7 为什么需要了解 Java 字节码? 无论你是一名 Java 开发者.架构师.CxO 还是智能手机的普通用户,Java ...
- SpringBoot启动流程分析(六):IoC容器依赖注入
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- LinkedList - java.util.ConcurrentModificationException
package com.test.io; import java.io.BufferedReader; import java.io.FileNotFoundException; import jav ...
- Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质
原文:Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质 Linux内核分析(六) 昨天我们对字符设备进行了初步的了解,并且实现了简单的字符设备驱动,今天我们继续对字符设备的某些方 ...
- LINUX内核分析第六周学习总结——进程的描述与创建
LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...
随机推荐
- Spark-Unit1-spark概述与安装部署
一.Spark概述 spark官网:spark.apache.org Spark是用的大规模数据处理的统一计算引擎,它是为大数据处理而设计的快速通用的计算引擎.spark诞生于加油大学伯克利分校AMP ...
- Java实现Windows、Mouse监听器
1.通过实现WindowListener接口来实现Windows监听器: import java.awt.event.WindowEvent; import java.awt.event.Window ...
- hdu 3499 flight 【分层图】+【Dijkstra】
<题目链接> 题目大意: 现在给你一些点,这些点之间存在一些有向边,每条边都有对应的边权,有一次机会能够使某条边的边权变为原来的1/2,求从起点到终点的最短距离. 解题分析: 分层图最短路 ...
- jupyter notebook不能选择虚拟环境的解决方法
今天使用dlib没有py37版本,因此创建了Version_36虚拟环境.但jupyter notebook默认的内核找不到新建的虚拟环境,解决方法是需要安装两个包: × ipykernel × nb ...
- 声明式调用---Feign
Feign:Feign是一种声明式.模板化的HTTP客户端. 用我的理解来说,Feign的功能类似dubbo暴露服务,但是与dubbo稍有不同的是Feign是HTTP REST接口的形式暴露的. 这一 ...
- 按字典序依次打印只由1~n组成的n位数
//我的dfs入门.将1~n一次填入数组然后打印. #include<stdio.h> #include<string.h> ]; ]; void dfs(int,int); ...
- [MySQL] MySQL联表查询的执行顺序优化查询
SELECT t4.orgName, t3.projectName, t3.Partner, t1.type, COUNT(DISTINCT t1.imei) AS count FROM `t_tem ...
- [Python]Python入坑小项目推荐- Flask example minitwit
知乎上看到的Python练手项目推荐,链接见:https://www.zhihu.com/question/29372574,不知道是我自己懒得看还是理解力不行,这些项目真的是...太大了呀~~~~ ...
- Codeforces.578E.Walking(构造)
题目链接 \(Description\) 给定一个长为\(n\)的足迹序列(只包含\(L,R\)两种字符),你需要\(LRLRLR...\)这样交替在\(L\)和\(R\)上走(第一步可以选择\(L\ ...
- BZOJ.4888.[TJOI2017]异或和(树状数组)
BZOJ 洛谷 \(Description\) 求所有区间和的异或和. \(n\leq 10^5,\ \sum a_i\leq 10^6\). \(Solution\) 这样的题还是要先考虑按位做. ...