二叉樹的四種遍歷方法(C++)


1.前序遍歷

前序遍歷:先遍歷根節點,再遍歷左子樹,最后遍歷右子樹(根-左-右)

測試代碼:

// 二叉樹的三種遍歷
// 1.前序遍歷
// 2.中序遍歷
// 3.后序遍歷

#include <cstdio>
#include <stack>
#include <vector>
#include "BinaryTree.h"

using namespace std;

void visitAlongLeftBranch(BinaryTreeNode* , vector<int>& , stack<BinaryTreeNode*>&);

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹前序遍歷算法(迭代版)
{
    stack<BinaryTreeNode*> S; //輔助棧

    while (true)
    {
        visitAlongLeftBranch(pRoot, treeNodes, S);  //從當前節點逐批訪問
        if (S.empty()) break; //棧為空, 彈出
        pRoot = S.top();  //彈出下一批的起點
        S.pop();
    }
}

//從當前節點出發, 沿左分支不斷深入, 直至沒有左分支的節點; 沿途節點遇到后立即訪問
void visitAlongLeftBranch(BinaryTreeNode* pRoot, vector<int>& treeNodes, stack<BinaryTreeNode*>& S)
{
    while (pRoot)
    {
        treeNodes.push_back(pRoot->m_nValue); //訪問當前節點
        S.push(pRoot->m_pRight); //右子節點入棧暫存
        pRoot = pRoot->m_pLeft; //沿左分支深入一層
    }
}

// ====================測試代碼====================
void Test(const char* testName, BinaryTreeNode* pRoot, 
    vector<int> expectedPre, vector<int> expectedIn, vector<int> expectedPost, int expectedLength)
{
    if (testName != nullptr)
        printf("%s begins: ", testName);

    vector<int> treeNodes;  //保存遍歷值
    TraverseBinaryTree(pRoot, treeNodes);
    int length = treeNodes.size();

    bool flag = true;  //標志位
    if (length != expectedLength) flag = false;  //長度不一致, 則遍歷算法錯誤

    for (int i = 0; i < length; ++i)  //順序不一致, 則遍歷算法錯誤
    {
        if (treeNodes[i] != expectedPre[i])  //注意:遍歷期望值在這里改
            flag = false;
    }
    
    if (flag)
        printf("Passed.");
    else
        printf("Failed.");

    //打印遍歷值
    printf("\nExpected: ");
    for (int i = 0; i < expectedLength; ++i)
        printf("%d ", expectedPre[i]);  //注意:遍歷期望值在這里改

    printf("\nActual:   ");
    for (int i = 0; i < length; ++i)
        printf("%d ", treeNodes[i]);
    printf("\n\n");
}

// 1.滿二叉樹
//            10
//          /    \
//         6      14
//        /\      /\
//       4  8   12  16
void Test1()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);
    BinaryTreeNode* pNode16 = CreateBinaryTreeNode(16);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, pNode16);

    vector<int> expectedPre = {10, 6, 4, 8, 14, 12, 16};
    vector<int> expectedIn = {4, 6, 8, 10, 12, 14, 16};
    vector<int> expectedPost = {4, 8, 6, 12, 16, 14, 10};

    Test("Test1", pNode10, expectedPre, expectedIn, expectedPost, 7);

    DestroyTree(pNode10);
}

// 2.完全二叉樹
//            10
//          /    \
//         6      14
//        /\      /
//       4  8   12
void Test2()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, nullptr);

    vector<int> expectedPre = { 10, 6, 4, 8, 14, 12};
    vector<int> expectedIn = { 4, 6, 8, 10, 12, 14};
    vector<int> expectedPost = { 4, 8, 6, 12, 14, 10 };

    Test("Test2", pNode10, expectedPre, expectedIn, expectedPost, 6);

    DestroyTree(pNode10);
}

// 3.二叉樹
//            10
//          /    \
//         6      14
//         \      /
//          8   12  
//         /
//        4
void Test3()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, nullptr , pNode8);
    ConnectTreeNodes(pNode8, pNode4, nullptr);
    ConnectTreeNodes(pNode14, pNode12, nullptr);

    vector<int> expectedPre = { 10, 6, 8, 4, 14, 12 };
    vector<int> expectedIn = { 6, 4, 8, 10, 12, 14 };
    vector<int> expectedPost = { 4, 8, 6, 12, 14, 10 };

    Test("Test3", pNode10, expectedPre, expectedIn, expectedPost, 6);

    DestroyTree(pNode10);
}

// 4.只有最左側通路
//               5
//              /
//             4
//            /
//           3
//          /
//         2
//        /
//       1
void Test4()
{
    BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
    BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);

    ConnectTreeNodes(pNode5, pNode4, nullptr);
    ConnectTreeNodes(pNode4, pNode3, nullptr);
    ConnectTreeNodes(pNode3, pNode2, nullptr);
    ConnectTreeNodes(pNode2, pNode1, nullptr);

    vector<int> expectedPre = {5, 4, 3, 2, 1};
    vector<int> expectedIn = {1, 2, 3, 4, 5};
    vector<int> expectedPost = {1, 2, 3, 4, 5};

    Test("Test4", pNode5, expectedPre, expectedIn, expectedPost, 5);

    DestroyTree(pNode5);
}

// 4.只有最右側通路
// 1
//  \
//   2
//    \
//     3
//      \
//       4
//        \
//         5
void Test5()
{
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);
    BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
    BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);

    ConnectTreeNodes(pNode1, nullptr, pNode2);
    ConnectTreeNodes(pNode2, nullptr, pNode3);
    ConnectTreeNodes(pNode3, nullptr, pNode4);
    ConnectTreeNodes(pNode4, nullptr, pNode5);

    vector<int> expectedPre = {1, 2, 3, 4, 5};
    vector<int> expectedIn = { 1, 2, 3, 4, 5 };
    vector<int> expectedPost = {5, 4, 3, 2, 1};

    Test("Test5", pNode1, expectedPre, expectedIn, expectedPost, 5);

    DestroyTree(pNode1);
}

// 樹中只有1個結點
void Test6()
{
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);

    vector<int> expectedPre = {1};
    vector<int> expectedIn = {1};
    vector<int> expectedPost = {1};

    Test("Test6", pNode1, expectedPre, expectedIn, expectedPost, 1);

    DestroyTree(pNode1);
}

// 樹中沒有結點
void Test7()
{
    vector<int> expectedPre = {};
    vector<int> expectedIn = {};
    vector<int> expectedPost = {};

    Test("Test7", nullptr, expectedPre, expectedIn, expectedPost, 0);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();

    return 0;
}
前序遍歷測試代碼

1.1 基於遞歸實現

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹前序遍歷算法(遞歸版)
{
    if (pRoot == nullptr)
        return;

    treeNodes.push_back(pRoot->m_nValue);
    TraverseBinaryTree(pRoot->m_pLeft, treeNodes);
    TraverseBinaryTree(pRoot->m_pRight, treeNodes);
}

1.2 基於迭代實現

 由於沒有指向父節點的指針,所以需要輔助棧來記錄路徑中的右子節點。

void visitAlongLeftBranch(BinaryTreeNode* , vector<int>& , stack<BinaryTreeNode*>&);

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹前序遍歷算法(迭代版)
{
    stack<BinaryTreeNode*> S; //輔助棧

    while (true)
    {
        visitAlongLeftBranch(pRoot, treeNodes, S);  //從當前節點逐批訪問
        if (S.empty()) break; //棧為空, 彈出
        pRoot = S.top();  //彈出下一批的起點
        S.pop();
    }
}

//從當前節點出發, 沿左分支不斷深入, 直至沒有左分支的節點; 沿途節點遇到后立即訪問
void visitAlongLeftBranch(BinaryTreeNode* pRoot, vector<int>& treeNodes, stack<BinaryTreeNode*>& S)
{
    while (pRoot)
    {
        treeNodes.push_back(pRoot->m_nValue); //訪問當前節點
        S.push(pRoot->m_pRight); //右子節點入棧暫存
        pRoot = pRoot->m_pLeft; //沿左分支深入一層
    }
}

 LeetCode

/**
 * 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<int> preorderTraversal(TreeNode* root) {
        
        vector<int> ret;  //保存路徑值
        stack<TreeNode*> S;  //輔助棧

        while (true)
        {
            if (root)  //尋找最左節點
            {
                ret.push_back(root->val);  //中途節點直接訪問
                S.push(root->right);  //暫存右子節點
                root = root->left;
            }
            else if (!S.empty())
            {
                root = S.top(); S.pop();
            }
            else
                break;
        }
        return ret;
    }
};

 

2.中序遍歷

中序遍歷:先遍歷左子樹,再遍歷根節點,最后遍歷右子樹(左-根-右)

 測試代碼:

// 二叉樹的三種遍歷
// 1.前序遍歷
// 2.中序遍歷
// 3.后序遍歷

#include <cstdio>
#include <stack>
#include <vector>
#include "BinaryTree.h"

using namespace std;

void goAlongLeftBranch(BinaryTreeNode*, stack<BinaryTreeNode*>&);

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹中序遍歷算法(迭代版#1)
{
    stack<BinaryTreeNode*> S; //輔助棧

    while (true)
    {
        goAlongLeftBranch(pRoot, S);  //從當前節點出發,逐批入棧
        if (S.empty()) break;  //直至所有節點處理完畢
        pRoot = S.top();  //彈出棧頂節點並訪問
        S.pop();
        treeNodes.push_back(pRoot->m_nValue);
        pRoot = pRoot->m_pRight;  //轉向右子樹
    }
}

//從當前節點出發, 沿左分支不斷深入, 直至沒有左分支的節點
void goAlongLeftBranch(BinaryTreeNode* pRoot, stack<BinaryTreeNode*>& S)
{
    while (pRoot) //當前節點入棧后隨機向左側分支深入, 迭代到無左子節點
    {
        S.push(pRoot);
        pRoot = pRoot->m_pLeft;
    }
}

// ====================測試代碼====================
void Test(const char* testName, BinaryTreeNode* pRoot, 
    vector<int> expectedPre, vector<int> expectedIn, vector<int> expectedPost, int expectedLength)
{
    if (testName != nullptr)
        printf("%s begins: ", testName);

    vector<int> treeNodes;  //保存遍歷值
    TraverseBinaryTree(pRoot, treeNodes);
    int length = treeNodes.size();

    bool flag = true;  //標志位
    if (length != expectedLength) flag = false;  //長度不一致, 則遍歷算法錯誤

    for (int i = 0; i < length; ++i)  //順序不一致, 則遍歷算法錯誤
    {
        if (treeNodes[i] != expectedIn[i])  //注意:遍歷期望值在這里改
            flag = false;
    }
    
    if (flag)
        printf("Passed.");
    else
        printf("Failed.");

    //打印遍歷值
    printf("\nExpected: ");
    for (int i = 0; i < expectedLength; ++i)
        printf("%d ", expectedIn[i]);  //注意:遍歷期望值在這里改

    printf("\nActual:   ");
    for (int i = 0; i < length; ++i)
        printf("%d ", treeNodes[i]);
    printf("\n\n");
}

// 1.滿二叉樹
//            10
//          /    \
//         6      14
//        /\      /\
//       4  8   12  16
void Test1()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);
    BinaryTreeNode* pNode16 = CreateBinaryTreeNode(16);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, pNode16);

    vector<int> expectedPre = {10, 6, 4, 8, 14, 12, 16};
    vector<int> expectedIn = {4, 6, 8, 10, 12, 14, 16};
    vector<int> expectedPost = {4, 8, 6, 12, 16, 14, 10};

    Test("Test1", pNode10, expectedPre, expectedIn, expectedPost, 7);

    DestroyTree(pNode10);
}

// 2.完全二叉樹
//            10
//          /    \
//         6      14
//        /\      /
//       4  8   12
void Test2()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, nullptr);

    vector<int> expectedPre = { 10, 6, 4, 8, 14, 12};
    vector<int> expectedIn = { 4, 6, 8, 10, 12, 14};
    vector<int> expectedPost = { 4, 8, 6, 12, 14, 10 };

    Test("Test2", pNode10, expectedPre, expectedIn, expectedPost, 6);

    DestroyTree(pNode10);
}

// 3.二叉樹
//            10
//          /    \
//         6      14
//         \      /
//          8   12  
//         /
//        4
void Test3()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, nullptr , pNode8);
    ConnectTreeNodes(pNode8, pNode4, nullptr);
    ConnectTreeNodes(pNode14, pNode12, nullptr);

    vector<int> expectedPre = { 10, 6, 8, 4, 14, 12 };
    vector<int> expectedIn = { 6, 4, 8, 10, 12, 14 };
    vector<int> expectedPost = { 4, 8, 6, 12, 14, 10 };

    Test("Test3", pNode10, expectedPre, expectedIn, expectedPost, 6);

    DestroyTree(pNode10);
}

// 4.只有最左側通路
//               5
//              /
//             4
//            /
//           3
//          /
//         2
//        /
//       1
void Test4()
{
    BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
    BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);

    ConnectTreeNodes(pNode5, pNode4, nullptr);
    ConnectTreeNodes(pNode4, pNode3, nullptr);
    ConnectTreeNodes(pNode3, pNode2, nullptr);
    ConnectTreeNodes(pNode2, pNode1, nullptr);

    vector<int> expectedPre = {5, 4, 3, 2, 1};
    vector<int> expectedIn = {1, 2, 3, 4, 5};
    vector<int> expectedPost = {1, 2, 3, 4, 5};

    Test("Test4", pNode5, expectedPre, expectedIn, expectedPost, 5);

    DestroyTree(pNode5);
}

// 4.只有最右側通路
// 1
//  \
//   2
//    \
//     3
//      \
//       4
//        \
//         5
void Test5()
{
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);
    BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
    BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);

    ConnectTreeNodes(pNode1, nullptr, pNode2);
    ConnectTreeNodes(pNode2, nullptr, pNode3);
    ConnectTreeNodes(pNode3, nullptr, pNode4);
    ConnectTreeNodes(pNode4, nullptr, pNode5);

    vector<int> expectedPre = {1, 2, 3, 4, 5};
    vector<int> expectedIn = { 1, 2, 3, 4, 5 };
    vector<int> expectedPost = {5, 4, 3, 2, 1};

    Test("Test5", pNode1, expectedPre, expectedIn, expectedPost, 5);

    DestroyTree(pNode1);
}

// 樹中只有1個結點
void Test6()
{
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);

    vector<int> expectedPre = {1};
    vector<int> expectedIn = {1};
    vector<int> expectedPost = {1};

    Test("Test6", pNode1, expectedPre, expectedIn, expectedPost, 1);

    DestroyTree(pNode1);
}

// 樹中沒有結點
void Test7()
{
    vector<int> expectedPre = {};
    vector<int> expectedIn = {};
    vector<int> expectedPost = {};

    Test("Test7", nullptr, expectedPre, expectedIn, expectedPost, 0);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();

    return 0;
}
中序遍歷測試代碼

2.1 基於遞歸實現

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹中序遍歷算法(遞歸版)
{
    if (pRoot == nullptr)
        return;

    TraverseBinaryTree(pRoot->m_pLeft, treeNodes);
    treeNodes.push_back(pRoot->m_nValue);
    TraverseBinaryTree(pRoot->m_pRight, treeNodes);
}

2.2 基於迭代實現

void goAlongLeftBranch(BinaryTreeNode*, stack<BinaryTreeNode*>&);

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹中序遍歷算法(迭代版#1)
{
    stack<BinaryTreeNode*> S; //輔助棧

    while (true)
    {
        goAlongLeftBranch(pRoot, S);  //從當前節點出發,逐批入棧
        if (S.empty()) break;  //直至所有節點處理完畢
        pRoot = S.top();  //彈出棧頂節點並訪問
        S.pop();
        treeNodes.push_back(pRoot->m_nValue);
        pRoot = pRoot->m_pRight;  //轉向右子樹
    }
}

//從當前節點出發, 沿左分支不斷深入, 直至沒有左分支的節點
void goAlongLeftBranch(BinaryTreeNode* pRoot, stack<BinaryTreeNode*>& S)
{
    while (pRoot) //當前節點入棧后隨即向左側分支深入, 迭代到無左子節點
    {
        S.push(pRoot);
        pRoot = pRoot->m_pLeft;
    }
}
void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹中序遍歷算法(迭代版#2)
{
    stack<BinaryTreeNode*> S; //輔助棧

    while (true)
    {
        if (pRoot)
        {
            S.push(pRoot);  //根節點進棧
            pRoot = pRoot->m_pLeft;  //深入遍歷左子樹
        }
        else if (!S.empty())
        {
            pRoot = S.top();  //尚未訪問的最低祖先節點退棧
            S.pop();
            treeNodes.push_back(pRoot->m_nValue);
            pRoot = pRoot->m_pRight;  //轉向右子樹
        }
        else
            break;
    }
}

 

3. 后序遍歷

后序遍歷:先遍歷左子樹,再遍歷右子樹,最后遍歷根節點(左-右-根)

 測試代碼:

// 二叉樹的三種遍歷
// 1.前序遍歷
// 2.中序遍歷
// 3.后序遍歷

#include <cstdio>
#include <stack>
#include <vector>
#include "BinaryTree.h"

using namespace std;

void gotoHLVFL(stack<BinaryTreeNode*>&);

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹后序遍歷算法(迭代版)
{
    stack<BinaryTreeNode*> S; //輔助棧

    if (pRoot)
        S.push(pRoot);  //根節點進棧

    while (!S.empty())
    {
        if ((S.top()->m_pLeft != pRoot)  // 若棧頂非當前節點的父節點(必為其右兄)
            && (S.top()->m_pRight != pRoot))  // 在以其右兄為根的子樹中, 找到HLVFL
            gotoHLVFL(S);

        pRoot = S.top(); S.pop();
        if (pRoot)
            treeNodes.push_back(pRoot->m_nValue);
    }
}

// 在以S棧頂節點為根的子樹中, 找到最高左側可見節點
void gotoHLVFL(stack<BinaryTreeNode*>& S)
{
    while (BinaryTreeNode* pRoot = S.top())  // 自頂向下, 反復檢查當前節點(即棧頂)
    {
        if (pRoot->m_pLeft) // 盡可能向左
        {
            if (pRoot->m_pRight)  //若有右子節點, 優先入棧
                S.push(pRoot->m_pRight);
            S.push(pRoot->m_pLeft);  //然后轉入左子節點
        }
        else  //只有右子節點
            S.push(pRoot->m_pRight);
    }
    S.pop();
}


// ====================測試代碼====================
void Test(const char* testName, BinaryTreeNode* pRoot, 
    vector<int> expectedPre, vector<int> expectedIn, vector<int> expectedPost, int expectedLength)
{
    if (testName != nullptr)
        printf("%s begins: ", testName);

    vector<int> treeNodes;  //保存遍歷值
    TraverseBinaryTree(pRoot, treeNodes);
    int length = treeNodes.size();

    bool flag = true;  //標志位
    if (length != expectedLength) flag = false;  //長度不一致, 則遍歷算法錯誤

    for (int i = 0; i < length; ++i)  //順序不一致, 則遍歷算法錯誤
    {
        if (treeNodes[i] != expectedPost[i])  //注意:遍歷期望值在這里改
            flag = false;
    }
    
    if (flag)
        printf("Passed.");
    else
        printf("Failed.");

    //打印遍歷值
    printf("\nExpected: ");
    for (int i = 0; i < expectedLength; ++i)
        printf("%d ", expectedPost[i]);  //注意:遍歷期望值在這里改

    printf("\nActual:   ");
    for (int i = 0; i < length; ++i)
        printf("%d ", treeNodes[i]);
    printf("\n\n");
}

// 1.滿二叉樹
//            10
//          /    \
//         6      14
//        /\      /\
//       4  8   12  16
void Test1()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);
    BinaryTreeNode* pNode16 = CreateBinaryTreeNode(16);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, pNode16);

    vector<int> expectedPre = {10, 6, 4, 8, 14, 12, 16};
    vector<int> expectedIn = {4, 6, 8, 10, 12, 14, 16};
    vector<int> expectedPost = {4, 8, 6, 12, 16, 14, 10};

    Test("Test1", pNode10, expectedPre, expectedIn, expectedPost, 7);

    DestroyTree(pNode10);
}

// 2.完全二叉樹
//            10
//          /    \
//         6      14
//        /\      /
//       4  8   12
void Test2()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, nullptr);

    vector<int> expectedPre = { 10, 6, 4, 8, 14, 12};
    vector<int> expectedIn = { 4, 6, 8, 10, 12, 14};
    vector<int> expectedPost = { 4, 8, 6, 12, 14, 10 };

    Test("Test2", pNode10, expectedPre, expectedIn, expectedPost, 6);

    DestroyTree(pNode10);
}

// 3.二叉樹
//            10
//          /    \
//         6      14
//         \      /
//          8   12  
//         /
//        4
void Test3()
{
    BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
    BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
    BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14);
    BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, nullptr , pNode8);
    ConnectTreeNodes(pNode8, pNode4, nullptr);
    ConnectTreeNodes(pNode14, pNode12, nullptr);

    vector<int> expectedPre = { 10, 6, 8, 4, 14, 12 };
    vector<int> expectedIn = { 6, 4, 8, 10, 12, 14 };
    vector<int> expectedPost = { 4, 8, 6, 12, 14, 10 };

    Test("Test3", pNode10, expectedPre, expectedIn, expectedPost, 6);

    DestroyTree(pNode10);
}

// 4.只有最左側通路
//               5
//              /
//             4
//            /
//           3
//          /
//         2
//        /
//       1
void Test4()
{
    BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
    BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);

    ConnectTreeNodes(pNode5, pNode4, nullptr);
    ConnectTreeNodes(pNode4, pNode3, nullptr);
    ConnectTreeNodes(pNode3, pNode2, nullptr);
    ConnectTreeNodes(pNode2, pNode1, nullptr);

    vector<int> expectedPre = {5, 4, 3, 2, 1};
    vector<int> expectedIn = {1, 2, 3, 4, 5};
    vector<int> expectedPost = {1, 2, 3, 4, 5};

    Test("Test4", pNode5, expectedPre, expectedIn, expectedPost, 5);

    DestroyTree(pNode5);
}

// 4.只有最右側通路
// 1
//  \
//   2
//    \
//     3
//      \
//       4
//        \
//         5
void Test5()
{
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);
    BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
    BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
    BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
    BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);

    ConnectTreeNodes(pNode1, nullptr, pNode2);
    ConnectTreeNodes(pNode2, nullptr, pNode3);
    ConnectTreeNodes(pNode3, nullptr, pNode4);
    ConnectTreeNodes(pNode4, nullptr, pNode5);

    vector<int> expectedPre = {1, 2, 3, 4, 5};
    vector<int> expectedIn = { 1, 2, 3, 4, 5 };
    vector<int> expectedPost = {5, 4, 3, 2, 1};

    Test("Test5", pNode1, expectedPre, expectedIn, expectedPost, 5);

    DestroyTree(pNode1);
}

// 樹中只有1個結點
void Test6()
{
    BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1);

    vector<int> expectedPre = {1};
    vector<int> expectedIn = {1};
    vector<int> expectedPost = {1};

    Test("Test6", pNode1, expectedPre, expectedIn, expectedPost, 1);

    DestroyTree(pNode1);
}

// 樹中沒有結點
void Test7()
{
    vector<int> expectedPre = {};
    vector<int> expectedIn = {};
    vector<int> expectedPost = {};

    Test("Test7", nullptr, expectedPre, expectedIn, expectedPost, 0);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();

    return 0;
}
后序遍歷測試代碼

3.1 基於遞歸實現

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹后序遍歷算法(遞歸版)
{
    if (pRoot == nullptr)
        return;

    //后序遍歷
    TraverseBinaryTree(pRoot->m_pLeft, treeNodes);
    TraverseBinaryTree(pRoot->m_pRight, treeNodes);
    treeNodes.push_back(pRoot->m_nValue);
}

3.2 基於迭代實現

void gotoHLVFL(stack<BinaryTreeNode*>&);

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹后序遍歷算法(迭代版)
{
    stack<BinaryTreeNode*> S; //輔助棧

    if (pRoot)
        S.push(pRoot);  //根節點進棧

    while (!S.empty())
    {
        if ((S.top()->m_pLeft != pRoot)  // 若棧頂非當前節點的父節點(必為其右兄)
            && (S.top()->m_pRight != pRoot))  // 在以其右兄為根的子樹中, 找到HLVFL
            gotoHLVFL(S);

        pRoot = S.top(); S.pop();
        if (pRoot)
            treeNodes.push_back(pRoot->m_nValue);
    }
}

// 在以S棧頂節點為根的子樹中, 找到最高左側可見節點
void gotoHLVFL(stack<BinaryTreeNode*>& S)
{
    while (BinaryTreeNode* pRoot = S.top())  // 自頂向下, 反復檢查當前節點(即棧頂)
    {
        if (pRoot->m_pLeft) // 盡可能向左
        {
            if (pRoot->m_pRight)  //若有右子節點, 優先入棧
                S.push(pRoot->m_pRight);
            S.push(pRoot->m_pLeft);  //然后轉入左子節點
        }
        else  //只有右子節點
            S.push(pRoot->m_pRight);
    }
    S.pop();
}

 

4. 層次遍歷

 

 

void TraverseBinaryTree(BinaryTreeNode* pRoot, vector<int>& treeNodes)  //二叉樹層次遍歷算法(迭代版)
{
    queue<BinaryTreeNode*> Q; //輔助棧

    Q.push(pRoot);  //根節點進棧

    while (!Q.empty())  //隊列變空之前反復迭代
    {
        BinaryTreeNode* pRoot = Q.front();  //取出首節點並訪問
        treeNodes.push_back(pRoot->m_nValue);

        if (pRoot->m_pLeft)
            Q.push(pRoot->m_pLeft);

        if (pRoot->m_pRight)
            Q.push(pRoot->m_pRight);
    }
}

可以參考之字形打印二叉樹

https://www.cnblogs.com/ZSY-blog/p/12602375.html

 

調用代碼:

//==================================================================
// 《劍指Offer——名企面試官精講典型編程題》代碼
// 作者:何海濤
//==================================================================

#pragma once

struct BinaryTreeNode 
{
    int                    m_nValue; //節點data值
    BinaryTreeNode*        m_pLeft;  //左子節點
    BinaryTreeNode*        m_pRight; //右子節點
};

__declspec( dllexport ) BinaryTreeNode* CreateBinaryTreeNode(int value);
__declspec( dllexport ) void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight);
__declspec( dllexport ) void PrintTreeNode(const BinaryTreeNode* pNode);
__declspec( dllexport ) void PrintTree(const BinaryTreeNode* pRoot);
__declspec( dllexport ) void DestroyTree(BinaryTreeNode* pRoot);
BinaryTree.h
//==================================================================
// 《劍指Offer——名企面試官精講典型編程題》代碼
// 作者:何海濤
//==================================================================

#include <cstdio>
#include "BinaryTree.h"

//新建一個父節點
BinaryTreeNode* CreateBinaryTreeNode(int value)
{
    BinaryTreeNode* pNode = new BinaryTreeNode();
    pNode->m_nValue = value;
    pNode->m_pLeft = nullptr;
    pNode->m_pRight = nullptr;

    return pNode;
}

//父節點連接左右子節點
void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight)
{
    if(pParent != nullptr)
    {
        pParent->m_pLeft = pLeft;
        pParent->m_pRight = pRight;
    }
}

//打印當前父節點以及左右子節點
void PrintTreeNode(const BinaryTreeNode* pNode)
{
    if(pNode != nullptr)
    {
        printf("value of this node is: %d\n", pNode->m_nValue);

        if(pNode->m_pLeft != nullptr)
            printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
        else
            printf("left child is nullptr.\n");

        if(pNode->m_pRight != nullptr)
            printf("value of its right child is: %d.\n", pNode->m_pRight->m_nValue);
        else
            printf("right child is nullptr.\n");
    }
    else
    {
        printf("this node is nullptr.\n");
    }

    printf("\n");
}

//遞歸調用打印整個二叉樹
void PrintTree(const BinaryTreeNode* pRoot)
{
    PrintTreeNode(pRoot);

    if(pRoot != nullptr)
    {
        if(pRoot->m_pLeft != nullptr)
            PrintTree(pRoot->m_pLeft);

        if(pRoot->m_pRight != nullptr)
            PrintTree(pRoot->m_pRight);
    }
}

//遞歸調用刪除整個樹
void DestroyTree(BinaryTreeNode* pRoot)
{
    if(pRoot != nullptr)
    {
        BinaryTreeNode* pLeft = pRoot->m_pLeft;
        BinaryTreeNode* pRight = pRoot->m_pRight;

        delete pRoot;
        pRoot = nullptr;

        DestroyTree(pLeft);
        DestroyTree(pRight);
    }
}
BinaryTree.cpp

 

代碼與圖參考:

[1] 劍指offer(第二版), 何海濤, 2011.

[2] 數據結構(C++語言版), 鄧俊輝, 2010.

 


免責聲明!

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



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