From 6314718cc496a5c016dd43343ce3ebbffb1b0ab2 Mon Sep 17 00:00:00 2001 From: wxm <602260235@qq.com> Date: Sun, 8 Mar 2020 17:50:03 +0800 Subject: [PATCH] =?UTF-8?q?073=E7=9A=84=E7=AC=AC=E4=B8=80=E5=91=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20\347\240\201\345\210\206\346\236\220.md" | 266 +++++++++ ...20\347\240\201\345\210\206\346\236\220.md" | 554 ++++++++++++++++++ ...20\347\240\201\345\210\206\346\236\220.md" | 324 ++++++++++ 3 files changed, 1144 insertions(+) create mode 100644 "second/week_01/73/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" create mode 100644 "second/week_01/73/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" create mode 100644 "second/week_01/73/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" diff --git "a/second/week_01/73/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/second/week_01/73/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" new file mode 100644 index 0000000..24ac92f --- /dev/null +++ "b/second/week_01/73/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -0,0 +1,266 @@ +##关于ArrayList的随笔 + + + +## 继承体系 + +- AbstractList +- List +- RandomAccess +- Cloneable +- java.io.Serializable + + +###1、初步认识ArrayList + + +> List 是一种以数组形式实现的有序集合,特点是动态扩展。 +> 默认容量是10 +> 每次扩容1.5倍 + 如果加了这么多容量发现比需要的容量还小,则以需要的容量为准 + + + + +## 构造方法 + +1. 属性分析 + +- ```java + //默认初始容量 10 + private static final int DEFAULT_CAPACITY = 10; + ``` + +- ```java + // 一个空数组,当用户指定ArrayList容量为0时,返回该数组 + private static final Object[] EMPTY_ELEMENTDATA = {}; + ``` + +- ```java + // 一个空对象,如果使用默认构造函数创建,则默认对象内容默认是该值 + private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; + ``` + +- ```java + // 动态数组的实际大小 ,默认为0 + private int size; + ``` +- ```java + // 最大数组容量Integer -8 避免内存溢出 + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + ``` + + +2. 构造方法 + + ​ + + ```java + /** + * 默认构造方法,初始化为空数组,当添加第一个元素的时候扩容为10 + */ + public ArrayList() { + this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; + } + ``` + + + + ```java + /** + * 传入初始换容量,如果大于0就初始化elementData为对应大小,如果等于0就使用EMPTY_ELEMENTDATA空数组,如果小于0抛出异常。 + */ + public ArrayList(int initialCapacity) { + if (initialCapacity > 0) { + this.elementData = new Object[initialCapacity]; + } else if (initialCapacity == 0) { + this.elementData = EMPTY_ELEMENTDATA; + } else { + throw new IllegalArgumentException("Illegal Capacity: "+ + initialCapacity); + } + } + ``` + + + ```java + /** + * 传入集合并初始化elementData,这里会使用拷贝把传入集合的元素拷贝到elementData数组中,如果元素个数为0,则初始化为EMPTY_ELEMENTDATA空数组。 + * 其中需要判断elementData的类型,如果不是object就重新拷贝成Object类型 + */ + public ArrayList(Collection c) { + elementData = c.toArray(); + if ((size = elementData.length) != 0) { + if (elementData.getClass() != Object[].class) + elementData = Arrays.copyOf(elementData, size, Object[].class); + } else { + this.elementData = EMPTY_ELEMENTDATA; + } + } + ``` + + ## + +## 方法 + +1. size + + ```java + /** + * 返回list中的元素数量 + */ + public int size() { + return size; + } + ``` + +2. isEmpty + + ```java + /** + * 判断list是否是空数组,如果list中不包含元素返回 true + */ + public boolean isEmpty() { + return size == 0; + } + ``` + +3. get + + ```java + /** + * 返回list在指定位置的元素 + */ + public E get(int index) { + Objects.checkIndex(index, size); + return elementData(index); + } + ``` + +4. set + + ```java + /** + * 替换指定位置元素 + */ + public E set(int index, E element) { + Objects.checkIndex(index, size); + E oldValue = elementData(index); + elementData[index] = element; + return oldValue; + } + ``` + +5. iterator + + ```java + /** + * 返回此list的遍历器(以正确的顺序) + */ + public Iterator iterator() { + return new Itr(); + } + ``` + +6. listIterator + + ```java + /** + * 继承于Iterator接口,只能用于各种List类型的访问 + */ + public ListIterator listIterator(int index) { + rangeCheckForAdd(index); + return new ListItr(index); + } + ``` + + +7. add + + ```java + /** + * 在列表中结尾增加指定元素 + * 其中modCount是指修改次数 + */ + public boolean add(E e) { + modCount++; + add(e, elementData, size); + return true; + } + + + +8. addAll + + ```java + /** + * 将所有集合中元素加入此list的最后 + */ + public boolean addAll(Collection c) { + // 转成数组 + Object[] a = c.toArray(); + // 修改数量 + 1 + modCount++; + // 增加的数量 还有空指针的风险 + int numNew = a.length; + if (numNew == 0) + return false; + Object[] elementData; + // 增加的位置 + final int s; + if (numNew > (elementData = this.elementData).length - (s = size)) + elementData = grow(s + numNew); + // 将集合c中的元素拷贝到最后 + System.arraycopy(a, 0, elementData, s, numNew); + size = s + numNew; + return true; + } + + + ``` + +9. remove + + ```java + /** + * 移除list中第一个出现的元素(如果存在的话),如果list不包含元素,那这个就不会改变。更正式来说就是移除低索 + * 引的元素 满足Objects.equals(o, get(i))的元素存在。 + * 将元素删除后将后面的数据前移并且不再缩减容量 + */ + public boolean remove(Object o) { + final Object[] es = elementData; + final int size = this.size; + int i = 0; + // 代码块 + found: { + // 区分为空 + if (o == null) { + for (; i < size; i++) + if (es[i] == null) + break found; + // 不为空的 + } else { + for (; i < size; i++) + if (o.equals(es[i])) + break found; + } + return false; + } + fastRemove(es, i); + return true; + } + + /** + * 基础的移除方法 跳过界限检查不返回移除的元素 + */ + private void fastRemove(Object[] es, int i) { + modCount++; + final int newSize; + if ((newSize = size - 1) > i) + System.arraycopy(es, i + 1, es, i, newSize - i); + es[size = newSize] = null; + } + + ``` + + \ No newline at end of file diff --git "a/second/week_01/73/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/second/week_01/73/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" new file mode 100644 index 0000000..0b86511 --- /dev/null +++ "b/second/week_01/73/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -0,0 +1,554 @@ +# 关于HashMap的随笔 + + + +## 继承体系 + +### 继承 + +​ AbstractMap + +### 实现 + +1. Map +2. Cloneable +3. Serializable + +## 主要属性 + +```java +/** + * 默认初始容量16 + */ +static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 + +/** + * 最大的容量 + */ +static final int MAXIMUM_CAPACITY = 1 << 30; + +/** + * 默认加载因子,作用于扩容 + */ +static final float DEFAULT_LOAD_FACTOR = 0.75f; + +/** + * 使用树的桶数量阈值 + */ +static final int TREEIFY_THRESHOLD = 8; + +/** + * 树退化成链表的阈值 + */ +static final int UNTREEIFY_THRESHOLD = 6; + +/** + * 当桶的个数达到64的时候才进行树化 + */ +static final int MIN_TREEIFY_CAPACITY = 64; +``` + +```java +/** + * 桶(表),第一次使用时才会初始化,必要时扩容 + */ +transient Node[] table; + +/** + * 缓存键值对的entrySet + */ +transient Set> entrySet; + +/** + * 键值对的数量 + */ +transient int size; + +/** + * 改变次数 + */ +transient int modCount; + +/** + * 当桶的使用数量达到多少时进行扩容 + */ +int threshold; + +/** + * 加载因子 + */ +final float loadFactor; +``` + +## 构造函数 + +1. 空构造函数 + + ```java + /** + * 默认值 16 + */ + public HashMap() { + this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted + } + ``` + +2. 传入Map的构造函数 + + ```java + /** + * 构造足够承载目标的容量 + */ + public HashMap(Map m) { + this.loadFactor = DEFAULT_LOAD_FACTOR; + putMapEntries(m, false); + } + ``` + + ```java + /** + * 初始化或将table双倍。如果是初始化,通过初始化容量threshold来分配, + * 然而由于我们使用了二次幂的扩容方式,元素可能存储在原索引位置,或者移动到二次幂的新表中 + */ + final Node[] resize() { + Node[] oldTab = table; + int oldCap = (oldTab == null) ? 0 : oldTab.length; + // 过去的扩容指标 + int oldThr = threshold; + int newCap, newThr = 0; + if (oldCap > 0) { + if (oldCap >= MAXIMUM_CAPACITY) { + threshold = Integer.MAX_VALUE; + return oldTab; + } + // 旧容量 >= DEFAULT_INITIAL_CAPACITY && 新容量 = 旧容量 * 2 < MAXIMUM_CAPACITY + else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && + oldCap >= DEFAULT_INITIAL_CAPACITY) + // 这种就是翻倍的情况 + newThr = oldThr << 1; // double threshold + } + else if (oldThr > 0) // initial capacity was placed in threshold + newCap = oldThr; + else { // zero initial threshold signifies using defaults + // 初始默认值 + newCap = DEFAULT_INITIAL_CAPACITY; + newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); + } + if (newThr == 0) { + float ft = (float)newCap * loadFactor; + newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? + (int)ft : Integer.MAX_VALUE); + } + threshold = newThr; + @SuppressWarnings({"rawtypes","unchecked"}) + Node[] newTab = (Node[])new Node[newCap]; + table = newTab; + if (oldTab != null) { + for (int j = 0; j < oldCap; ++j) { + Node e; + if ((e = oldTab[j]) != null) { + // gc help + oldTab[j] = null; + if (e.next == null) + newTab[e.hash & (newCap - 1)] = e; + else if (e instanceof TreeNode) + ((TreeNode)e).split(this, newTab, j, oldCap); + else { // preserve order + Node loHead = null, loTail = null; + Node hiHead = null, hiTail = null; + Node next; + do { + next = e.next; + if ((e.hash & oldCap) == 0) { + if (loTail == null) + loHead = e; + else + loTail.next = e; + loTail = e; + } + else { + if (hiTail == null) + hiHead = e; + else + hiTail.next = e; + hiTail = e; + } + } while ((e = next) != null); + if (loTail != null) { + loTail.next = null; + newTab[j] = loHead; + } + if (hiTail != null) { + hiTail.next = null; + newTab[j + oldCap] = hiHead; + } + } + } + } + } + return newTab; + } + ``` + + ```java + /** + * 实现Map.put 和 相关方法,关于put的方法在后面 + */ + final V putVal(int hash, K key, V value, boolean onlyIfAbsent, + boolean evict) { + Node[] tab; Node p; int n, i; + // 容器没有初始化的情况下 需要调用resize + if ((tab = table) == null || (n = tab.length) == 0) + n = (tab = resize()).length; + // 如果该位置为空的情况直接赋值 即 桶的位置上为空 + if ((p = tab[i = (n - 1) & hash]) == null) + tab[i] = newNode(hash, key, value, null); + else { + // 此位置已存在桶 + Node e; K k; + if (p.hash == hash && + ((k = p.key) == key || (key != null && key.equals(k)))) + e = p; + else if (p instanceof TreeNode) + // 如果已经是树了,那么调用TreeNode#putTreeVal + e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value); + else { + for (int binCount = 0; ; ++binCount) { + if ((e = p.next) == null) { + p.next = newNode(hash, key, value, null); + // 如果插入了新数据后链表长度大于8,那么就要进行树化 + if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st + treeifyBin(tab, hash); + break; + } + if (e.hash == hash && + ((k = e.key) == key || (key != null && key.equals(k)))) + break; + p = e; + } + } + // 找到相同key的元素 + if (e != null) { // existing mapping for key + V oldValue = e.value; + // 是否要替换旧值 + if (!onlyIfAbsent || oldValue == null) + e.value = value; + afterNodeAccess(e); + return oldValue; + } + } + ++modCount; + if (++size > threshold) + resize(); + afterNodeInsertion(evict); + return null; + } + ``` + + + +## 内部类 + +1. Node + + ```java + /** + * 基础hash桶节点,是一个典型的单链表节点 + */ + static class Node implements Map.Entry { + final int hash; + final K key; + V value; + // 单向链表 + Node next; + + Node(int hash, K key, V value, Node next) { + this.hash = hash; + this.key = key; + this.value = value; + this.next = next; + } + + public final K getKey() { return key; } + public final V getValue() { return value; } + public final String toString() { return key + "=" + value; } + + public final int hashCode() { + return Objects.hashCode(key) ^ Objects.hashCode(value); + } + + public final V setValue(V newValue) { + V oldValue = value; + value = newValue; + return oldValue; + } + + public final boolean equals(Object o) { + if (o == this) + return true; + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry)o; + if (Objects.equals(key, e.getKey()) && + Objects.equals(value, e.getValue())) + return true; + } + return false; + } + } + ``` + + + +2. TreeNode + + ```java + /** + * 树桶,继承了 LinkedHashMap.Entry,所以即可以作为常规或链式节点 + */ + static final class TreeNode extends LinkedHashMap.Entry { + // 父亲节点 + TreeNode parent; // red-black tree links + // 左节点 + TreeNode left; + // 右节点 + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + // 构造方法 + TreeNode(int hash, K key, V val, Node next) { + super(hash, key, val, next); + } + + /** + * Returns root of tree containing this node. + * 树的根 + */ + final TreeNode root() { + for (TreeNode r = this, p;;) { + if ((p = r.parent) == null) + return r; + r = p; + } + } + + /** + * 确保给的根是头结点,将Root移到最前面 + * Ensures that the given root is the first node of its bin. + */ + static void moveRootToFront(Node[] tab, TreeNode root) { + int n; + if (root != null && tab != null && (n = tab.length) > 0) { + int index = (n - 1) & root.hash; + TreeNode first = (TreeNode)tab[index]; + if (root != first) { + Node rn; + tab[index] = root; + TreeNode rp = root.prev; + if ((rn = root.next) != null) + ((TreeNode)rn).prev = rp; + if (rp != null) + rp.next = rn; + if (first != null) + first.prev = root; + root.next = first; + root.prev = null; + } + assert checkInvariants(root); + } + } + + /** + * 找到给定hash值和key的Treenode + * Finds the node starting at root p with the given hash and key. + * The kc argument caches comparableClassFor(key) upon first use + * comparing keys. + */ + final TreeNode find(int h, Object k, Class kc) { + TreeNode p = this; + do { + int ph, dir; K pk; + TreeNode pl = p.left, pr = p.right, q; + if ((ph = p.hash) > h) + p = pl; + else if (ph < h) + p = pr; + else if ((pk = p.key) == k || (k != null && k.equals(pk))) + return p; + else if (pl == null) + p = pr; + else if (pr == null) + p = pl; + else if ((kc != null || + (kc = comparableClassFor(k)) != null) && + (dir = compareComparables(kc, k, pk)) != 0) + p = (dir < 0) ? pl : pr; + else if ((q = pr.find(h, k, kc)) != null) + return q; + else + p = pl; + } while (p != null); + return null; + } + + /** + * Calls find for root node. + */ + final TreeNode getTreeNode(int h, Object k) { + return ((parent != null) ? root() : this).find(h, k, null); + } + + /** + * Tie-breaking utility for ordering insertions when equal + * hashCodes and non-comparable. We don't require a total + * order, just a consistent insertion rule to maintain + * equivalence across rebalancings. Tie-breaking further than + * necessary simplifies testing a bit. + */ + static int tieBreakOrder(Object a, Object b) { + int d; + if (a == null || b == null || + (d = a.getClass().getName(). + compareTo(b.getClass().getName())) == 0) + d = (System.identityHashCode(a) <= System.identityHashCode(b) ? + -1 : 1); + return d; + } + + /** + * Forms tree of the nodes linked from this node. + */ + final void treeify(Node[] tab) { + TreeNode root = null; + for (TreeNode x = this, next; x != null; x = next) { + next = (TreeNode)x.next; + x.left = x.right = null; + if (root == null) { + x.parent = null; + x.red = false; + root = x; + } + else { + K k = x.key; + int h = x.hash; + Class kc = null; + for (TreeNode p = root;;) { + int dir, ph; + K pk = p.key; + if ((ph = p.hash) > h) + dir = -1; + else if (ph < h) + dir = 1; + else if ((kc == null && + (kc = comparableClassFor(k)) == null) || + (dir = compareComparables(kc, k, pk)) == 0) + dir = tieBreakOrder(k, pk); + + TreeNode xp = p; + if ((p = (dir <= 0) ? p.left : p.right) == null) { + x.parent = xp; + if (dir <= 0) + xp.left = x; + else + xp.right = x; + root = balanceInsertion(root, x); + break; + } + } + } + } + moveRootToFront(tab, root); + } + + /** + * Returns a list of non-TreeNodes replacing those linked from + * this node. + */ + final Node untreeify(HashMap map) { + Node hd = null, tl = null; + for (Node q = this; q != null; q = q.next) { + Node p = map.replacementNode(q, null); + if (tl == null) + hd = p; + else + tl.next = p; + tl = p; + } + return hd; + } + + /** + * Tree version of putVal. + */ + final TreeNode putTreeVal(HashMap map, Node[] tab, + int h, K k, V v) { + Class kc = null; + boolean searched = false; + TreeNode root = (parent != null) ? root() : this; + for (TreeNode p = root;;) { + int dir, ph; K pk; + if ((ph = p.hash) > h) + dir = -1; + else if (ph < h) + dir = 1; + else if ((pk = p.key) == k || (k != null && k.equals(pk))) + return p; + else if ((kc == null && + (kc = comparableClassFor(k)) == null) || + (dir = compareComparables(kc, k, pk)) == 0) { + if (!searched) { + TreeNode q, ch; + searched = true; + if (((ch = p.left) != null && + (q = ch.find(h, k, kc)) != null) || + ((ch = p.right) != null && + (q = ch.find(h, k, kc)) != null)) + return q; + } + dir = tieBreakOrder(k, pk); + } + + TreeNode xp = p; + if ((p = (dir <= 0) ? p.left : p.right) == null) { + Node xpn = xp.next; + TreeNode x = map.newTreeNode(h, k, v, xpn); + if (dir <= 0) + xp.left = x; + else + xp.right = x; + xp.next = x; + x.parent = x.prev = xp; + if (xpn != null) + ((TreeNode)xpn).prev = x; + moveRootToFront(tab, balanceInsertion(root, x)); + return null; + } + } + } + + + +## 主要方法 + + +```java +/** + * 返回指定key映射的值,如果不存在此Key 就返回null + */ +public V get(Object key) { + Node e; + return (e = getNode(hash(key), key)) == null ? null : e.value; +} + +``` + +```java +/** + * 在这个map中将键值关联,如果map之前存在此key,老的值会被替代 + */ +public V put(K key, V value) { + // 此方法上面有分析 + return putVal(hash(key), key, value, false, true); +} +``` + + diff --git "a/second/week_01/73/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/second/week_01/73/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" new file mode 100644 index 0000000..6a3c563 --- /dev/null +++ "b/second/week_01/73/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -0,0 +1,324 @@ +# 关于LinkedList的随笔 + + +> 双向链表实现了List接口和Deque,实现了所有的list操作,允许包含空的所有元素。 +> 并且LinkedList可以作为队列或者栈来使用 + + + + + + + +## 主要属性 + +```java +/** +* 元素的个数 +*/ +transient int size = 0; + +/** + * 链表第一个节点 + */ +transient Node first; + +/** + * 链表最后一个节点 + */ +transient Node last; +``` + + + +## 构造方法 + +1. LinkedList() + + ```java + /** + * 构造空的集合 + * Constructs an empty list. + */ + public LinkedList() { + } + ``` + +2. LinkedList(Collection c) + + ```java + /** + * 构造一个list集合包含传入的集合的所有元素,他们的顺序按照 集合c 所iterator的返回顺序 + */ + public LinkedList(Collection c) { + this(); + addAll(c); + } + ``` + + + + + + + +## 方法 + + +1. get + + ```java + /** + * 返回第一个元素 + */ + public E getFirst() { + final Node f = first; + if (f == null) + throw new NoSuchElementException(); + return f.item; + } + + /** + * 返回最后一个元素 + */ + public E getLast() { + final Node l = last; + if (l == null) + throw new NoSuchElementException(); + return l.item; + } + + ``` + +2. delete + + ```java + /** + * 移出并返回第一元素 + */ + public E removeFirst() { + final Node f = first; + if (f == null) + throw new NoSuchElementException(); + return unlinkFirst(f); + } + + /** + * 移出并返回最后一个元素 + */ + public E removeLast() { + final Node l = last; + if (l == null) + throw new NoSuchElementException(); + return unlinkLast(l); + } + ``` + + +3. addAll + + ```java + /** + * 将传入的集合c全部加入到此集合list中,他们的顺序是按照collection c iterator的顺序。 + * 当传入的collection c 在操作在进行中时,被修改了。此操作的表现 undefined + */ + public boolean addAll(Collection c) { + return addAll(size, c); + } + + /** + * 将传入的集合的所有元素加入到此list中(从指定位置开始),将当前位置交换,右边的往后移。 + * 新增的元素会以集合的 iterator的函数顺序 + */ + public boolean addAll(int index, Collection c) { + // 检查索引是否越界 + checkPositionIndex(index); + + Object[] a = c.toArray(); + int numNew = a.length; + if (numNew == 0) + return false; + // pred 要加入的前一个,succ 要插入的元素的位置 + Node pred, succ; + if (index == size) { + succ = null; + pred = last; + } else { + succ = node(index); + pred = succ.prev; + } + // 遍历要加入集合的元素数组 + for (Object o : a) { + // 将元素强转成对应的类型 + @SuppressWarnings("unchecked") E e = (E) o; + Node newNode = new Node<>(pred, e, null); + if (pred == null) + // 前者为空 将此作为链首 + first = newNode; + else + // 否则就将前者的后节点指向他 + pred.next = newNode; + // pred 使用newNode + pred = newNode; + } + + if (succ == null) { + //  插入的位置为空的情况 证明最后一个就是加进去的最后一个即pred + last = pred; + } else { + // 不为空仅需将俩相连 + pred.next = succ; + succ.prev = pred; + } + + size += numNew; + modCount++; + return true; + } + + /** + * 返回在指定索引位置的节点 + */ + Node node(int index) { + // assert isElementIndex(index); + // 在前一半从前往后找 + if (index < (size >> 1)) { + Node x = first; + for (int i = 0; i < index; i++) + x = x.next; + return x; + } else { + // 在后一半从后往前找 + Node x = last; + for (int i = size - 1; i > index; i--) + x = x.prev; + return x; + } + } + ``` + +4. add + + ```java + /** + * 插入具体元素在指定的位置 移动此位置的元素和右边的元素 + */ + public void add(int index, E element) { + checkPositionIndex(index); + + if (index == size) + linkLast(element); + else + linkBefore(element, node(index)); + } + ``` + +5. unlinkFirst, unlinkLast + + ```java + /** + * 移出并返回非空的第一节点f,删除头 + */ + private E unlinkFirst(Node f) { + // assert f == first && f != null; + final E element = f.item; + final Node next = f.next; + f.item = null; + f.next = null; // help GC + first = next; + if (next == null) + // 如果下一个为空 证明这条链就是无元素的 + last = null; + else + // 将头结点 prev至成空 + next.prev = null; + size--; + modCount++; + return element; + } + + /** + * 移出并返回非空的最后一个节点,删除尾 + */ + private E unlinkLast(Node l) { + // assert l == last && l != null; + final E element = l.item; + final Node prev = l.prev; + l.item = null; + l.prev = null; // help GC + last = prev; + if (prev == null) + first = null; + else + prev.next = null; + size--; + modCount++; + return element; + } + ``` + +6. linkFirst, linkLast + + ```java + /** + * 将元素作为头结点连接 + */ + private void linkFirst(E e) { + // 头结点取出作为 新增节点的next节点 + final Node f = first; + final Node newNode = new Node<>(null, e, f); + // 将头重置成新节点 + first = newNode; + if (f == null) + // 如果头结点为空 那么尾节点也是这个新节点 + last = newNode; + else + // f的prev指向现有节点 + f.prev = newNode; + size++; + modCount++; + } + + /** + * 将元素作为尾结点连接. + */ + void linkLast(E e) { + // 找到之前最后一个节点 + final Node l = last; + // 组装出现有节点 + final Node newNode = new Node<>(l, e, null); + last = newNode; + if (l == null) + // 之前的最后一个节点为空 证明这条链无数据 + first = newNode; + else + // 最后一个节点的 + l.next = newNode; + size++; + modCount++; + } + ``` + +7. linkBefore + + ```java + /** + * 将元素e 插入到succ之前 + */ + void linkBefore(E e, Node succ) { + // assert succ != null; + // succ之前的位置 + final Node pred = succ.prev; + // pred -> newNode(e) -> succ + final Node newNode = new Node<>(pred, e, succ); + succ.prev = newNode; + if (pred == null) + // 之前的最后一个节点为空 证明这条链无数据 + first = newNode; + else + pred.next = newNode; + size++; + modCount++; + } + ``` + -- Gitee