前言

主要是模拟Java中的LinkList的实现。

LinkedList概述

LinkedList是一种双向链表。

根据双向链表的特点,会有头节点和尾节点,并且节点之间是通过前驱指针和后继指针来维护关系的,而不是像数组那样通过位置下标来维护节点间关系的。所以既可以从头到尾遍历,又可以从尾到头遍历。

双向链表是包含两个指针的,pre指向前一个节点,next指向后一个节点,但是第一个节点head的pre指向null,最后一个节点的tail的next指向null。

LinkedList是一个继承于AbstractSequentialList,并实现了List接口和Deque接口的双端链表。

LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性(addFirst(),removeLast()…),它可以被当作堆栈、队列或双端队列进行操作。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。

1
2
3
4
5
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
...
}

LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法。

和ArrayList一样,类中的iterator()方法和listIterator()方法返回的iterators迭代器是fail-fast的:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件,底层由modCount实现。

AbstractSequentialList 实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些骨干性函数。降低了List接口的复杂度。这些接口都是随机访问List的,LinkedList是双向链表(链表数据结构本身不具备随机访问的特性);既然它继承于AbstractSequentialList,就相当于已经实现了“get(int index)这些接口”。

此外,我们若需要通过AbstractSequentialList自己实现一个列表,只需要扩展此类,并提供 listIterator() 和 size() 方法的实现即可。若要实现不可修改的列表,则需要实现列表迭代器的 hasNext、next、hasPrevious、previous 和 index 方法即可。

模拟LinkedList

Queue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* @ClassName Queue
* @Description 队列
* @Author HuangCanCan
* @Date 2019/10/10 17:46
* @Version 1.0
**/
public interface Queue {

/**
* 将指定的元素值e插入此列表末尾
*
* @param e
* @return
*/
boolean offer(Object e);

/**
* 获取并移除此队列的头,如果此队列为空,则抛出NoSuchElementException异
*
* @return
*/
Object remove();

/**
* 获取并移除此队列的头,如果此队列为空,则返回 null
*
* @return
*/
Object poll();

/**
* 获取但不移除此队列的头;如果此队列为空,则抛出NoSuchElementException异常
*
* @return
*/
Object element();

/**
* 获取但不移除此队列的头;如果此队列为空,则返回 null
*
* @return
*/
Object peek();
}

Deque

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* @ClassName Deque
* @Description 双端队列
* @Author HuangCanCan
* @Date 2019/10/10 18:23
* @Version 1.0
**/
public interface Deque extends Queue {
/**
* 将指定的元素插入此双端队列的开头
*
* @param e
* @return
*/
boolean offerFirst(Object e);

/**
* 将指定的元素插入此双端队列的末尾
*
* @param e
* @return
*/
boolean offerLast(Object e);

/**
* 获取,但不移除此双端队列的第一个元素;如果此双端队列为空,则返回 null
*
* @return
*/
Object peekFirst();

/**
* 获取,但不移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null
*
* @return
*/
Object peekLast();

/**
* 获取并移除此双端队列的第一个元素;如果此双端队列为空,则返回 null
*
* @return
*/
Object pollFirst();

/**
* 获取并移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null
*
* @return
*/
Object pollLast();

/**
* 将一个元素推入此双端队列所表示的堆栈(换句话说,此双端队列的头部)
*
* @param e
*/
void push(Object e);

/**
* 从此双端队列所表示的堆栈中弹出一个元素(换句话说,移除并返回此双端队列的头部)
*/
Object pop();

/**
* 从此双端队列移除第一次出现的指定元素,如果列表中不包含次元素,则没有任何改变
*
* @param e
* @return
*/
boolean removeFirstOccurrence(Object e);

/**
* 从此双端队列移除最后一次出现的指定元素,如果列表中不包含次元素,则没有任何改变
*
* @param e
* @return
*/
boolean removeLastOccurrence(Object e);
}

LinkedList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* @ClassName LinkedList
* @Description 模拟LinkedList
* @Author HuangCanCan
* @Date 2019/10/8 17:18
* @Version 1.0
**/
public class LinkedList implements List, Iterable, Deque {

/**
* 指向头结点,
* <p>
* 不变的: (first == null && last == null) || (first.prev == null && first.data != null)
*/
private Node first;

/**
* 指向尾结点
* <p>
* 不变的: (first == null && last == null) || (last.next == null && last.data != null)
*/
private Node last;

/**
* 结点个数
*/
private int size;

/**
* 修改此列表的次数
* <p>
* 用于在迭代器遍历时,用于判断在迭代过程中是否发生了修改操作,如果发生了修改,则抛出ConcurrentModificationException异常
*/
private int modCount;

public LinkedList() {
}

public LinkedList(Collection c) {
this();
addAll(c);
}

@Override
public int size() {
return size;
}

@Override
public Object get(int index) {
//检查index范围
checkElementIndex(index);

return getNode(index).data;
}

/**
* 判断元素的索引是否越界
*
* @param index
*/
private void checkElementIndex(int index) {
if (index < 0 || index > size) {
throw new RuntimeException("指针越界异常:" + index);
}
}

@Override
public boolean isEmpty() {
return size == 0;
}

@Override
public boolean contains(Object e) {
// 判断列表中是否包含有元素值e,返回true当列表中至少存在一个元素值e
return indexOf(e) >= 0;
}

/**
* 正向查找,返回LinkedList中元素值Object data <strong>第一次</strong> 出现的位置,如果元素不存在,则返回-1
*
* @param data
* @return
*/
@Override
public int indexOf(Object data) {
//返回第一次出现的指定元素的索引
int index = 0;
if (data == null) {
for (Node x = first; x != null; x = x.next) {
if (x.data == null) {
return index;
}
index++;
}
} else {
for (Node x = first; x != null; x = x.next) {
if (data.equals(x.data)) {
return index;
}
index++;
}
}
return -1;
}

/**
* 逆向查找,返回LinkedList中元素值Object e <strong>最后一次</strong>出现的位置,如果元素不存在,则返回-1
*
* @param e
* @return
*/
public int lastIndexOf(Object e) {
int index = size;
if (e == null) {
for (Node x = last; x != null; x = x.pre) {
index--;
if (x.data == null) {
return index;
}
}
} else {
for (Node x = last; x != null; x = x.pre) {
index--;
if (e.equals(x.data)) {
return index;
}
}
}
return -1;
}

@Override
public void add(int index, Object data) {
//检查index范围
checkElementIndex(index);

/*
判断此索引是否等于节点的个数,如果相等那就在尾部插入元素,否则在中间插入元素
*/
if (index == size) {
//尾插入
linkLast(data);
} else {
//中间插入
//获取指定索引位置的节点
Node node = getNode(index);
//在指定索引位置的节点前插入新节点
linkBefore(data, node);
}

}

/**
* 在非空节点node之前插入新节点的值。中间操作
*
* @param data 新节点的值
* @param node 当前节点
*/
private void linkBefore(Object data, Node node) {
Node pred = node.pre;
// 构建一个新的节点
Node newNode = new Node(pred, data, node);
//设置node的前驱节点为这个新的节点
node.pre = newNode;
// 第一个节点head的pre指向null,最后一个节点的tail的next指向null
//判断node是否是首节点(node.pre前驱节点为null)
if (pred == null) {
//表示node是首节点
//将newNode设置为首节点
first = newNode;
} else {
//node不是首节点,设置node的前驱节点的后续节点设置为新的节点
pred.next = newNode;
}
//节点个数加 1
size++;
//修改此列表的次数加 1
modCount++;
}

/**
* 将新节点的值添加到链表尾部。尾插入
*
* @param data
*/
private void linkLast(Object data) {
Node l = last;
//构建一个新的节点
Node newNode = new Node(l, data, null);
//将新节点作为尾节点
last = newNode;
//如果原尾节点为null,即原链表为null,则链表首节点设置为newNode
if (l == null) {
first = newNode;
} else {
//否则,原尾节点的next设置为newNode
l.next = newNode;
}
//节点个数加 1
size++;
//修改此列表的次数加 1
modCount++;
}

/**
* 在链表头部添加元素,头插入
*
* @param data
*/
private void linkFirst(Object data) {
Node f = first;
// 构建一个新节点
Node newNode = new Node(null, data, f);
//将新节点作为首节点
first = newNode;

//如果原首节点为null,即原链表为null,则链表尾节点也设置为newNode
if (f == null) {
last = newNode;
} else {
//否则,原首节点的pre设置为newNode
f.pre = newNode;
}
//节点个数加 1
size++;
//修改此列表的次数加 1
modCount++;
}


/**
* 返回指定索引位置的节点
*
* @return
*/
private Node getNode(int index) {
/*
* *************【折半思想】**************
* 当index < size/2 (size >> 1)时,从列表首节点向后查找
* 当 index >= size/2时,从列表尾节点向前查找
*/
if (index < size / 2) {
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.pre;
}
return x;
}

}

@Override
public void add(Object data) {
linkLast(data);
}

/**
* 按照指定collection的迭代器所返回的元素顺序,将该collection中的所有元素添加到此链表的尾部。尾部插入
* <p>
* 如果指定的集合添加到链表的尾部的过程中,集合被修改,则该插入过程的后果是不确定的。
* 一般这种情况发生在指定的集合为该链表的一部分,且其非空。
*
* @param c
*/
public boolean addAll(Collection c) {
return addAll(size, c);
}

/**
* 从指定的位置开始,将指定collection中的所有元素插入到此链表中,新元素的顺序为指定collection的迭代器所返回的元素顺序
*
* @param index
* @param c
*/
public boolean addAll(int index, Collection c) {
//检查index范围
checkElementIndex(index);

Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0) {
return false;
}

Node pred, //指向需要插入节点的位置的前驱节点
succ;//需要插入节点的位置
if (index == size) {
// 在链表表尾部插入集合元素
succ = null;
pred = last;

} else {
// 在中间插入
// 获取指定索引位置的节点
succ = getNode(index);
pred = succ.pre;
}

//指定collection中的所有元素依次插入到此链表中指定位置的过程
for (Object data : a) {
// 构建新节点
Node newNode = new Node(pred, data, null);
if (pred == null) { // 如果原链表为null,则新插入的节点作为链表首节点
first = newNode;
} else {
pred.next = newNode;
}
pred = newNode; // pred指针向后移动,指向下一个需插入节点位置的前一个节点
}

//集合元素插入完成后,与原链表index位置后面的子链表链接起来
if (succ == null) { //说明之前是在列表尾部插入的集合元素
last = pred; //pred指向的是最后插入的那个节点
} else {
// 否则,是在中间插入的集合元素
pred.next = succ;
succ.pre = pred;
}

size += numNew;
modCount++;
return true;

}

/**
* 在链表头部添加元素,头插入
*
* @param data
*/
public void addFirst(Object data) {
linkFirst(data);
}

/**
* 在链表尾部添加元素,等价于add
*
* @param data
*/
public void addLast(Object data) {
linkLast(data);
}

@Override
public boolean addBefore(Object obj, Object e) {
int index = indexOf(obj);
if (index < 0) {
return false;
}
add(index, e);
return true;
}

@Override
public boolean addAfter(Object obj, Object e) {
int index = indexOf(obj);
if (index < 0) {
return false;
}
add(index + 1, e);
return true;
}

@Override
public Object remove(int index) {
checkElementIndex(index);

Node oldNode = getNode(index); // 获取指定索引处的节点,老节点
return unlink(oldNode);
}

/**
* 删除非空节点node
*
* @param node 要删除的节点
* @return
*/
private Object unlink(Node node) {
Object oldValue = node.data;
Node prev = node.pre; //老节点的前驱节点
Node next = node.next; // 老节点的后续节点

// 更改老节点的前驱节点和后续节点的的关联
// prev.next = next;
// next.pre = prev;

/*
需要判断删除的元素是否是头节点和尾节点
*/
if (prev == null) { //代表该节点是头节点
first = next;
} else { // 不是头结点
prev.next = next;
node.pre = null;
}

if (next == null) { //代表该节点是尾节点
last = prev;
} else { // 不是尾结点
next.pre = prev;
node.next = null;
}

node.data = null; // 使GC能够快速回收

size--;
modCount++;

return oldValue;
}

@Override
public boolean remove(Object e) {
//移除列表中首次出现的指定元素(如果存在),LinkedList中允许存放重复的元素
/*
* 第一种:
*/
// int index = indexOf(e);//返回元素e第一次出现的索引
// if (index < 0) {
// return false;
// }
// remove(index);
// return true;

if (e == null) {
for (Node x = first; x != null; x = x.next) {
if (x.data == null) {
unlink(x);
return true;
}
}
} else {
for (Node x = first; x != null; x = x.next) {
if (e.equals(x.data)) {
unlink(x);
return true;
}
}
}
return false;
}

/**
* 替换指定索引位置节点的元素值,并返回旧值
*
* @param index 索引
* @param element 元素的值
* @return
*/
private Object set(int index, Object element) {
checkElementIndex(index);
Node node = getNode(index);
Object oldValue = node.data;
node.data = element;
return oldValue;
}

@Override
public Object replace(int index, Object e) {
return set(index, e);
}

@Override
public String toString() {
if (size == 0) {
return "[]";
}
StringBuilder builder = new StringBuilder("[");
Node p = first;
for (int i = 0; i < size; i++) {
if (i != size - 1) {
builder.append(p.data + ",");
} else {
builder.append(p.data);
}

//移动指针到下一个结点
p = p.next;
}

builder.append("]");
return builder.toString();
}

@Override
public Iterator iterator() {

return new LinkedListIteraor();
}

/**
* 获取列表首节点元素值
*/
public Object getFirst() {
Node head = first;
if (head == null) {
throw new NoSuchElementException();
}
return head.data;
}

/**
* 获取列表尾节点元素值
*/
public Object getLast() {
Node tail = last;
if (tail == null) {
throw new NoSuchElementException();
}
return tail.data;
}

/**
* 移除首节点,并返回该节点的元素值
*
* @return
*/
public Object removeFirst() {
final Node f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}

/**
* 移除尾节点,并返回该节点的元素值
*
* @return
*/
public Object removeLast() {
final Node l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}

/**
* 删除非空的首节点f
*/
private Object unlinkFirst(Node f) {
Object element = f.data;
Node next = f.next;
f.data = null;
f.next = null; // help GC
first = next; //将原首节点的next节点设置为首节点
if (next == null) //如果原链表只有一个节点,即原首节点,删除后,链表为null
last = null;
else
next.pre = null;
size--;
modCount++;
return element;
}

//删除非空的尾节点l
private Object unlinkLast(Node l) {
// assert l == last && l != null;
final Object element = l.data;
final Node prev = l.pre;
l.data = null;
l.pre = null; // help GC
last = prev; //将原尾节点的prev节点设置为尾节点
if (prev == null) //如果原链表只有一个节点,则删除后,链表为null
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}

@Override
public boolean offer(Object e) {
// 将指定的元素值e插入此列表末尾
add(e);
return true;
}

@Override
public Object remove() {
//获取并 移除 此队列的头,如果此队列为空,则抛出NoSuchElementException异
return removeFirst();
}

@Override
public Object poll() {
//获取并 移除 此队列的头,如果此队列为空,则返回 null
Node f = first;
return f == null ? null : unlinkFirst(f);
}

@Override
public Object element() {
//获取但 不移除 此队列的头;如果此队列为空,则抛出NoSuchElementException异常
return getFirst();
}

@Override
public Object peek() {
//获取但 不移除 此队列的头;如果此队列为空,则返回 null
Node f = first;
return f == null ? null : f.data;
}

@Override
public boolean offerFirst(Object e) {
addFirst(e);
return true;
}

@Override
public boolean offerLast(Object e) {
addLast(e);
return true;
}

@Override
public Object peekFirst() {
final Node f = first;
return (f == null) ? null : f.data;
}

@Override
public Object peekLast() {
final Node l = last;
return (l == null) ? null : l.data;
}

@Override
public Object pollFirst() {
final Node f = first;
return (f == null) ? null : unlinkFirst(f);
}

@Override
public Object pollLast() {
final Node l = last;
return (l == null) ? null : unlinkLast(l);
}

@Override
public void push(Object e) {
addFirst(e);
}

@Override
public Object pop() {
return removeFirst();
}

@Override
public boolean removeFirstOccurrence(Object e) {
return remove(e);
}

@Override
public boolean removeLastOccurrence(Object e) {
if (e == null) {
for (Node x = last; x != null; x = x.pre) { //逆向向前
if (x.data == null) {
unlink(x);
return true;
}
}
} else {
for (Node x = last; x != null; x = x.pre) {
if (e.equals(x.data)) {
unlink(x);
return true;
}
}
}
return false;
}

public static class Node {
/**
* 要存储的数据
*/
Object data;
/**
* 后续结点
*/
Node next;
/**
* 前驱结点
*/
Node pre;

public Node(Node pre, Object data, Node next) {
this.pre = pre;
this.data = data;
this.next = next;
}
}

private class LinkedListIteraor implements Iterator {

/**
* 起始位置的后续节点
*/
private Node current = first.next;
/**
* 记录此刻集合修改的总次数,之后会拿modCount再和此值作比较,如果不相等,说明在迭代过程中,集合发生了修改操作,则会抛出ConcurrentModification异常
*/
private int expectedModCount = modCount;

/**
* 判断是否可以向后移动指针
*/
private boolean canMove = false;

@Override
public boolean hasNext() {
//后续节点与尾节点比较,如果不相等证明还有元素没有迭代完
return current != last;
}

@Override
public Object next() {
if (expectedModCount != modCount) {
throw new java.util.ConcurrentModificationException();
}
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
Object nextVal = current.data;
current = current.next;
canMove = true;
return nextVal;
}

@Override
public void remove() {
if (expectedModCount != modCount) {
throw new java.util.ConcurrentModificationException();
}
if (!canMove) {
throw new IllegalStateException();
}

LinkedList.this.unlink(current.pre);

canMove = false;
expectedModCount++;
}

}
}




遍历集合时进行修改或删除操作为什么会抛出ConcurrentModificationException?

如一下代码:以上面的代码为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(4);
linkedList.add(5);
linkedList.add(6);
for (Object i : linkedList) {
if ((Integer) i == 2) {
linkedList.remove(2);
}
}

输出:Exception in thread "main" java.util.ConcurrentModificationException

原因:

因为增强的for循环内部使用的是iterator迭代器的方式进行遍历的,在遍历过程中,如果进行修改操作会导致exceptedModCount的值和modCount的值不相等.因此会抛出ConcurrentModificationException的异常。

正确的删除元素的方式应该是使用iterator()的方式遍历并进行删除操作,因为迭代器中的remove()方法和集合中的remove()有一点不同就是,前者删除后,会进行exceptedModCount++,因为不会抛出上面那个异常。

下面的代码不会抛出ConcurrentModificationException:

1
2
3
4
5
6
7
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Integer next = (Integer) iterator.next();
if (next == 2) {
iterator.remove();
}
}

总结

LinkedList是基于双向链表实现的,适合增删多查找少的场景。

LinkedList添加的元素,取时与添加时的顺序一致。因为向双向链表的尾部添加元素,然后按照头节点顺序遍历获取,所以一致。

LinkedList允许添加重复元素。

LinkedList不是线程安全的集合。

LinkedList允许添加null元素。

add方法插入元素是在双向链表的尾部插入。

get方法遍历双向链表,先判断下标靠近头节点还是尾节点,这样会减少多余的循环。

折半思想:当index < size/2 (size >> 1)时,从列表首节点向后查找;当 index >= size/2时,从列表尾节点向前查找