transient int size = 0;
transient Node<E> first; //指向头结点
transient Node<E> last; //指向尾节点
两个构造函数:
public LinkedList() {}
//将c集合中的元素都放进list中
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
方法:
//设置头结点;private 用户不能调用;实现过程,先Node<E> f = first;因为等下first要指向新的节点,然后Node<E> newNode = new Node<>(null,e,f); null位置表示newNode的prev指向,e表示该节点的元素,f表示next的指向;然后将fisrt指向newNode;判断原来的头结点f是否为空,为空的话last也指向newNode,否则将f的prev指向newNode.最后size和modCount自增。
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
//设置尾节点,没有权限修饰符,用户可以调用(以后没特别写明都说明可调用);实现方法和设置头结点类似,以下默写一遍;
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++;
}
//在某个非空节点的前面插入新节点;参数有两个,要插入的元素和被插入的节点;先要声明一个节点指向该节点的prev,然后声明一个新节点,还要考虑原来的节点是不是头结点,是的话要要first指向新节点;
void linkBefore(E e,Node<E> succ){
final Node<E> pred = succ.prev;
final Node<E> newNode = Node<>(pred, e, succ);
succ.prev = newNode;
if(pred == null) first = newNode;
else pred.next = newNode;
size++;
modCount++;
}
//移除非空首节点,private修饰,用户不能调用,removeFirst()调用;返回被移除节点的元素值;将头结点的元素值和next都设为null;
private E unlinkFirst(Node<E> f){
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null;
if(next == null) last == null;
else next.prev = null;
size--;
modCount++;
return element;
}
//移除尾节点,private修饰,返回元素值;
private E unlinkLast(Node<E> l){
final element = l.item;
final prev = l.prev;
l.item == null;
l.prev == null;
if(prev == null) first = null;
else prev.next = null;
size--;
modCount++;
return element;
}
//移除某个节点;返回元素值;要判断该节点是否是头结点或者尾节点
E unlink(Node<E> x){
final Node<E> prev = x.prev;
final Node<E> next = x.next;
final E element = x.item;
x.item = null;
if(prev == null) first = next;
else {
pre.next = next;
x.prev = null;//默写的时候忘了
}
if(next == null) last = prev;
else {
next.prev = prev;
x.next = null;
}
size--;
modCount++;
return element;
}
//返回首节点的元素值,在首节点为null时要抛出异常,抛出异常的代码就不写了;
public E getFirst(){
final Node<E> f = First;
return f.item;
}
//返回尾节点,同上
public E getLast(){
final Node<E> l = Last;
return l.item;
}
//移除首节点和尾,调用unlinkFirst和unlinkLast,首节点和尾节点为空时报错,疑问为什么不直接把unlinkFirst设为public用来调用
public E removeFirst(){
final Node<E> f = First;
return unlinkFirst(f);
}
public E removeLast(){
//省略
}
//增加首尾节点,调用linkFirst(E e)和linkLast(E e)
public void addFirst(E e){ linkFirst(e);}
public void addLast(E e){ linkLast(e);}
// 是否包含某元素
public boolean contains(Object o){return indexOf(o) != -1;}
//返回元素个数
public int size(){return size;}
//add方法同addLast作用一样,但返回值是boolean类型,由于LinkedList实现了Collection接口,所以需要这个
public boolean add(E e){
linkLast(e);
return true;
}
//移除list中该元素首次出现的位置,如果没有该元素,则没有改变
public boolean remove(Object o){
if(o == null){
for(Node<E> x = first; x != null; x = x.next){
if(x.item == null) {
unlink(x);
return true;
}
}
} else{
for(Node<E> x = first; x != null; x = x.next){
if(o.equals(x.item)){
unlink(x);
return true;
}
}
}
return false;
}
//把集合中的所有元素加入到队列队尾,调用addAll( int index, Collection< ? extends E> c);
public boolean addAll(Collection< ? extends E> c){
return addAll(size, Collection<? extends E> c);
}
//把集合总的元素插入到指定位置,要检查index是否超出范围; 新建一个数组a = c.toArray; 如果数组长度为0,则返回false; 然后新建两个Node来放当前index的节点succ,以及前一个节点pred;如果index是size,那么当前节点succ就是null,pred就是pred,否则succ是node(index),pred = succ.prev;
public boolean addAll(int index, Collection< ? extends E> c){
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = c.length;
if(numNew == 0) return false;
Node<E> succ, pred;
if(index == size){
succ = null;
pred = last;
}else {
succ = node(index);
pred = succ.prev;
}
//遍历a数组,赋值给o;先把a里面的元素都接到pred后面,最后succ的prev指向pred,pred的next指向succ;
for(Object o : a){
E e = (E) o; // 类型转换
Node<E> newNode = new Node<>(pred, e, null);
if(pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if(succ == null)
last = pred;
else{
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
//将某个元素添加到指定位置,检查index是否超限,当index = size时,调用linkLast(e),else 调用 linkBefore(e);
public void add(int index, E element){
checkPositionIndex(index);
if(index == size)
return linkLast(element);
else
return linkBefore( element, node(index));
}
//移除指定位置的节点。检查index是否超限,调用unlink(Node)
public E remove(int index){
checkElementIndex(index); //这个和chekPositionIndex的区别是它不包括index==size的情况,它是检查该位置是否有元素,通常在移除的时候用来检查,而后者通常在添加的时候用来检查。
return unlink(node(index));
}
//下面是一些检查是否超限的方法
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//返回指定节点,通过编号找节点的时候用二分法,index超过一半就从尾巴开始往前找,小于一半就从头开始找
Node<E> node(int 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;
}
}
//返回某个元素最早出现的位置, 下一个是返回最后出现的位置lastIndexOf, 只需要遍历的时候反过来遍历就行。
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( x.item = o )
return index;
index++;
}
}
return -1;
}
//队列操作
//两个得到首节点元素的操作,区别是element()会在首节点为空的时候报错,因为它调用getfirst()
,而 peek()会返回null
public E peek(){ //同peekFirst(), peekLast()只需把f = last就行
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E element(){
return getfirst();
}
//得到并移除首节点
public E poll(){ //同pollFirst(), pollLast()只需把f = last就行
final Node<E> f = first;
return (f == null) ? null:unlinkFisrt(f);
}
publuc E remove(){ //同pop()
return removeFirst();
}
//在队尾加上元素
public boolean offer(E e){
return add(e);
}
//在队首(尾)插入元素
public boolean offerFirst(E e){
addFirst(e);
return true;
}
public boolean offerLast(E e){
addLast(e);
return true;
}
//往队首加一个元素
public void push(E e){
addFirst(e);
}
//移除该元素第一次出现的节点,同move(Object o)
,removeLastOccurence(Object o)
从Node<E> x = last
开始往回遍历就行
public boolean removeFirstOccurence(Object o){
return move(0)
}