#數據結構與算法學習筆記#劍指Offer14:反轉鏈表+非遞歸思路與遞歸思路+PTA升級版+測試用例(Java、C/C++)

2018.8.10

這道題用非遞歸方法需要3個指針做,一個指向後一個結點(later),一個指向中間結點(temp),一個指向前一個結點(front)。每次反轉前front記錄下一結點位置,temp與later進行反轉(此時temp與front之間的指針會斷開),然後later前移至temp位置,temp前移至front位置。循環進行之後的反轉。反轉結束後將最後兩個結點反向,並去掉最開始兩個結點的自循環。

代碼實現過程的注意點:1.輸入head==null,2.輸入鏈表只有一個結點,3.最後兩個結點忘記操作,4.頭兩個結點未去除自循環

另外還有一種遞歸思路可以從鏈表尾部不斷向前翻轉,以此解決鏈表不能回溯的缺點。

鏈表反轉題還有一道升級版,要求每隔k個元素進行一次反轉,比這個要複雜得多。很早之前做過,可以參考之前的文章:

#數據結構與算法學習筆記#PTA6:鏈表翻轉升級版(C/C++)


題目描述

輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。


Java實現代碼:

/**
 * 
 * @author ChopinXBP 
 * 輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。
 *  
 *
 */

public class ReverseList_15 {

	public static class ListNode {
		int val;
		ListNode next = null;

		ListNode(int val) {
			this.val = val;
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		ListNode head = new ListNode(0);
		ListNode p = head;
		for (int i = 0; i < 5; i++) {
			ListNode newnode = new ListNode(i + 1);
			p.next = newnode;
			p = p.next;
		}
		p = head;
		System.out.print("原序列: ");
		for (int i = 0; i < 6; i++) {
			System.out.print(p.val);
			p = p.next;
		}
		p = Solution(head);

		System.out.print("\n翻轉序列: ");
		for (int i = 0; i < 6; i++) {
			System.out.print(p.val);
			p = p.next;
		}
	}

	public static ListNode Solution(ListNode head) {
		if (head == null)
			return null;
		else if (head.next == null)
			return head;

		ListNode temp = head.next;		//指向前一個結點
		ListNode later = head;			//指向後一個結點

		//每次循環先定義一個former指向下一個結點,將temp與later所指結點反向,並依次前進later與temp
		while (temp.next != null) {

			ListNode former = temp.next;	//指向下一個結點
			temp.next = later;
			later = temp;
			temp = former;

		}

		temp.next = later;		//將最後兩個結點反向
		head.next = null;		//去掉頭兩個結點的自循環

		return temp;
	}
}

C++實現示例:

//第一種方法是:非遞歸方法

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
         
        if(pHead==NULL) return NULL;//注意程序魯棒性
         
        ListNode* pNode=pHead;//當前指針
        ListNode* pReverseHead=NULL;//新鏈表的頭指針
        ListNode* pPrev=NULL;//當前指針的前一個結點
         
        while(pNode!=NULL){//當前結點不爲空時才執行
            ListNode* pNext=pNode->next;//鏈斷開之前一定要保存斷開位置後邊的結點
             
            if(pNext==NULL)//當pNext爲空時,說明當前結點爲尾節點
                pReverseHead=pNode;
  
            pNode->next=pPrev;//指針反轉
            pPrev=pNode;
            pNode=pNext;
        }
        return pReverseHead;
    }
}
 
//第二種方法是:遞歸方法 
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        //如果鏈表爲空或者鏈表中只有一個元素
        if(pHead==NULL||pHead->next==NULL) return pHead;
         
        //先反轉後面的鏈表,走到鏈表的末端結點
        ListNode* pReverseNode=ReverseList(pHead->next);
         
        //再將當前節點設置爲後面節點的後續節點
        pHead->next->next=pHead;
        pHead->next=NULL;
         
        return pReverseNode;
         
    }
};

測試代碼:

// ====================測試代碼====================
ListNode* Test(ListNode* pHead)
{
    printf("The original list is: \n");
    PrintList(pHead);

    ListNode* pReversedHead = ReverseList(pHead);

    printf("The reversed list is: \n");
    PrintList(pReversedHead);

    return pReversedHead;
}

// 輸入的鏈表有多個結點
void Test1()
{
    ListNode* pNode1 = CreateListNode(1);
    ListNode* pNode2 = CreateListNode(2);
    ListNode* pNode3 = CreateListNode(3);
    ListNode* pNode4 = CreateListNode(4);
    ListNode* pNode5 = CreateListNode(5);

    ConnectListNodes(pNode1, pNode2);
    ConnectListNodes(pNode2, pNode3);
    ConnectListNodes(pNode3, pNode4);
    ConnectListNodes(pNode4, pNode5);

    ListNode* pReversedHead = Test(pNode1);

    DestroyList(pReversedHead);
}

// 輸入的鏈表只有一個結點
void Test2()
{
    ListNode* pNode1 = CreateListNode(1);

    ListNode* pReversedHead = Test(pNode1);

    DestroyList(pReversedHead);
}

// 輸入空鏈表
void Test3()
{
    Test(NULL);
}

int _tmain(int argc, _TCHAR* argv[])
{
    Test1();
    Test2();
    Test3();

    return 0;
}

#Coding一小時,Copying一秒鐘。留個言點個讚唄,謝謝你#

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