二叉樹的遍歷 C++

二叉樹的遍歷有前序遍歷(遍歷順序:根->左->右),中序遍歷(遍歷順序:左->根->右),後序遍歷(遍歷順序:左->右->根),可以看出,這裏的“前/中/後”是對根的位置而言的。哦對,還有一種遍歷方法叫做層序遍歷,下面就來C++實現下。(代碼中除了各種遍歷方法,還有求樹深,樹的鏡像二叉樹的鏡像(劍指offer),以及根據兩個遍歷序列重構二叉樹的實現)

#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
using namespace std;

//定義樹的節點
typedef struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
} TreeNode;

void FrontPrint(TreeNode* root){

    if(root == nullptr){
        return;
    }
    //根
    printf("%d ", root->val);
    //左
    FrontPrint(root->left);
    //右
    FrontPrint(root->right);

}

void FrontPrintByStack(TreeNode* root){
    //前序遍歷的非遞歸實現,藉助stack
    stack<TreeNode*> s;
    TreeNode* cur = root;
    while (cur!= nullptr || !s.empty()){
        //把左子樹壓棧,直至無左子樹
        while (cur != nullptr){
            printf("%d ", cur->val);//根
            s.push(cur);
            cur = cur->left;
        }
        //訪問右子樹
        cur = s.top()->right;
        s.pop();//出棧
    }

}

void MidPrint(TreeNode* root){
    //左根右
    if(root== nullptr) return;
    //左
    MidPrint(root->left);
    //根
    printf("%d ", root->val);
    //右
    MidPrint(root->right);

}

void MidPrintByStack(TreeNode* root){
    //左根右
    stack<TreeNode*> s;
    TreeNode* cur = root;
    while (cur != nullptr || !s.empty()){
        while(cur != nullptr){
            s.push(cur);
            cur = cur->left;
        }
        cur = s.top();
        s.pop();
        printf("%d ", cur->val);

        cur = cur->right;

    }
}

void BackPrint(TreeNode* root){

    if(root== nullptr) return;
    //左
    BackPrint(root->left);//遞歸調用其實是一次壓棧
    //右
    BackPrint(root->right);
    //根
    printf("%d ", root->val);

}

void BackPrintByStack(TreeNode* root){
    //左右根 參考https://blog.csdn.net/monster_ii/article/details/82115772
    stack<TreeNode*> s;
    TreeNode* cur = root;
    TreeNode* top, *last= nullptr;//last可以表示是從左子樹返回根節點還是從右子樹返回根節點
    while (cur != nullptr || !s.empty()){
        while(cur != nullptr){
            s.push(cur);
            cur = cur->left;
        }

        top = s.top();//棧中保存的元素是它的右子樹和自身都沒有被遍歷到的節點
        if (top->right == nullptr || top->right == last){
            s.pop();
            printf("%d ", top->val);
            last = top;
        }
        else {
            cur = top->right;
        }
    }
}

void LevelPrintbByQueue(TreeNode* root){
    //層序遍歷二叉樹並輸出 用隊列實現
    queue<TreeNode*> q;
    if(root !=  nullptr){
        q.push(root);
    }
    while(!q.empty()){
        TreeNode *tmp = q.front(); //隊首
        printf("%d ", tmp->val);

        if(tmp->left != nullptr){
            q.push(tmp->left);
        }
        if(tmp->right != nullptr){
            q.push(tmp->right);
        }

        q.pop();
    }
    printf("\n");
}

void LevelPrintbByArray(TreeNode* root){
    //層序遍歷二叉樹並輸出 用數組實現 https://blog.csdn.net/m0_37925202/article/details/80796010
    TreeNode* a[100];
    int in=0, out=0;//in表示進入數組的元素數,out表示出數組的元素數,[out,in]區間就是模擬的當前的隊列
    if(root != nullptr){
        a[in++] = root;
    }
    while(in > out){
        printf("%d ",a[out]->val);
        if(a[out]->left != nullptr){
            a[in++] = a[out]->left;
        }
        if(a[out]->right != nullptr){
            a[in++] = a[out]->right;
        }
        out++;
    }
}

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
    //根據前序遍歷pre和中序遍歷vin重建二叉樹
    //遞歸方法

    //停止條件
    if(pre.size() == 0){
        return nullptr;
    }

    //解題步驟

    vector<int> lpre,lvin,rpre,rvin;
    //確定root
    TreeNode* root = new TreeNode(pre[0]);

    //在中序中找到root的位置,以及左右子樹
    int loc = 0;//root在中序遍歷的位置
    int flag = 0;

    //對於中序遍歷數組,下標0到loc,其中下標0到loc-1是左子樹,loc是根節點
    for(int i=0;i<vin.size();i++){
        if(vin[i] == root->val){
            loc = i;
            flag = 1;
        }
        else{
            if(flag == 0){
                lvin.push_back(vin[i]);
            }
            else{
                rvin.push_back(vin[i]);
            }
        }
    }

    //對於前序遍歷數組,下標0到loc,其中0是根節點,1-loc是左子樹
    for(int i = 1;i < pre.size();i++){
        if(i <= loc){
            lpre.push_back(pre[i]);
        }
        else
            rpre.push_back(pre[i]);
    }

    //得到左右子樹
    root->left = reConstructBinaryTree(lpre,lvin);
    root->right = reConstructBinaryTree(rpre,rvin);

    //返回以root爲根節點的樹
    return root;
}

void Mirror(TreeNode *pRoot) {
    //樹的鏡像
    queue<TreeNode *>q;//使用隊列對樹進行層序遍歷
    if(pRoot == nullptr){
        return;
    }
    else{
        q.push(pRoot);
    }

    while(!q.empty()){
        TreeNode* f = q.front();
        if(f->left!=nullptr || f->right!=nullptr){
            //只要不是葉節點,就交換左子樹和右子樹
            TreeNode* tmp = f->left;
            f->left = f->right;
            f->right = tmp;
            tmp = nullptr;
        }
        if(f->left != nullptr)
            q.push(f->left);
        if(f->right != nullptr)
            q.push(f->right);

        q.pop();
    }
}

int maxn = 0;
int len = 0;
//樹深=樹中最長的路徑長度
int TreeDepth(TreeNode* pRoot)
{
    if(pRoot==nullptr){
        //該條路徑搜索結束
        if(len>maxn){
            maxn=len;
        }
    }
    else{
        len++;//當前節點在路徑上
        TreeDepth(pRoot->left);//雖然有return但不一定要用變量去接受這個返回值
        TreeDepth(pRoot->right);
        len--;//返回上一個節點,即當前節點不在路徑上
    }
    return maxn;
}

int main(){
    vector<int> pre = {1,2,3,4,5,6,7};//前序遍歷
    vector<int> vin = {3,2,4,1,6,5,7};//中序遍歷
    TreeNode* ans = reConstructBinaryTree(pre,vin);
    LevelPrintbByQueue(ans);
    LevelPrintbByArray(ans);
    printf("\n");
    FrontPrint(ans);
    printf("\n");
    FrontPrintByStack(ans);
    printf("\n");
    MidPrint(ans);
    printf("\n");
    MidPrintByStack(ans);
    printf("\n");
    BackPrint(ans);
    printf("\n");
    BackPrintByStack(ans);
    printf("\n");
    printf("depth=%d\n", TreeDepth(ans));
    Mirror(ans);
    LevelPrintbByQueue(ans);
}

 

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