劍指Offer面試題:4.從尾到頭打印鏈表


一、題目:從尾到頭打印鏈表

題目:輸入一個鏈表的頭結點,從尾到頭反過來打印出每個結點的值。

  到解決這個問題肯定要遍歷鏈表。遍歷的順序是從頭到尾的順序,可輸出的順序卻是從尾到頭。也就是說第一個遍歷到的結點最后一個輸出,而最后一個遍歷到的結點第一個輸出。這就是典型的“后進先出”,我們可以用棧實現這種順序。

二、解題思路

Stack

  每經過一個結點的時候,把該結點放到一個棧中。當遍歷完整個鏈表后,再從棧頂開始逐個輸出結點的值,此時輸出的結點的順序已經反轉過來了。

三、解決問題

3.1 代碼實現

  這里使用的是自定義實現的鏈表類,其節點定義如下:

    public class Node<T>
    {
        // 數據域
        public T Item { get; set; }
        // 指針域
        public Node<T> Next { get; set; }

        public Node()
        {
        }

        public Node(T item)
        {
            this.Item = item;
        }
    }

  這里的自定義的單鏈表的實現請參考:《數據結構基礎溫故-1.線性表(中)

  (1)基於棧的循環版本

    public static void PrintListReversinglyIteratively(Node<int> head)
    {
        Stack<Node<int>> stackNodes = new Stack<Node<int>>();
        Node<int> node = head;
        // 單鏈表元素依次入棧
        while (node != null)
        {
            stackNodes.Push(node);
            node = node.Next;
        }
        // 棧中的單鏈表元素依次出棧
        while (stackNodes.Count > 0)
        {
            Node<int> top = stackNodes.Pop();
            Console.Write("{0}", top.Item);
        }
    }

  (2)遞歸版本

    public static void PrintListReversinglyRecursively(Node<int> head)
    {
        if (head != null)
        {
            if (head.Next != null)
            {
                PrintListReversinglyRecursively(head.Next);
            }

            Console.Write("{0}", head.Item);
        }
    }

  兩個版本的對比:上面的基於遞歸的代碼看起來很簡潔,但有個問題:當鏈表非常長的時候,就會導致函數調用的層級很深,從而有可能導致函數調用棧溢出顯式用棧基於循環實現的代碼的魯棒性要好一些

3.2 單元測試

  (1)單元測試主入口

    // 測試主入口
    static void PrintTestPortal(Node<int> head)
    {
        Console.WriteLine("-------Begin--------");
        NormalPrint(head);
        Console.WriteLine();
        PrintListReversinglyIteratively(head);
        Console.WriteLine();
        PrintListReversinglyRecursively(head);
        Console.WriteLine("\n-------End--------");
    }
    // 輔助方法:正序打印鏈表
    static void NormalPrint(Node<int> head)
    {
        Node<int> temp = head;
        while(temp != null)
        {
            Console.Write("{0}",temp.Item);
            temp = temp.Next;
        }
    }

  在測試入口中,我們首先正序打印鏈表,然后使用循環版從尾到頭打印鏈表,最后使用遞歸版從尾到頭打印鏈表。

  (2)正常的多元素鏈表

    // 1->2->3->4->5
    static void PrintTest1()
    {
        Console.WriteLine("TestCase1:");
        SingleLinkedList<int> linkedList = new SingleLinkedList<int>();
        linkedList.Add(1);
        linkedList.Add(2);
        linkedList.Add(3);
        linkedList.Add(4);
        linkedList.Add(5);

        PrintTestPortal(linkedList.Head);
    }

  (3)只有一個節點的鏈表

    // 只有一個節點的鏈表
    static void PrintTest2()
    {
        Console.WriteLine("TestCase2:");
        SingleLinkedList<int> linkedList = new SingleLinkedList<int>();
        linkedList.Add(1);

        PrintTestPortal(linkedList.Head);
    }

  (4)魯棒性測試:NULL

    // 空鏈表
    static void PrintTest3()
    {
        Console.WriteLine("TestCase3:");

        PrintTestPortal(null);
    } 

  測試結果如下圖所示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM