JAVA LinkedList 数据结构学习

 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)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值