二叉搜索樹的前序、中序、層次、後序遍歷

一、二叉樹的前序遍歷

Leetcode-144:二叉樹的前序遍歷

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

遞歸大法:

vector<int> res;
vector<int> preorderTraversal(TreeNode* root) {
    if(root == NULL){
        return res;
    }
    //將根節點的值保存在數組中,然後遞歸處理左子樹和右子樹
    res.push_back(root->val);
    preorderTraversal(root->left);
    preorderTraversal(root->right);
    return res;
}

迭代大法:

思路:

  1. 從根結點開始遍歷,遇到不爲空的節點,就將節點值放入數組,並將節點保存在棧中(方便後續遍歷其右子樹)。
  2. 當遇到空節點時,從棧裏面取出一個節點,然後開始遍歷其右子樹。
  3. 每個節點訪問兩次,第一次先入棧並加入結果數組,然後處理其左子樹,第二次出棧,然後處理其右子樹。
vector<int> preorderTraversal(TreeNode* root) {
    vector<int> res;
    stack<TreeNode*> myStack;
    TreeNode* curNode = root;
    while(curNode != NULL || myStack.size() > 0){
        //1、第一次先入棧,並加入結果數組,然後處理其左子樹
        while(curNode != NULL){
            myStack.push(curNode);
            res.push_back(curNode->val);
            curNode = curNode->left;
        }
        //2、第二次出棧,然後處理其右子樹
        TreeNode* node = myStack.top();
        myStack.pop();
        curNode = node->right;
    }
    return res;
}

二、二叉樹的中序遍歷

Leetcode-94:二叉樹的中序遍歷

遞歸大法:

vector<int> res;
vector<int> inorderTraversal(TreeNode* root) {
    if(root == NULL){
        return res;
    }
    //先處理左子樹,然後根節點,最後處理右子樹
    inorderTraversal(root->left);
    res.push_back(root->val);
    inorderTraversal(root->right);
    return res;
}

迭代大法:

思路:

  1. 從根節點開始遍歷,一直尋找其左子節點,直到左子節點爲空之前,將所有節點入棧。
  2. 取棧頂元素加入數組,然後迭代處理棧頂元素的右子樹。
  3. 每個節點訪問兩次,第一次先入棧,然後處理其左子樹,第二次出棧並加入結果數組,然後處理其右子樹。
vector<int> inorderTraversal(TreeNode* root) {
    vector<int> res;
    stack<TreeNode*> myStack;
    TreeNode* curNode = root;
    while(curNode != NULL || myStack.size() > 0){
        //1、第一次先入棧,然後處理其左子樹
        while(curNode != NULL){
            myStack.push(curNode);
            curNode = curNode->left;
        }
        //2、第二次先出棧,並加入結果數組,然後處理其右子樹
        TreeNode* node = myStack.top();
        myStack.pop();
        res.push_back(node->val);
        curNode = node->right;
    }
    return res;
}

三、二叉樹的層次遍歷

Leetcode-103:二叉樹的層次遍歷

DFS:深度優先大法:

vector<vector<int>> res;
int levelNum = 0;
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    add2Vector(root, 0);
    for(int i = 1; i < levelNum; i=i+2){
        reverse(res[i].begin(), res[i].end());
    }
    return res;
}
//遞歸函數每次向下處理一層,將對應層的節點值放入到結果數組中對應下標的數組裏面
void add2Vector(TreeNode* root, int level){
    levelNum = max(levelNum, level);
    if(root == NULL){
        return;
    }
    //level層數實際上比數組的值要大1,處理第0層的時候數組裏面只保存2個元素,處理第1層的時候,數組裏面要保存2個元素
    if(res.size() == level){
        res.resize(res.size() + 1);
    }
    //注意一定是根據層數作爲數組的下標來進行往結果數組裏面賦值
    res[level].push_back(root->val);
    add2Vector(root->left, level+1);
    add2Vector(root->right, level+1);
}

BFS:廣度優先大法(使用2個棧解決)

vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    vector<vector<int>> res;
    //1、異常情況處理
    if(root == NULL){
        return res;
    }
    //2/定義兩個棧和保存每個數組元素的vec
    vector<int> vec;
    stack<TreeNode*> myStack1;
    stack<TreeNode*> myStack2;
    myStack1.push(root);
    //3、初始將root放入myStack1,然後開始遍歷myStack1,也就是處理樹的第一層(奇數層),處理的順序是先左子樹,後右子樹,處理的同時將第一層的左子樹和右子樹都放入myStack2
    while(!myStack1.empty() || !myStack2.empty()){
        vec.clear();
        while(!myStack1.empty()){
            TreeNode* node = myStack1.top();
            myStack1.pop();
            vec.push_back(node->val);
            if(node->left != NULL){
                myStack2.push(node->left);
            }
            if(node->right != NULL){
                myStack2.push(node->right);
            }
        }
        //奇數層處理完了之後把結果放入res中,並清空vec
        if(vec.size() > 0){
            res.push_back(vec);
            vec.clear();
        }
        //然後開始處理偶數層的節點(由於在放入myStack2中節點的時候是先左後右,所以處理的時候是先右後左,滿足偶數層的結果逆序),在處理偶數層的節點的同時需要把其左右子樹加入到myStack1中(此前myStack1已經處理完了,爲空),注意需要先放右子樹,再放左子樹,這樣在處理myStack1的時候就會按照先左子樹,後右子樹的順序處理了
        while(!myStack2.empty()){
            TreeNode* node = myStack2.top();
            myStack2.pop();
            vec.push_back(node->val);
            if(node->right != NULL){
                myStack1.push(node->right);
            }
            if(node->left != NULL){
                myStack1.push(node->left);
            }
        }
        //偶數層處理完了之後把結果放入res中,並清空vec
        if(vec.size() > 0){
            res.push_back(vec);
            vec.clear();
        }
    }
    return res;
}

四、二叉樹的後序遍歷

Leetcode-145:二叉樹的後序遍歷

遞歸大法:

vector<int> res;
vector<int> postorderTraversal(TreeNode* root) {
    if(root == NULL){
        return res;
    }
    //先左子樹,後右子樹,最後根節點
    postorderTraversal(root->left);
    postorderTraversal(root->right);
    res.push_back(root->val);
    return res;
}

迭代大法:

思路:

  1. 每個節點需要訪問三次。
  2. 第一次先入棧然後處理其左子樹。
  3. 第二次先出棧後入棧然後處理其右子樹。
  4. 第三次將其值加入結果數組。
  5. 需要給每個節點新增一個flag記錄訪問的次數
struct newTreeNode {
     TreeNode* node;
     int flag;
 };

vector<int> postorderTraversal(TreeNode* root) {
    vector<int> res;
    if(root == NULL){
        return res;
    }
    stack<newTreeNode*> myStack;
    TreeNode* curNode = root;
    while(curNode != NULL || !myStack.empty()){
        while(curNode != NULL){
            //1、第一次先將節點入棧,並循環處理其左子節點
            newTreeNode* p = new newTreeNode();
            p->node = curNode;
            p->flag = 1;
            myStack.push(p);
            curNode = curNode->left;
        }
        //2、第二次先出棧,然後入棧,並處理其右子樹
        newTreeNode* newNode = myStack.top();
        myStack.pop();
        if(newNode->flag == 1){
            newNode->flag = 2;
            myStack.push(newNode);
            curNode = newNode->node->right;
        }else{
            //3、第三次出棧,並加入結果數組
            res.push_back(newNode->node->val);
        }
    }
    return res;
}

總結一下:遞歸大法真的香。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章