使用单向链表实现LinkedList

版权声明:本文为博主原创文章,转载请注明作者与出处,http://blog.csdn.net/lixingtao0520 https://blog.csdn.net/lixingtao0520/article/details/78359586

单向链表是指节点中的指针域只有一个,指针域只能沿着同一个方向移动的链表。Java.util包中提供了LinkedList,此LinkedList是基于双向链表实现的。本文基于单向链表实现LinkedList中的某些方法,主要是学习使用下单向链表这种数据结构。
首先给出节点类,节点类中包含数据域value,和指针域next,以及三个构造函数。

class Entry {
          E value;//数据域
          Entry next;//指针域
          Entry() {}
          Entry (E value){
              this.value = value;
          }
          Entry (E value, Entry next){
              this.value = value;
              this.next = next;
          }

}

为了方便处理链表中的插入,删除和查找操作,在链表的开始结点之前,增加一个head节点,此head节点指向开始结点。这样好处为:

  1. 开始结点的地址存放在了head节点中,这样开始结点的操作和其他节点的操作一样,无需特殊处理。
  2. 不论链表是否为空,其头结点的指针是指向开始节点的非空节点(只不过空链表时,头结点的指针域next为null)。空链表的处理和非空链表一样了。
我们将LinkedList类实现java.util.List<E>接口,尽可能的实现java.util.List<E>中的方法。实现的java.util.List<E>接口方法如下

返回值 方法 说明
boolean add(E e) 将特定元素e添加到List中
void   add(int index, E element) 在索引index处添加给定的元素
boolean addAll(Colleaction<? extends E> c) 将集合c中的元素全部加入List中
boolean addAll(intindex, Collection<?extendsE> c) 在给定位置,添加集合c中的元素
int size() 返回链表中的元素个数
E get(int index) 获取下标为index的元素
boolean isEmpty() List为空时,返回true
boolean remove(Object o) 移除链表中第一个元素值为o的元素。
boolean removeAll(Collection<?> c) 从链表中移除c中所有的元素。
E remove(int index) 删除index处的元素
E set(int index, E element) 将index处的值设置为元素element。
int

indexOf(Object o)

返回元素o在链表中第一次出现的索引位置,未出现返回-1
boolean contains(Object o) 如果List中包含元素o则,返回true;否则false
boolean containsAll(Collection<?> c) List中是否包含集合c中的全部元素,是返回true,否则false
void clear() 清空List中的值
Object[] toArray() 将链表转换为数组,返回Object[]
T[] toArray(T[] a) 将链表转换为类型为T的数组
int lastIndexOf(Object o)  返回链表中value等于o的倒数第一个索引值。
boolean retainAll(Collection<?> c) 从链表中移除所有不在集合c中的元素。
Iterator<E> iterator() 返回链表的迭代子


下面看下LinkedList类的具体实现。

LinkedList类成员域

     LinkedList中除了有包含开始节点的head节点之外,还需要一个整型域count,此属性记录了链表中的节点个数。LinkedList类的成员域如下
//头指针。
private Entry head = new Entry();
//节点个数
private int count = 0;

add(E e)

     向链表中插入节点时,是从开始节点插入:将新增节点指向开始节点,head指向新增节点
public boolean add(E e) {
          //新增节点
          Entry addE = new Entry(e);        
          addE.next = head.next;
          head.next = addE;
          count++;
          return true;
     }

add(int index, E element)

扫描二维码关注公众号,回复: 3414814 查看本文章
     在特定位置,加入某个元素。
     使用变量tmp表示当前处理的节点,变量pre表示当前节点的前趋,用i记录移动的元素个数。当i=index时,将前趋节点指针域指向新节点,新节点的指针域指向当前节点。
/*
      * 特定位置加入某个元素
      */
     @Override
     public void add(int index, E element) {
          if(index < 0 || index >= count) {
              throw new RuntimeException("index越界");
          }
          int i = 0;
          Entry tmp = head.next;
          Entry pre = head;
          while(i != index) {
              tmp = tmp.next;
              pre = pre.next;
              i++;
          }
          Entry add = new Entry(element);
          pre.next = add;
          add.next = tmp;
          count++;
     }

addAll(Collection<?extendsE> c)

    将集合c中的所有元素添加到链表中。利用集合c的迭代子循环增加元素
public boolean addAll(Collection<? extends E> c) {
          Iterator<? extends E> it = c.iterator();
          while(it.hasNext()) {
              add(it.next());
          }
          return true;

addAll(intindex, Collection<?extendsE> c)

  在特定位置,向链表中添加集合c中的元素 .
   分两种情况:1、index<count,记录下前趋节点,将c中的元素追加到前趋节点的末尾,将追加的最后一个元素的指针域指向原index处的节点
    2、index=count,即在末尾节点添加集合c中的元素。循环将c中的元素追加到末尾节点
public boolean addAll(int index, Collection<? extends E> c) {
          if(index < 0 || index > count) {
              throw new RuntimeException("index越界");
          }
          /*
           * 如果index等于count大小,需要单独处理
           */
          if(index == count) {
              Entry tmp = head;
              while(null != tmp.next) {
                   tmp = tmp.next;
              }
              //循环将c中的元素追加到末尾
              Iterator<? extends E> it = c.iterator();
              while(it.hasNext()) {
                   Entry add = new Entry(it.next());
                   tmp.next = add;
                   tmp = tmp.next;
                   count++;
              }
              return true;
          }
          /*
           * 如果index < count,则按以下逻辑处理。
           * 记录下前趋节点,移动到index处时,将c中的元素追加到前趋节点末尾
           */
          int i = 0;
          Entry tmp = head.next;
          Entry pre = head;
          while(i != index) {
              tmp = tmp.next;
              pre = pre.next;
              i++;
          }
          //循环将c中的元素追加到pre的末尾
          Iterator<? extends E> it = c.iterator();
          while(it.hasNext()) {
              Entry add = new Entry(it.next());
              pre.next = add;
              pre = pre.next;
              count++;
          }
          //将pre的指针域指向原index处的节点tmp
          pre.next = tmp;
          return true;
     }

size()

    返回链表中的元素个数    
public int size() {
          return count;
 }

get(int index)

获取下标为index的元素。
    1 通过head指针,循环去访问后继元素
    2 因为插入时,是从开始结点插入的。获取时,后插入的先获取(栈)
/*
* 获取下标为index的元素
*/
public E get(int index) {
          if(index < 0 || index >= size()){
              throw new RuntimeException("IndexOutOfBounds");
          }
          //获取头指针
          Entry headTemp = head;
          //开始节点
          Entry target = headTemp.next;
          int i = 0;
          while(i != index) {
              target = target.next;
              i++;
          }
          return target.value;
     }

isEmpty() 

    空链表判断
public boolean isEmpty() {
          return size() == 0;
     }

remove(Object o)

    移除链表中第一个元素值为o的元素。
    记下当前节点的前趋节点,循环判断,如果移除的o与value相同,则将当前前趋节点的next指向
当前节点的next.
public boolean remove(Object o) {
          Entry tmp = head.next;
          if(null == tmp || null == o) {
              return false;
          }
          //tmp的前趋节点
          Entry pre = head;
          while(null != tmp) {
              Object v = tmp.value;
              if(o.equals(v)) {
                   pre.next = tmp.next;
                   count--;
                   return true;
              }
              pre = tmp;
              tmp = tmp.next;
          }
          return false;
     }

remove(intindex)

   删除index处的元素
public E remove(int index) {
          if(index < 0 || index >= count) {
              throw new RuntimeException("index越界");
          }
          //开始节点
          Entry tmp = head.next;
          int i = 0;
          while(i != index) {
              tmp = tmp.next;
              i++;
          }
          return tmp.value;
     }

removeAll(Collection<?> c)

    从链表中移除c中所有的元素。
    利用集合c的迭代子,循环移除
public boolean removeAll(Collection<?> c) {
          Iterator<?> it =  c.iterator();
          while(it.hasNext()) {
              boolean re = remove(it.next());
              if(re != true) {
                   return false;
              }
          }
          return true;
     }

set(int index, E element)

     将index处的值设置为元素element。
public E set(int index, E element) {
          if(index < 0 || index >= size()){
              throw new RuntimeException("IndexOutOfBounds");
          }
          //获取头指针
          Entry headTemp = head;
          //开始节点
          Entry target = headTemp.next;
          int i = 0;
          while(i != index) {
              target = target.next;
              i++;
          }
          E oldValue = target.value;
          target.value = element;
          return oldValue;
     }

indexOf(Object o)

    获取某个值的索引。
    元素o为null和不为null时分开处理。
public int indexOf(Object o) {
          Entry tmp = head.next;
          int index = 0;
          if(o == null) {//o为null
              while(tmp != null && tmp.value != null) {
                   tmp = tmp.next;
                   index++;
              }
          } else {//o不为null
              while(tmp != null && !o.equals(tmp.value)) {
                   tmp = tmp.next;
                   index++;
              }
          }
          
          if(null == tmp) {
              return -1;
          } else {
              return index;
          }
     }

contains(Object o)和containsAll(Collection<?> c)

     链表中是否包含某个元素

public boolean contains(Object o) {
          return indexOf(o) != -1;
     }

   链表中是否包含集合c中的所有元素

public boolean containsAll(Collection<?> c) {
          Iterator<?> it =  c.iterator();
          while(it.hasNext()) {
              boolean re = contains(it.next());
              if(re != true) {
                   return false;
              }
          }
          return true;
     }

clear()

        清空链表。只是让头节点指向了null。内存中真正的节点,并为消失
public void clear() {
          head.next = null;
          count = 0;
     }

toArray()和toArray(T[] a)

     将链表转换为数组
public Object[] toArray() {
          Object[] arr = new Object[count];
          Entry tmp = head.next;
          int i = 0;
          while(null != tmp) {
              arr[i] = tmp.value;
              tmp = tmp.next;
          }
          return arr;
     }

将链表转换为类型为T的数组,如果给定的a长度不够,则将重新实例化一个T数组。
public <T> T[] toArray(T[] a) {
          //如果a的长度不够,则重新实例化一个数组
          if (a.length < count)
            a = (T[])java.lang.reflect.Array.newInstance(
                                a.getClass().getComponentType(), count);
          Object[] re = a;
          Entry tmp = head.next;
          int i = 0;
          while(null != tmp) {
              re[i] = tmp.value;
              i++;
              tmp = tmp.next;
          }
          //多出部分填充为null
          if(a.length > count) {
              a[count] = null;
          }
          return a;
     }

lastIndexOf(Object o)

    返回链表中value等于o的倒数第一个索引值。
    逻辑:将链表向后移动判断每个value值,并使用一个变量lastIndex存储value与o最后一次相等的索引地址,当链表移动到末尾时,如果lastIndex值为-1,说明链表中不存在value为o的节点, 否则,返回lastIndex的值。o为null时和不为null时,分开处理
public int lastIndexOf(Object o) {
          Entry tmp = head.next;
          int index = 0;
          int lastIndex = -1;
          if(o == null) {
              while(tmp != null) {
                   if(tmp.value != null) {
                        tmp = tmp.next;
                        index++;
                   } else {
                        lastIndex = index;
                        tmp = tmp.next;
                        index++;
                   }
              }
          } else {
              while(tmp != null) {
                   if(!o.equals(tmp.value)) {//如果元素o与value不相等,则继续向后移动。
                        tmp = tmp.next;
                        index++;
                   } else {//如果元素o与value相等,则记录下此处的索引,继续向后移动,寻找是否还有值与o相等。
                        lastIndex = index;
                        tmp = tmp.next;
                        index++;
                   }
              }
          }
          
          if(-1 == lastIndex) {
              return -1;
          } else {
              return lastIndex;
          }
     }

retainAll(Collection<?> c)

    从链表中移除所有不在集合c中的元素。
public boolean retainAll(Collection<?> c) {
          Entry tmp = head.next;
          Entry pre = head;//tmp的前趋节点,移除时使用
          while(null != tmp) {
              E value = tmp.value;
              if(!c.contains(value)) {//如果c中不包含value,则移除对应的节点,并将tmp指向tmp.next,pre指针不动。
                   pre.next = tmp.next;
                   count--;      
                   tmp = tmp.next;
                   continue;
              }
              //如果c中包含value,则将tmp指向tmp.next,pre指向tmp。
              pre = tmp;
              tmp = tmp.next;
          }
          return true;
     }

iterator()

    获取链表的迭代子
public Iterator<E> iterator() {
          class Itr implements Iterator<E> {
              //迭代类中,所处理元素的当前索引位置。起始为-1
              private int cur = -1;
              
              @Override
              public boolean hasNext() {
                   return cur + 1 < size();
              }
              //获取迭代类中当前索引的元素
              @Override
              public E next() {
                   cur++;
                   E tmp = get(cur);
                   return tmp;
              }
              @Override
              public void remove() {
                   //必须调用过next()方法
                   if(cur < 0) {
                        throw new RuntimeException("cur<0");
                   }
                   
                   //移除cur处的元素
                   Entry tmp = head.next;
                   Entry pre = head;
                   int i = 0;
                   while(cur != i && tmp != null) {//cur与i不相等且没有移动到末尾
                        tmp = tmp.next;
                        pre = pre.next;
                        i++;
                   }
                   //当移动到当前处理的节点cur时,进行移除处理
                   if(cur == i) {
                        if(tmp != null) {
                            //移除的为非末尾节点
                             pre.next = tmp.next;
                             count--;
                             cur--;//迭代子处理的元素位置减1
                             return;
                        } else {
                            //移除的为末尾节点
                             pre.next = null;
                             count--;
                             cur--;//迭代子处理的元素位置减1
                             return;
                        }
                   } else {
                        throw new RuntimeException("找不到remove的元素");
                   }
              }
              
          }
          return new Itr();
     }    	


猜你喜欢

转载自blog.csdn.net/lixingtao0520/article/details/78359586