數據結構之棧和隊列


棧和隊列是計算機中基本的兩個數據結構,棧可以達到后進先出,隊列可以先進先出。在實際應用上,我們可以使用棧進行逆序遍歷鏈表,非遞歸中序遍歷二叉樹,括號匹配,函數調用等等;可以使用隊列對二叉樹進行層次遍歷,打印機的打印服務,通信中的消息隊列等等。

 

下面貼幾道關於棧和隊列較常考的筆試/面試題。

鏈表逆序遍歷:思想很簡單,當鏈表節點不為null就進行壓棧,直到為null。

class Node2{
    int value;
    Node2 next;
}
    
public void reservePrintList(Node2 root) {
        
    if (root == null) {
        return;
    }
        
    Stack<Node2> stack = new Stack<>();
    while (root !=null) {
        stack.push(root);
        root = root.next;
    }
        
    while (!stack.isEmpty()) {
        System.out.println(stack.pop().value);
    }
}

 

非遞歸中序遍歷二叉樹:中序遍歷二叉樹第一個被遍歷的節點肯定位於二叉樹的最左邊,在未到最左邊之前一直壓棧,到了就出棧。

class Node{
    int value;
    Node left;
    Node right;
}
/**
 * 非遞歸中序遍歷二叉樹,利用棧可以很方便的實現
 * @param root
 */
public void printTree1(Node root) {
        
    if (root == null) {
        return;
    }
        
    Stack<Node> stack = new Stack<>();
    while (root != null) {
        stack.push(root);  // 根節點壓棧
        if (root.left != null) { // 左子樹不為空,將左子樹壓入棧
            stack.push(root.left);
        }else {
            // root的左子樹為空,說明root要么是葉子,要么是還有右子樹,不管是葉子還是有右子樹的節點,它都將進行輸出
            // 因為中序遍歷的的順序是從左到右
            Node node = stack.pop(); 
            System.out.println(node.value);
            if (node.right != null) {
                // 存在右子樹,將右子節點壓棧,因為不清楚右子節點是否為葉子,所以是壓棧進行下一輪循環進行處理
                stack.push(node.right);
            }
                
            root = stack.peek(); // 取棧頂元素,但不移除,因為不清楚目前棧頂節點是否為葉子
        }
    }
        
}

 

二叉樹層次遍歷:層次遍歷值對二叉樹從上到下進行一層層的遍歷,每層的遍歷順序為從左到右,借助隊列可以很容易實現

class Node{
        int value;
        Node left;
        Node right;
}
/**
* 層次遍歷二叉樹(從上到下),借助隊列這一數據結構可以很好的實現
* @param root
*/
public void printTree2(Node root) {
        
    if (root == null) {
        return;
    }
        
    Queue<Node> queue = new LinkedList<>();
    queue.add(root); // 將根節點加入隊列
    while (root != null) {
        Node node = queue.poll(); // 取出隊頭root
        if (node.left != null) { // 左子節點不為空,入隊
            queue.offer(root.left);
        }
        if (node.right != null) { // 右子節點不為空 ,入隊
            queue.offer(root.right);
        }
        System.out.println(node.value); // 打印隊頭元素
        root = queue.peek();    // 獲取新的隊頭元素,但不移除,更新為root
    }
}

 

看師弟師妹們數據機構第三章的總結,都是自行實現棧和隊列這兩個數據結構,我上面貼出的代碼沒有進行棧或隊列滿的判斷,這是因為我偷懶直接使用java類庫,java類庫里的棧或隊列都是在超過初始容量后自動擴容的(最大容量好像int類型最大的整數)。C++也是直接把棧和隊列封裝好可以直接使用,但是在學習的時候建議還是先理解底層原理,自己實現,等底層原理熟練就直接用封裝好的類,還有就是建議師弟師妹們要多去敲代碼,不能說基本理論原理了解了,就不去使用代碼進行實現,理論和代碼實現還是有一定差別的,在代碼實現過程中,可能會出現一些bug,不要怕bug,雖然bug的確很煩,一個引用出錯就找了幾小時(我的慘痛經歷),但是解決bug后下次我們就可以更好的避免同類型的bug了。

  


免責聲明!

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



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