鏈表反轉問題重新總結 20.1.27

題目:

輸入一個鏈表,反轉鏈表後,反向打印鏈表

第一種  非遞歸——借用棧來實現逆序

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> ArrayList1 = new ArrayList<Integer>();
        ListNode list;
        
        list = listNode;
        Stack<Integer> sta = new Stack<Integer>();
        while(listNode!=null){
            sta.add(listNode.val);
            listNode = listNode.next;
        }
        while(!sta.isEmpty()){
            ArrayList1.add(sta.pop());
        }
        return ArrayList1;
    }
}

第二種  非遞歸

這種做法是三指針來實現的,比較簡單,且易於理解,但如果不夠熟練還是會想不清楚的。

先貼代碼,然後做個圖形助於理解

有以下兩種方式,但實際效果一樣,各有特點,看各位自己選擇哪種了

第一種

public class Solution {
    public ListNode ReverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode tmp = null;
        while(cur!=null){
            tmp = cur.next;//先更新後指針
            cur.next = pre;//反向
            pre = cur;     //更新前指針
            cur = tmp;     //更新當前指針
        }
        return pre;
    }
}

第二種:

//逆置——非遞歸
LinkList non_recursive_ListReverse(LinkList L) {
	LinkList pre,cur,rear;
	pre = L;	                //帶頭結點
	cur = pre->next;	      
	rear = cur->next;
	pre->next = NULL;	 	//pre轉向後是最後結點

	while (rear) {
		cur->next = pre;	//換向
		pre = cur;		//更新pre
		cur = rear;             //更新cur
		rear = rear->next;      //更新rear
	}
	cur->next = pre;		//換向
	return cur;
}

第二種的圖解:

 

第三種  遞歸

用遞歸來做的其實都不太好理解,我也搞了好久才明白

LinkList recursive_ListReverse(LinkList head) {
	LinkList cur, rear;
	if (head->next == NULL)	//遞歸出口
		return head;
	LinkList LL = recursive_ListReverse(head->next);//待返回的頭結點

	cur = head;        //更新
	rear = head->next; //更新
	rear->next = cur;  //換向
	cur->next = NULL;  
	return LL;
}

對於鏈表問題,就得自己寫一遍,圖畫一遍,這樣纔會有印象,而且要時常過一遍,因爲其中有一些細節方面,我們往往會搞不明白,鏈表主要的問題就是空指針異常,也就是說邊界情況沒有處理好。最好是做題時時畫一幅圖,來幫助自己理解

下面給出比較全的代碼:可運行於Visual Studio

#include<iostream>
#include<malloc.h>
#include<stdio.h>
using namespace std;
#define ElemType int
typedef struct LNode {
	ElemType data;
	struct LNode* next;
}LNode,*LinkList;

LinkList L = (LinkList)malloc(sizeof(LNode));//創建了頭結點
//LinkList L;//只是定義了一個空指針

//初始化
void InitList(LinkList L) {
	L->data = -1;
	LinkList q = L;
	int val;
	cout << "請輸入數值空格隔開,換行結束" << endl;
	while (cin >> val) {
		LinkList p = (LinkList)malloc(sizeof(LNode));
		p->data = val;
		p->next = NULL;
		q->next = p;
		q = p;
		if(getchar() == '\n')
			break;
	}
}

//逆置——非遞歸
LinkList non_recursive_ListReverse(LinkList L) {
	LinkList pre,cur,rear;
	pre = L;				//帶頭結點
	cur = pre->next;	      
	rear = cur->next;
	pre->next = NULL;	 	//pre轉向後是最後結點

	while (rear) {
		cur->next = pre;	//換向
		pre = cur;			//更新pre
		cur = rear;			//更新cur
		rear = rear->next;  //更新rear
	}
	cur->next = pre;		//換向
	return cur;
}
//逆置——遞歸
/*
 當有很多的next->next搞不清楚的時候,用新的指針代替會更加清晰
*/
LinkList recursive_ListReverse(LinkList head) {
	LinkList cur, rear;
	if (head->next == NULL)	//遞歸出口
		return head;
	LinkList LL = recursive_ListReverse(head->next);//待返回的頭結點

	cur = head;        //更新
	rear = head->next; //更新
	rear->next = cur;  //換向
	cur->next = NULL;  
	return LL;
}

//鏈表判空
int ListEmpty(LinkList L) {
	LinkList p = L;
	if (!p->next)
		return 1;
	return 0;
}

//遍歷
void ListTraverse(LinkList L) {
	LinkList p = L;
	while (p) {
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
int main() {
	InitList(L);
	ListTraverse(L);
	//ListTraverse(recursive_ListReverse(L->next));//遞歸輸出
	ListTraverse(non_recursive_ListReverse(L->next));//非遞歸輸出
	return 0;
}

 

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