LinkedList部分源碼分析(雙鏈表)

LinkedList就是雙鏈表的數據結構,所以主要複習下雙鏈表的插入、刪除和查找

1、結點類

結點類是LinkedList類的靜態內部類,包括指向上一個結點的prev引用、指向下一個結點的next引用和數據域item。構造函數也是初始化這三個參數。

	private static class Node<E>{
		E item;
		Node<E> prev;
		Node<E> next;
		
		Node(Node<E> prev,E element,Node<E> next){
			this.item = element;
			this.prev = prev;
			this.next = next;
		}
	}

2、LinkedList中的某些域

這裏只寫了表示LinkedList大小的size、指向最後一個結點的last引用和指向第一個結點的first引用

	private int size = 0;	//鏈表元素個數
	private Node last;	//指向最後一個結點
	private Node first;	//指向首元結點

3、LinkedList的插入結點操作

(1)在鏈表頭插入一個元素,在鏈表尾插入元素與之相似

注意考慮鏈表本來就沒有元素的情況

	/**
	 *  在鏈表頭插入一個元素e
	 * @param e
	 */
	private void linkFirst(E e) {
		Node<E> f = first;	//初始化f,使其指向首元結點,如果鏈表爲空,則f==first==null
		Node<E> newNode = new Node<>(null,e,f);
	//新建一個newNode結點,newNode結點的next引用指向原來的首元結點,此時該結點成爲新的首元結點
		first = newNode;	//first引用指向新的首元結點
		if(f == null)
			last = newNode;//如果f==null則表示newNode是第一個創建的結點,此時最後一個元素也就是 
                           //第一個元素,last指向最後一個元素
		else
			f.prev = newNode;	//如果f!=null則表示鏈表之前就有元素,並且f指向的是舊的首元結點, 
                                //使舊首元結點的prev引用指向新首元結點
		size++;				//插入了元素,鏈表長度變化
//		modCount++;
	}

(2)在鏈表尾插入元素

/**
	 * 在鏈表尾插入一個元素,操作與linkFirst類似
	 * @param e
	 */
	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++;
	}

(3)在某個非空結點前插入一個元素

	/**
	 * 在結點succ(確保非空)前插入元素e
	 * @param e
	 * @param succ
	 */
	void linkBefore(E e,Node<E> succ) {
        //succ爲空會拋出空指針異常,使用succ結點的prev引用初始化pred,此時pred指向succ的前一個結點
		final Node<E> pred = succ.prev;	
        //創建一個新節點,並且使其prev指向succ的前一個結點,next指向succ
		final Node<E> newNode = new Node<>(pred,e,succ);
		succ.prev = newNode; //將succ的prev指向新的結點,此時新結點成爲succ的前一個結點
		if(pred == null)	//pred爲空即succ爲首元結點,則first指向新結點
			first = newNode;
		else
			pred.next = newNode;
		size++;
//		modCount++;
	}

4、LinkedList結點刪除操作

(1)刪除第一個結點(確保非空),並返回它的值

	/**
	 * 刪除第一個結點(非空),並返回其數據值,傳給該函數的參數一般爲first
     * 當鏈表只有一個結點時,first和last指向的是同一個結點
	 * @param f
	 * @return
	 */
	private E unlinkFirst(Node<E> f) {
		final E element= f.item;  //element爲返回值
		final Node<E> next = f.next;  //使next指向f的下一個結點
		first = next;  //第一個元素刪除後要使first指向之前的第二個元素
		f.item = null;  //這裏相當於將item和next引用設爲空,有助垃圾回收機制回收內存
		f.next = null;
		
		if(next == null)  //如果next爲空則表示元鏈表只有一個元素
			last = null;  //last原本指向的是要刪除的那一個元素,所刪除後要將last指向空
		else
			next.prev = null;
		size--;
//		modCount++;
		return element;
	}

(2)刪除最後一個結點(確保非空)並返回其值

    /**
	 * 刪除最後一個結點l(確保非空),並返回結點的數據值
	 * @param l
	 * @return
	 */
	private E unlinkLast(Node<E> l) {
		final E element = l.item;	//獲取結點l的數據值
		final Node<E> prev = l.prev;//l的前一個結點引用
	    l.item = null;				
		l.prev = null;				//幫助垃圾回收
		last = prev;				//將舊尾結點的引用指向前一個結點
		if(prev == null) 			//如果最後一個結點 l 也是首元結點,即只有一個結點
			first = null;			//則將首元結點引用指向空(此時鏈表中已經沒有結點了)
		else
			prev.next = null;		//如果l不是唯一的結點,則將新尾節的next設爲空
		size--;
		return element;
			
	}

(3)刪除指定的結點並返回其值

   /**
	 * 刪除某一個結點x(確保非空),並返回結點數據值
	 * @param x
	 * @return 
	 */
	E unlink(Node<E> x) {
		final E element = x.item;	//取得結點x的數據值
		final Node<E> prev = x.prev;
		final Node<E> next = x.next;

		//如果x爲首元結點,則將first引用指向下一個結點(x刪除後x的下一個結點爲首元結點)
		if(x.prev == null) {		
			first = next;
		}else {						//否則將x前一個結點的next指向x的下一個結點
			prev.next = next;
			x.prev = null;			//幫助垃圾回收
		}
		
		if(next == null) {			//如果x爲尾結點,則將last指向x的前一個結點
			last = prev;
		}else {						//否則將x的下一個結點的prev引用指向x的前一個結點
			next.prev = prev;
			x.next = null;			//設爲空,幫助垃圾回收
		}
		x.item = null;				//設爲空,幫助垃圾回收
		size--;
//		modCount++;
		return element;
	}

上面的這幾個方法並不是完全對外暴露的接口,但是常用的那些方法實際上都是調用的這些方法,如下

/**
	 * 返回鏈表第一個元素值,鏈表中無元素則拋出異常
	 * @return
	 */
	public E getFirst() {
		final Node<E> f = first;
		if(f == null){
			throw new NoSuchElementException();
		}
		return f.item;
	}
	
	/**
	 * 返回鏈表最後一個元素值,鏈表中無元素則拋出異常
	 * @return
	 */
	public E getLast() {
		final Node<E> l =last;
		if(l == null) {
			throw new NoSuchElementException();
		}
		return l.item;
	}
	
	/**
	 *   刪除第一元素並返回數據值 
	 * @return
	 */
	public E removeFirst() {
		final Node<E> f = first;
		if(f == null)
			throw new NoSuchElementException();
		return unlinkFirst(f);
	}
	
	/**
	 * 刪除最後一個元素並返回值
	 * @return
	 */
	public E removeLast() {
		final Node<E> l = last;
		if(l == null)
			throw new NoSuchElementException();
		return unlinkLast(l);
	}
	
	/**
	 *  刪除指定元素,順在鏈表查找,找到了就刪除
	 */
	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;
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章