日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

【剑指offer - C++/Java】3、从尾到头打印链表

發(fā)布時(shí)間:2023/12/10 c/c++ 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【剑指offer - C++/Java】3、从尾到头打印链表 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

學(xué)習(xí)交流加

  • 個(gè)人qq:
    1126137994
  • 個(gè)人微信:
    liu1126137994
  • 學(xué)習(xí)交流資源分享qq群:
    962535112

牛客網(wǎng)題目鏈接:
從尾到頭打印鏈表

文章目錄

  • 題目描述
  • 1、遞歸解法
    • 1.1、 遞歸解法一
      • java代碼:
      • C++代碼
      • 分析:
    • 1.2 遞歸解法二
      • java代碼:
      • C++代碼
  • 2、使用棧
    • java代碼
    • C++代碼
  • 總結(jié)

題目描述

輸入一個(gè)鏈表,按鏈表值從尾到頭的順序返回一個(gè)ArrayList。

本題較為簡(jiǎn)單。有兩種解法:遞歸和使用棧循環(huán)。

1、遞歸解法

遞歸解法,也可以有兩種寫法。

1.1、 遞歸解法一

先上代碼,下面給解釋:

java代碼:

import java.util.ArrayList; public class Solution {ArrayList<Integer> arrayList=new ArrayList<Integer>();//注意這個(gè)ArrayList必須在方法體外定義public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {if(listNode!=null){this.printListFromTailToHead(listNode.next);arrayList.add(listNode.val);}return arrayList;} }

C++代碼

class Solution { public:vector<int> res;//注意這個(gè)vector必須在成員函數(shù)外定義vector<int> printListFromTailToHead(ListNode* head) {if(head!=nullptr){this->printListFromTailToHead(head->next);res.push_back(head->val);}return res;} };

分析:

這種遞歸的寫法,可以這么想:因?yàn)橄胍獜奈驳筋^打印鏈表,那么如果此鏈表為空,則直接返回。如果只有一個(gè)節(jié)點(diǎn),則將此節(jié)點(diǎn)打印。否則,遞歸打印頭結(jié)點(diǎn)以后的節(jié)點(diǎn),直到遞歸到最后一個(gè)節(jié)點(diǎn),那么,因?yàn)樽詈笠粋€(gè)節(jié)點(diǎn)后面為空,所以返回上一級(jí)調(diào)用,上一級(jí)調(diào)用后的代碼為res.push_back(head->val);,此時(shí)的head剛好指向的最后的節(jié)點(diǎn),將最后一個(gè)節(jié)點(diǎn)先放到數(shù)組。然后又返回到上一級(jí)的調(diào)用,將倒數(shù)第二個(gè)節(jié)點(diǎn)放到數(shù)組中。以此類推,直到將第一個(gè)節(jié)點(diǎn)放到數(shù)組中。

我們可以看如下圖示來(lái)分析上述遞歸的過(guò)程:


1.剛開(kāi)始head指向節(jié)點(diǎn)1,不為空,將head指針指向下一個(gè)節(jié)點(diǎn),然后遞歸調(diào)用函數(shù)到第2步


2.此時(shí)head依然不為空,將head指針指向下一個(gè)節(jié)點(diǎn),然后遞歸調(diào)用函數(shù)到第3步


3.此時(shí)head依然不為空,將head指針指向下一個(gè)節(jié)點(diǎn),然后遞歸調(diào)用函數(shù)到第4步


4.此時(shí)head依然不為空,將head指針指向下一節(jié)點(diǎn),然后遞歸調(diào)用函數(shù)第5步


5.此時(shí)head指向空,遞歸結(jié)束,那么遞歸結(jié)束后,就需要返回到上一個(gè)遞歸的步驟,上一步驟是步驟4,那么執(zhí)行遞歸語(yǔ)句的下一句:res.push_back(head->val)
(C++代碼),節(jié)點(diǎn)4的值放到數(shù)組中。然后再返回到步驟3,將節(jié)點(diǎn)3的值放入數(shù)組。以此類推,最終從后往前將所有鏈表節(jié)點(diǎn)的值放到數(shù)組中。

注意:此種遞歸方法中,返回?cái)?shù)組的定義一定要放在函數(shù)體外面定義,如果放在函數(shù)體內(nèi)定義,那么由于遞歸的層級(jí)不同,就會(huì)導(dǎo)致每次遞歸的時(shí)候都會(huì)重新定義一個(gè)數(shù)組,導(dǎo)致最后我們只能將第一個(gè)節(jié)點(diǎn)的值返回,結(jié)果肯定是錯(cuò)的。在下一種遞歸的方法中,返回?cái)?shù)組是可以定義在函數(shù)體內(nèi)的,原因見(jiàn)下面解釋。

1.2 遞歸解法二

java代碼:

import java.util.ArrayList; public class Solution {public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {ArrayList<Integer> resArray = new ArrayList<>();if(listNode != null){if(listNode.next != null)resArray = printListFromTailToHead(listNode.next);resArray.add(listNode.val);}return resArray;} }

C++代碼

class Solution { public:vector<int> printListFromTailToHead(ListNode* head) {vector<int> res;if(head!=nullptr){if(head->next!=nullptr)res = printListFromTailToHead(head->next);res.push_back(head->val);}return res;} };

分析: 這種遞歸,實(shí)際上更好理解。首先,如果鏈表位空,則直接返回空數(shù)組。如果鏈表只有一個(gè)節(jié)點(diǎn),則直接返回這個(gè)節(jié)點(diǎn)的值。如果這個(gè)鏈表不止一個(gè)節(jié)點(diǎn),那么遞歸調(diào)用函數(shù)得到除了頭結(jié)點(diǎn)外后面的鏈表,得到后面的鏈表的從后往前打印(放到數(shù)組)的結(jié)果,然后再將之前的頭結(jié)點(diǎn)打印(放到數(shù)組末尾)。那么,最終得到的結(jié)果就是整個(gè)鏈表的從后往前打印的結(jié)果。

可以簡(jiǎn)單的以下面圖示理解:
1.
剛開(kāi)始,head指向頭結(jié)點(diǎn),它后面還有節(jié)點(diǎn)(具體有幾個(gè)都無(wú)所謂)。將head指向下一個(gè)節(jié)點(diǎn),然后遞歸調(diào)用函數(shù)。


2.現(xiàn)在是這樣的,從第1步過(guò)來(lái),該遞歸調(diào)用函數(shù)求現(xiàn)在的這個(gè)鏈表的從后往前打印的結(jié)果。我們把現(xiàn)在這剩下的具有三個(gè)節(jié)點(diǎn)的鏈表,看成一個(gè)黑匣子整體,我的函數(shù)要對(duì)這個(gè)黑匣子求解它的倒序,然后這個(gè)函數(shù)返回了該鏈表的倒序的結(jié)果{4,3,2}。(其實(shí)這里面有好幾個(gè)遞歸的過(guò)程,但是我們不必將所有的遞歸過(guò)程想出來(lái),只需要知道,現(xiàn)在我們可以將后面剩余的鏈表看成一個(gè)新鏈表,然后得到它的倒序就行)

3.得到后面的鏈表的倒序后,是存入數(shù)組的,最后我們?cè)賹㈩^結(jié)點(diǎn)的值,放到數(shù)組末尾res.push_back(head->val);,就可以得到{4,3,2,1},這正是我們要的結(jié)果。

注意:這里的遞歸解法中,返回?cái)?shù)組的定義,可以放到函數(shù)體內(nèi),也可以放到函數(shù)體外。與第一種遞歸的不同之處在于,這里我們可以將以下兩句話,放在同一個(gè)調(diào)用棧內(nèi)看待,即
res =
printListFromTailToHead(head->next);這句話得到后面的鏈表的倒序后,就執(zhí)行res.push_back(head->val);它們的執(zhí)行,可以看成是在一個(gè)函數(shù)調(diào)用棧內(nèi)進(jìn)行的。而第一種遞歸調(diào)用中如果將返回?cái)?shù)組定義在函數(shù)體內(nèi),每一個(gè)調(diào)用都是在一個(gè)新的函數(shù)調(diào)用棧,導(dǎo)致每一個(gè)函數(shù)棧中,都是一個(gè)新的返回?cái)?shù)組,最終只能得到最頂層的函數(shù)棧中的數(shù)組,也就是鏈表的頭結(jié)點(diǎn)的值。

2、使用棧

遞歸解法雖然寫法簡(jiǎn)單,但是遞歸調(diào)用需要重新開(kāi)辟函數(shù)調(diào)用棧,開(kāi)銷比較大。正常的解法實(shí)際上是使用棧來(lái)解決(棧這種數(shù)據(jù)結(jié)構(gòu)本身就與遞歸有很大的聯(lián)系)。

可以遍歷鏈表,每遍歷一個(gè)節(jié)點(diǎn)就將節(jié)點(diǎn)的值壓入到棧中,直到遍歷完鏈表。最后再依次將棧中的元素彈出到返回的數(shù)組中。

java代碼

import java.util.Stack; import java.util.ArrayList; public class Solution {public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {Stack<Integer> st = new Stack<>();ListNode pListNode = listNode;while(pListNode != null){st.push(pListNode.val);pListNode = pListNode.next;}ArrayList<Integer> resArray = new ArrayList<>();while(!st.isEmpty()){resArray.add(st.pop());}return resArray;} }

C++代碼

class Solution { public:vector<int> printListFromTailToHead(ListNode* head) {vector<int> res;stack<int> st;ListNode* p = head;while(p != nullptr){st.push(p->val);p = p->next;}int len = st.size();for(int i = 0;i<len;++i){res.push_back(st.top());st.pop();}return res;} };

總結(jié)

  • 理解遞歸的精髓,上述兩種遞歸的不一樣之處
  • 理解遞歸與棧的關(guān)系

學(xué)習(xí)探討加:
qq:1126137994
微信:liu1126137994

總結(jié)

以上是生活随笔為你收集整理的【剑指offer - C++/Java】3、从尾到头打印链表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。