1. 程式人生 > 其它 >劍指offer程式碼解析——面試題16反轉單鏈表

劍指offer程式碼解析——面試題16反轉單鏈表

本題的詳細解析均在程式碼中註釋:

/**
 * 題目:將單鏈表反轉,並輸出反轉後連結串列的頭結點
 * @author 大閒人柴毛毛
 */
public class RevertLink {
	/**
	 * 分析:本題是要將連結串列“反轉”,而不是反向輸出,這點要特別注意。
	 * 反轉需要改變連結串列的結構,使所有指標都指向相反方向;
	 * 而反向輸出不需要改變連結串列結構,只需反向輸出即可。
	 * 對於反向問題可使用棧來實現,可參見我的部落格《劍指offer——面試題5》,這裡不再贅述。
	 * 下面來解決反轉問題。 
	 */
	
	/**
	 * 反轉單鏈表其實就是將連結串列中的指標指向相反方向,
	 * 若a1和a2是單鏈表中兩個相鄰的結點,未反轉前的狀態是:a1.next = a2,
	 * 現在進行反轉:a2.next = a1.
	 * 此時,雖然a2指向了a1,但連結串列出現了“斷裂”,a2和它的後繼結點發生了斷裂,無法繼續進行反轉操作。
	 * 因此,我們需要再增加一個指標a3,指向a2的後繼結點。
	 * 當反轉完a2結點後,從a3開始繼續依次向後進行反轉操作,直到整個連結串列反轉完為止。
	 * 程式碼如下:
	 */
	
	/**
	 * 反轉連結串列
	 * @param first 連結串列的頭結點
	 * @return 返回反轉後連結串列的頭結點
	 */
	public static <T> Node<T> revertLink(Node<T> first){
		//當連結串列為空時
		if(first==null){
			System.out.println("連結串列為空!");
			return null;
		}
		
		//當連結串列只有一個結點時
		if(first.next==null){
			return first;
		}
		
		//當連結串列只有兩個結點時
		if(first.next.next==null){
			//end為連結串列的尾結點,是反轉後的頭結點
			Node<T> end = first.next;
			//將第二個結點的next域指向第一個結點
			first.next.next = first;
			//將第一個結點的next域設定null
			first.next = null;
			return end;
		}
		
		//當連結串列有三個及以上結點時
		{
			Node<T> a1 = first;//a1指向頭結點
			Node<T> a2 = first.next;//a2指向第二個結點
			Node<T> a3 = first.next.next;//a3指向第三個結點
		
			//將頭結點的後繼設為null
			first.next = null;
			
			//不停的將a1->a2反轉為a2->a1,直到a3為空
			while(a3!=null){
				//a2的後繼設為a1
				a2.next = a1;
				//a1、a2、a3依次向後移一位
				a1 = a2;
				a2 = a3;
				a3 = a3.next;
			}
			
			//將最後一個結點反向
			a2.next = a1;
			return a2;
		}
		//PS:這裡使用區域性程式碼塊一方面增強了程式碼的可讀性,另一方面使得區域性程式碼塊中的變數能夠在程式碼塊結束之後立即釋放,從而節約了記憶體空間。
	}
}


/**
 * 定義結點 
 */
class Node<T>{
	public T data;
	public Node<T> next;
}