本文參考自《劍指offer》一書,代碼采用Java語言。
題目
輸入一個鏈表的頭結點,從尾到頭反過來打印出每個結點的值。結點定義如下:
public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }
思路
結點遍歷順序只能從頭到尾,但是輸出的順序卻為從尾到頭,是典型的“后進先出”問題,這就要聯想到使用棧,從而也可以聯想到使用遞歸。
測試用例
1.功能測試(單個結點鏈表,多個結點鏈表)
2.特殊輸入測試(鏈表為空)
完整Java代碼
import java.util.Stack; /** * * @Description 從尾到頭打印鏈表 * * @author yongh * @date 2018年9月10日 下午7:07:23 */ //題目:輸入一個鏈表的頭結點,從尾到頭反過來打印出每個結點的值。 public class PrintListInReversedOrder { class ListNode{ int key; ListNode next; public ListNode(int key) { this.key=key; this.next=null; } } // 采用棧 public void printListReversingly_Iteratively(ListNode node) { Stack<ListNode> stack = new Stack<ListNode>(); while (node!= null) { stack.push(node); node=node.next; } while(!stack.empty()) { System.out.println(stack.pop().key); } } //采用遞歸 public void printListReversingly_Recursively(ListNode node) { if(node!=null) { printListReversingly_Recursively(node.next); System.out.println(node.key); }else return; } // ==================================測試代碼================================== /** * 鏈表為空 */ public void test1() { ListNode aListNode = null; System.out.println("采用棧:"); printListReversingly_Iteratively(aListNode); System.out.println("采用遞歸:"); printListReversingly_Recursively(aListNode); } /** * 多個結點鏈表 */ public void test2() { ListNode ListNode1 = new ListNode(1); ListNode ListNode2 = new ListNode(2); ListNode ListNode3 = new ListNode(3); ListNode ListNode4 = new ListNode(4); ListNode ListNode5 = new ListNode(5); ListNode1.next=ListNode2; ListNode2.next=ListNode3; ListNode3.next=ListNode4; ListNode4.next=ListNode5; System.out.println("采用棧:"); printListReversingly_Iteratively(ListNode1); System.out.println("采用遞歸:"); printListReversingly_Recursively(ListNode1); } /** * 單個結點鏈表 */ public void test3() { ListNode ListNode1 = new ListNode(1); System.out.println("采用棧:"); printListReversingly_Iteratively(ListNode1); System.out.println("采用遞歸:"); printListReversingly_Recursively(ListNode1); } public static void main(String[] args) { PrintListInReversedOrder demo = new PrintListInReversedOrder(); System.out.println("test1:"); demo.test1(); System.out.println("test2:"); demo.test2(); System.out.println("test3:"); demo.test3(); } }

test1: 采用棧: 采用遞歸: test2: 采用棧: 5 4 3 2 1 采用遞歸: 5 4 3 2 1 test3: 采用棧: 1 采用遞歸: 1
遞歸部分代碼也可以像下面這樣寫,注意體會不同的遞歸寫法:
// 采用遞歸 public void printListReversingly_Recursively(ListNode node) { // if(node!=null) { // printListReversingly_Recursively(node.next); // System.out.println(node.key); // }else // return; if (node != null) { if (node.next != null) { printListReversingly_Recursively(node.next); } System.out.println(node.key); } }
====================================================================
在牛客網中提交的代碼如下(參考自:grass_stars 的代碼):
public class Solution { ArrayList<Integer> arrayList = new ArrayList<Integer>(); public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { if (listNode != null) { this.printListFromTailToHead(listNode.next); arrayList.add(listNode.val); } return arrayList; } }
上面代碼采用的遞歸,非常簡潔,很值得學習。
收獲
1.對於“后進先出”問題,要快速想到”棧“,也同時想到遞歸。
2.采用遞歸時,返回的函數值不一定要有賦值操作,只要實現了遍歷的作用就可以了,上面牛客網的代碼可以多多學習。