1. 程式人生 > >Link連結串列的反轉

Link連結串列的反轉

尊重原創,轉載請標明出處   http://blog.csdn.net/abcdef314159

上一篇簡單介紹了LinkedList,程式碼都很簡單,基本上沒有什麼可說的,這一篇就來介紹一下連結串列的使用,反轉連結串列,這個連結串列和LinkedList是不一樣的,因為LinkedList是雙向連結串列,不需要反轉也可以從後往前遍歷,這裡建立的連結串列是單向的,只能從前往後,不能從後往前,如果想要從後往前遍歷,就需要把連結串列反轉,先建立一個節點類

public class LinkNode {
    public int val;
    public LinkNode next;

    public LinkNode(int x) {
        val = x;
    }
}
上面是一個節點類,下面再寫一個列印的類
    public static void printLink(LinkNode mLink) {
        LinkNode tempNoe = mLink;
        while (tempNoe != null) {
            System.out.print(tempNoe.val + "\t");
            tempNoe = tempNoe.next;
        }
        System.out.println();
    }
先來看第一個反轉的方法
public static LinkNode reverseList1(LinkNode head) {
	//反轉當前連結串列,prev是指前一個節點,表示已經反轉好的連結串列,最開始的時候為null
	LinkNode prev = null;
	while (head != null) {
		//這裡可以認為head是當前節點,因為下面通過不停的賦值,讓head始終指向當前節點,
		//tem是臨時節點,儲存的是當前節點的下一個,如果不儲存,在執行head.next = prev
		//的時候把當前節點之後的節點都搞丟了。
		LinkNode tmp = head.next;
		//讓前一個節點等於當前節點的下一個(前一個節點是已經反轉好的),這個是反轉的關鍵,
		//因為反轉是從頭結點開始的,而prev可以認為是前面幾個已經反轉好的節點,然後掛載在
		//當前節點的下一個,所以這裡不停的通過white迴圈,然後不斷的把已反轉好的prev掛載到
		//當前節點後面,最終實現了連結串列的反轉。
		head.next = prev;
		//掛載完之後讓head等於prev節點,表示已經反轉過來了,prev表示反轉之後的連結串列
		prev = head;
		//讓儲存的tmp節點等於head,實際就相當於在往後挪了一位。然後在迴圈
		head = tmp;
	}
	return prev;//返回反轉後的節點。
}
下面初始化一下連結串列
    public static LinkNode initLink() {
        LinkNode node1 = new LinkNode(1);
        LinkNode node2 = new LinkNode(2);
        LinkNode node3 = new LinkNode(3);
        LinkNode node4 = new LinkNode(4);
        LinkNode node5 = new LinkNode(5);
        LinkNode node6 = new LinkNode(6);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node6;
        return node1;
    }
在呼叫reverseList1方列印一下,看一下結果
1	2	3	4	5	6	
6	5	4	3	2	1	
上一排是正常列印,下一排是經過反轉之後的結果,實現了連結串列的反轉,那麼還有沒有其他方式,繼續看
    public static LinkNode reverseList2(LinkNode head) {
		//可以把head節點當做當前節點,如果當前節點為null,或者沒有後繼節點,直接返回當前節點,
		//因為就一個節點沒法反轉
        if (head == null || head.next == null)
            return head;
			//遞迴遍歷,從當前節點的下一個節點開始,prev表示已經反轉好的,所以這一步執行完之後
			//當前節點head之後的都已反轉完成(當前節點head沒有反轉)
        LinkNode prev = reverseList2(head.next);
		//既然head.next已經反轉完成,那麼head.next顯然是已經反轉到連結串列最後了,然後再讓head等於head.next的下一個,
		//把head節點放到已經反轉的連結串列的最後。其實每次head.next都是為null,因為在下一步把它置為null了,然後
		//再讓head等於head.next的下一個
        head.next.next = head;
		//然後讓head.next節點為空,因為這裡當前節點head是已經反轉好的最後一個節點,所以可以置為null。
        head.next = null;
        return prev;
    }
再看一下列印結果
1	2	3	4	5	6	
6	5	4	3	2	1	

也實現了反轉,如果不好理解可以在改一下,接著往下看

    public static LinkNode reverseList3(LinkNode head) {
        if (head == null || head.next == null)
            return head;
			//在reverseList2中可能這一點不太好理解,雖然prev是已經反轉之後的列表,但是prev指向的
			//是表頭,那怎麼樣才能把head新增到表尾,只能通過迴圈,找到最後一個。
        LinkNode prev = reverseList3(head.next);
        LinkNode current = prev;
        while (current.next != null)
            current = current.next;//找最後一個
        current.next = head;//把head新增到最後一個的next中
        head.next = null;
        return prev;
    }
接著往下看
    public static LinkNode reverseList4(LinkNode head) {
		//這個和reverseList1差不多
        if (null == head) {
            return head;
        }
		//還是一樣,pre是表示已經反轉好的連結串列,這裡的pre暫且認為他是等於head節點的,僅僅等於head這一個節點
		//不包含head後面的節點,暫且這樣認為,雖然不對
        LinkNode pre = head;
        LinkNode cur = head.next;//cur認為是當前節點
        LinkNode _next;//_next認為是當前節點的下一個節點
        while (null != cur) {
            _next = cur.next;//儲存當前節點的下一個節點
			//pre是表達已經反轉好的連結串列,讓他等於當前連結串列的下一個,就是掛載在當前連結串列的下一個
            cur.next = pre;
			//掛載完之後表示又反轉好了一個,然後讓他等於pre,因為pre就是已經反轉好的連結串列
            pre = cur;
			//跳到下一個連結串列迴圈,繼續迴圈
            cur = _next;
        }
        //將原連結串列的頭節點的下一個節點置為null,再將反轉後的頭節點賦給head,這裡為什麼要置null,因為如果不置null,
		//head.next一直是有值的,這個會造成死迴圈,那為什麼reverseList1中最後沒有把head.next置為null,那是因為一開始
		//的時候就讓head.next = prev; 而最開始prev是大於null的,其實已經把prev置為null了
        head.next = null;
        head = pre;//反轉之後的連結串列賦值給head
        return head;//其實上一步也可以不賦值,直接返回pre就可。
    }
繼續看
    public static LinkNode reverseList5(LinkNode prev, LinkNode curr) {
		//prev是前一個節點,表示已經反轉好的連結串列,可以為null,如果curr是first節點,那麼prev就是null,
		//就表示還沒有排序
        LinkNode next = curr.next;
        if (next == null) { 
		// 沒有下個節點則停止迴圈。
            curr.next = prev;
            return curr;
        }
		// 將反轉好的節點prev賦值給當前節點的下一個,這裡在第一次呼叫的時候prev為null,curr是頭結點,
		//所以第一步的時候就已經把尾節點置為null了。
        curr.next = prev; 
		//這裡是通過遞迴,不斷的取出當前節點,然後在不斷的讓已反轉好的節點掛載到當前節點中
        return reverseList5(curr, next);
    }
繼續
    public static LinkNode reverseList6(LinkNode head) {
        //cuur可以認為是當前節點
        LinkNode curr = head.next;
        //_next表示是當前節點curr節點的下一個節點,在下面迴圈中用到
        LinkNode _next = curr.next;
        //讓頭結點孤立起來,讓他沒有後繼節點,成為孤零零的一個節點,這時我們可以認為head節點是已經反轉好的節點
        head.next = null;
        while (_next != null) {
            //讓已經反轉好的節點head成為當前節點的下一個,實現反轉
            curr.next = head;
            //因為curr連結串列已經是反轉之後的了,所以讓curr等於head,head表示已經反轉好的連結串列
            head = curr;
            //讓下一個節點成為當前節點,然後下面迴圈
            curr = _next;
            //移動到下一個節點,繼續
            _next = _next.next;
        }
        //curr是最後一個節點,因為上面迴圈結束的條件是_next != null,而_next可以認為是curr的下一個節點
        //當curr的下一個節點為null的時候,說明curr是尾節點,所以這裡把前面已經反轉好的節點掛載到最後一個節點,
        //最終實現所以節點反轉。
        curr.next = head;
        return curr;
    }
繼續
    public static LinkNode reverseList7(LinkNode head, LinkNode next) {
        //這個和reverseList5很相似,如果下一個節點為null,直接返回
        if (next == null) {
            return head;
        }
        //head可以認為是已經反轉好的,如果head節點的下一個是next,要把head節點的下一個置為null,
        //否則會出現死迴圈,因為head暫且認為是已經反轉好的,然後會掛載到next的下面,如果不置為null,
        //那麼相互掛載,就會出現死迴圈。這裡要明白這一點,head的next是已經反轉好的head節點的下一個,
        // 不是已經反轉好的最後一個
        if (head.next.equals(next)) {
            head.next = null;
        }
        if (next.next != null) {
            //儲存next的下一個,下面遞迴的時候傳進去
            LinkNode next2 = next.next;
            //head可以認為是反轉好的,直接賦值給next的下一個
            next.next = head;
            //遞迴
            return reverseList7(next, next2);
        }
        //將反轉好的head賦值給next的下一個
        next.next = head;
        return next;
    }
接著往下看
    public static LinkNode reverseList8(LinkNode head) {
        LinkNode tail = head.next;
        if (tail.next != null) {
            LinkNode prev = reverseList8(tail);// prev表示已經反轉好的
            LinkNode last = prev;
            while (last.next != null)
                last = last.next;//找到最後一個
            last.next = head;//掛載到最後一個上
            head.next = null;
            return prev;
        }
        tail.next = head;
        head.next = null;
        return tail;
    }
再看
    public static LinkNode reverseList9(LinkNode head) {
        //這個和第一個很相似
        if (head == null || head.next == null) {
            return head;
        }
        LinkNode preNode = null;
        LinkNode curNode = head;
        LinkNode nextNode;
        while (curNode != null) {
            nextNode = curNode.next;
            curNode.next = preNode;
            preNode = curNode;
            curNode = nextNode;
        }
        return preNode;
    }