1. 程式人生 > 其它 >劍指 offer程式碼解析——面試題26複雜連結串列的複製

劍指 offer程式碼解析——面試題26複雜連結串列的複製

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

/**
 * 題目:請複製一個複雜連結串列。每個結點除了有一個next指標指向下一個結點外,還有一個sibling指向連結串列中的任意一個結點。
 * @author 大閒人柴毛毛
 * @date 2016年3月16日
 */
public class CopyLink {
	/**
	 * 分析:複製單鏈表較為簡單,只需遍歷單鏈表,建立結點,同時將前後連個結點相繼連起來即可。
	 * 本題的難點在於:每個結點還有一個sibling域,指向連結串列的任意一個結點。
	 * 本題最直觀的思路有兩種:
	 * 1.先複製單鏈表,然後再複製sibling域;
	 * 2.在複製單鏈表的同時確定sibling域名。
	 * 第一種方法較為簡單,複製完單鏈表後需再次遍歷原連結串列,
	 * 若當前結點的sibling域不為空,則從當前結點開始依次向後查詢sibling域指向的位置,
	 * 我們可以用一個計數器count記錄當前結點與sibling域指向的結點直接的距離,
	 * 然後在新連結串列中,以該結點為起點,向後走count步即為sibling域指向的結點。
	 * 這種方式由於每個結點都要依次向後查詢sibling指向的結點,因此時間複雜度為O(n^2)。
	 */
	
	/**
	 * 下面介紹一種巧妙的方法:
	 * 首先複製每個結點,並將他們插入在原結點的後面,從而形成一條新的連結串列;
	 * 然後遍歷連結串列,若當前結點a的sibling不為空,則將a的下一個結點b的sibling指向a.sibling的下一個結點;
	 * 最後拆分連結串列:將奇數位連起來,偶數位連起來即可。
	 * 程式碼如下:
	 */
	
	/**
	 * 複製複雜連結串列
	 * @param first 複雜連結串列的頭結點
	 * @return 返回複製後的複雜連結串列
	 */
	static boolean result = true;//copyLink執行結果
	public static <T> Node<T> copyLink(Node<T> first){
		//若連結串列為空
		if(first==null){
			System.out.println("連結串列為空!");
			result = false;
			return null;
		}
		
		//複製每個結點,並插入原結點之後
		Node<T> p = first;
		while(p!=null){
			//建立新結點
			Node<T> node = new Node<T>();
			node.data = p.data;
			//將新結點插入p之後
			node.next = p.next;
			p.next = node;
		}
		
		//複製每個結點的sibling域
		p = first;
		while(p!=null){
			p.next.sibling = p.sibling.next;
		}
		
		//拆分連結串列
		p = first;
		Node<T> q = p.next;
		Node<T> first_copy = q;//被複制連結串列的頭結點
		while(q!=null){
			p.next = q.next;
			p = q;
			q = q.next;
		}
		
		return first_copy;
	}
	
	
	/**
	 * 綜上所述:上述方法只需掃描連結串列3次:
	 * 1.第一遍複製每個結點,並依次插入結點的後面;
	 * 2.第二遍複製每個結點的sibling域;
	 * 3.第三次拆分連結串列。
	 * 因此,上述方式的時間複雜度為O(n)
	 */
}



/**
 * 複雜連結串列的一個結點
 */
class Node<T>{
	T data;
	Node<T> next;
	Node<T> sibling;
}