`
yuyiming1986
  • 浏览: 62223 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

LinkedList源码分析

阅读更多

 

LinkedList源码分析

 

 

LinkedList是动态数组的另一种实现,底层以双向循环链表为实现基础,它的优势在于可以快速的删除和添加元素,不需要像ArrayList那样移动大量的元素,但对于查找元素需要逐个遍历链表中的元素,进行匹配。所以LinkedList适用于频繁删除和添加元素,较少查找元素的应用场景。

 

 

LinkedList内部使用Entry<E>来封装双向循环链表结点.LinkedList头结点的定义:

        private transient Entry<E> header = new Entry<E>(null, null, null);

 

Entry是一个静态内部类,用于描述双向链表的结点

//有三个域:element对象引用或者基本类型的值,也就是结点的data域
//         next域指向节点的后继
//         previous指向结点的前驱
private static class Entry<E> {
    
	E element;
	Entry<E> next;
	Entry<E> previous;

	Entry(E element, Entry<E> next, Entry<E> previous) {
	    this.element = element;
	    this.next = next;
	    this.previous = previous;
	}
 }
 

1.LinkedList构造函数

 

    //LinkedList采用的内部数据结构是双向循环链表,结点使用Entry描述.

 //初始化时,将结点的前驱和后续都指向自己(header).形成了循环。
 public LinkedList() {
       header.next = header.previous = header;
 }

 

2.访问方法-getFirst(),GetLast(),get(int index)

 

   getFirst()方法

 

 

 //取得双向链表中的第一个元素,也就是header的后继域next域指向的元素
 public E getFirst() {
      
	if (size==0)
	    throw new NoSuchElementException();

	return header.next.element;
 }
 

  getLast()方法

   //取得双向链表的最后一个元素,也就是header前驱动域previous指向的元素.

  public E getLast()  {
	if (size==0)
	    throw new NoSuchElementException();

	return header.previous.element;
  }
 
 

   get(index)方法

//通过下标来查找元素

    public E get(int index) {
        return entry(index).element;
    }

      private Entry<E> entry(int index) {

        //对于参数index的合法性进行校验
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Entry<E> e = header;
        //查找指定位置的双向链表中的节点,从header->next开始算作是0
        //如果查找的位置比size/2小,则顺着找,只需要比对一半的元素
        if (index < (size >> 1)) {
            for (int i = 0; i <= index; i++)
                e = e.next;
            
        //如果指定位置比size/2大,则逆着找,从header->previous开始向前查找
        //最多,也只需要比对一半的元素。
        } else {
            for (int i = size; i > index; i--)
                e = e.previous;
        }
        return e;
    }

 

   3.remove方法

 

  remove(Entry<E> e)方法,在双向循环链表中删除指定结点e

 

  private E remove(Entry<E> e) {

        //如果指定删除的节点,是头结点,则抛出异常,头节点是不可能被删除的.
	if (e == header)
	    throw new NoSuchElementException();

        /*********************************
	 *  |--next---->| ----next--->|
	 * [P]         [e]           [N]
	 *  |<---pre----|<----pre-----|   
	**********************************/
	
	//将在e前驱和后继之间,剔出对e的关联
        E result = e.element;
	e.previous.next = e.next;
	e.next.previous = e.previous;
	
	//小心的释放当前被删除节点持有的关于其它节点的引用
        e.next = e.previous = null;
        e.element = null;
	size--;
	modCount++;

        return result;
    }
 

  由remove(Entry<E> e)方法衍生出removeFirst(Entry<E> e)和removeLast(Entry<E> e)

 

  removeFirst()方法+removeLast()方法

 

   //删除链表第一个元素,也就是header的后继

  public E removeFirst() {
	return remove(header.next);
  }

  //删除链表的最后一个元素,也就是header的前驱
  public E removeLast() {
	return remove(header.previous);
  }

 

 

    remove(Object o)首先是查找到指定的对象所在的节点,然后调用remove(Entry)

     public boolean remove(Object o) {

        //对于目标元素是null分开处理
        if (o==null) {
            for (Entry<E> e = header.next; e != header; e = e.next) {
                if (e.element==null) {
                    remove(e);
                    return true;
                }
            }
        } else {
            for (Entry<E> e = header.next; e != header; e = e.next) {
                if (o.equals(e.element)) {
                    remove(e);
                    return true;
                }
            }
        }
      
        //如果没有找到目标元素,则返回false
        return false;
    }

 

 

   

4.add方法

 

    addBefore(E o, Entry<E> e)方法,在e结点和e.previous之间添加添加元素o.

 

    private Entry<E> addBefore(E o, Entry<E> e) {

    
        //在newEntry的构造函数中已经将next,previous指向正确的位置
        //Entry(E element, Entry<E> next, Entry<E> previous) {
	//    this.element = element;
	//    this.next = next;
	//    this.previous = previous;
	//}
       
        Entry<E> newEntry = new Entry<E>(o, e, e.previous);
	
	//这里还需要更新newEntry前驱节点的next域
	//和newEntry后继节点的previous域
	newEntry.previous.next = newEntry;
	newEntry.next.previous = newEntry;
	size++;
	modCount++;
	return newEntry;
    }
 

    由addBefore(E o, Entry<E> e)衍生出addLast(), addFrist()方法

 

    //在双向循环链表头添加元素,也就是header.next和heder之间

    public void addFirst(E o) {
	addBefore(o, header.next);
    }


   //在双向循环链表尾添加元素,也就是header和header.previous之间
     public void addLast(E o) {
	addBefore(o, header);
    }
 

   通常的add(E)方法

 

    //直接就将元素存放在header.previous与header之间

   public boolean add(E o) {

	addBefore(o, header);
        return true;
    }
 

 

  5. 查找目标元素位置

        //查找指定的元素在链表中的位置,只能是遍历双向循环链表的每个节点,并将节点data取出来比对

    //查找元素,如果是查找null,采用==;如果是查找其它对象则使用equals()
    public int indexOf(Object o) {
        int index = 0;
        if (o==null) {
            for (Entry e = header.next; e != header; e = e.next) {
                if (e.element==null)
                    return index;
                index++;
            }
        } else {
            for (Entry e = header.next; e != header; e = e.next) {
                if (o.equals(e.element))
                    return index;
                index++;
            }
        }
        return -1;
    }

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics