【算法篇】棧和隊列專題之廣度優先遍歷和深度優先遍歷


  前言

     今天要介紹棧和隊列相關算法,棧和隊列這種數據結構相對簡單,但是結合算法就變化莫測了,一起來看一下吧

   一、棧

    1、簡介

    棧這種數據結構可以用數組、線性表和鏈表等來實現,但要保證先進后出這種性質;

    可能會問棧有什么應用呢?

    應用非常廣泛,像編輯器的撤銷功能,先把“操作”入棧,然后最后入棧的,先彈出,就實現撤銷功能了;

    像linux內核實現的函數調用,也是把函數不斷入棧,然后再彈出,還有棧和遞歸和密不可分的。

    2、題目

    LeetCode上第20號題,題目如下:

給定一個只包含字符“(”、“)”、“{”、“}”、“[”和“]”的字符串,確定輸入字符串是否有效。
如果:輸入字符串有效:
開括號必須用相同類型的括號括起來。
開括號必須按正確的順序關閉。
注意,空字符串也被認為是有效的。
示例1:
輸入:“()”
輸出:正確
示例2:
輸入:“()(){ }”
輸出:正確
示例3:
輸入:“(]”
輸出:假
示例4:
輸入:“([))”
輸出:假
例5:
輸入:“{[]}”
輸出:正確

  進行畫圖講解吧,如下圖:  PS:依舊是全網最丑圖!很努力去畫,依舊很丑,看來畫圖的天賦了!

 

  

  說明:

  假如,[()]要入棧,規則:遇到“左邊符號”入棧,“右邊符號”彈出棧頂元素,進行比較,“()”符合要求,就是正確的,以此類推;還有一點要注意的,最后棧不是空的,說明棧里還有“左邊符號”,這是不正確的。

  3、代碼及演示

  代碼如下:

#include <iostream>
#include <stack>
#include <cassert>

using namespace std;

// 20. Valid Parentheses
// https://leetcode.com/problems/valid-parentheses/description/
// 時間復雜度: O(n)
// 空間復雜度: O(n)
class Solution {
public:
    bool isValid(string s) {

        stack<char> stack;
        for( int i = 0 ; i < s.size() ; i ++ )
            if( s[i] == '(' || s[i] == '{' || s[i] == '[')
                stack.push(s[i]);
            else{

                if( stack.size() == 0 )
                    return false;

                char c = stack.top();
                stack.pop();

                char match;
                if( s[i] == ')' )
                    match = '(';
                else if( s[i] == ']' )
                    match = '[';
                else{
                    assert( s[i] == '}' );
                    match = '{';
                }

                if(c != match)
                    return false;
            }

        if( stack.size() != 0 )
            return false;

        return true;
    }
};

int main() {

    if(Solution().isValid("()"))
        cout << "() is valid." << endl;
    else
        cout << "() is invalid." << endl;

    if(Solution().isValid("()[]{}"))
        cout << "()[]{} is valid." << endl;
    else
        cout << "()[]{} is invalid." << endl;

    if(Solution().isValid("(]"))
        cout << "(] is valid." << endl;
    else
        cout << "(] is invalid." << endl;

    if(Solution().isValid("([)]"))
        cout << "([)] is valid." << endl;
    else
        cout << "([)] is invalid." << endl;

    return 0;
}
View Code

  我對幾組數據進行了測試:()、()[]{}等,運行結果如下:

  4、總結

  棧的應用非常多,主要理解棧的先進后出的特性!

  二、隊列

  1、簡介

  隊列也是一種線性數據結構,特性是先進先出;隊列有一個重要應用:廣度優先遍歷,相對於廣度還有一種深度優先遍歷,可能對於一些人還不知道廣度、深度優先遍歷,所以來解釋一下。

  對於二叉樹來說:

  廣度優先遍歷叫層序遍歷更貼切,一層一層來遍歷的,下面會詳細講解這種應用;

  深度優先遍歷就是先序、中序和后序遍歷;

  對圖來說:就分為廣度優先遍歷和深度優先遍歷了,圖這部分之后我還會詳細講解;

  2、題目

  LeetCode第102題,題目如下:

  

給定二叉樹,返回其節點值的層次順序遍歷。(例如,從左到右,逐層排列)。
例如:
給定二叉樹[3,9,20,null,null,15,7],
     3
    / \
   9 20
      / \
    15 7
返回其水平順序遍歷如下:
[
  [3],
  [9,20],
  [15,7]
]
    

  這是二叉樹典型的層序遍歷,還有二叉樹的先序、中序和后序遍歷,統稱為深度優先遍歷!不懂的老鐵可以參考這篇博客:https://www.cnblogs.com/liudw-0215/p/9835691.html,講的很詳細。

  用圖進行講解吧,圖如下:

  

  說明:先把根節點1入隊,然后是2、3,以此類推,然后再出隊,就可以實現層序遍歷了。

  3、代碼實現

  代碼如下:

  

#include <iostream>
#include <vector>
#include <queue>
#include <cassert>

using namespace std;

/// 102. Binary Tree Level Order Traversal
/// https://leetcode.com/problems/binary-tree-level-order-traversal/description/
/// 二叉樹的層序遍歷
/// 時間復雜度: O(n), n為樹的節點個數
/// 空間復雜度: O(n)

/// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {

        vector<vector<int>> res;
        if(root == NULL)
            return res;

        queue<pair<TreeNode*,int>> q;
        q.push(make_pair(root, 0));

        while(!q.empty()){

            TreeNode* node = q.front().first;
            int level = q.front().second;
            q.pop();

            if(level == res.size())
                res.push_back(vector<int>());
            assert( level < res.size() );

            res[level].push_back(node->val);
            if(node->left)
                q.push(make_pair(node->left, level + 1 ));
            if(node->right)
                q.push(make_pair(node->right, level + 1 ));
        }

        return res;
    }
};

int main() {

    return 0;
}
View Code

  總結

  棧和隊列的應用非常之多,要不斷理解它們的特性:先進后出、先進先出!喜歡的歡迎隨時點贊,不懂的歡迎隨時留言!

    


免責聲明!

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



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