学习的二叉树遍历方式有四种:前序遍历、中序遍历、后序遍历、层序遍历

也比较简单,复习下就ok了。

        A
       / \
      B   C
     / \   \
    D   E   F

1. 前序遍历

顺序是:

根 → 左 → 右

对示例二叉树进行前序遍历:

A → B → D → E → C → F

先访问自己,再访问左边,最后访问右边。

递归代码:

void preOrder(const BiTree &T) {
    if (T != nullptr) {
        std::cout << T->data << " ";
        preOrder(T->lchild);
        preOrder(T->rchild);
    }
}

2. 中序遍历

顺序是:

左 → 根 → 右

遍历结果:

D → B → E → A → C → F

先访问左边,再访问自己,最后访问右边。

递归代码:

void inOrder(const BiTree &T) {
    if (T != nullptr) {
        inOrder(T->lchild);
        std::cout << T->data << " ";
        inOrder(T->rchild);
    }
}

中序遍历有一个重要特点:如果二叉树是二叉搜索树,中序遍历得到的通常是从小到大的有序序列。

3. 后序遍历

顺序是:

左 → 右 → 根

遍历结果:

D → E → B → F → C → A

先处理左右子节点,最后处理自己。

递归代码:

void PostOrder(const BiTree &T) {
    if (T != nullptr) {
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        std::cout << T->data << " ";
    }
}

后序遍历适合处理“先处理子节点,再处理父节点”的问题,例如计算文件夹大小、删除整棵树等。

4. 层序遍历

层序遍历是按照树的层级,从上到下、从左到右访问:

第一层:A
第二层:B、C
第三层:D、E、F

最终结果:

A → B → C → D → E → F

层序遍历通常使用队列实现:

void LevelOrder(const BiTree &T) {
    if (T == nullptr) {
        return;
    }

    std::queue<BiTree> Q;   //创建一个队列
    Q.push(T);

    while (!Q.empty()) {    
        //队列不为空就一直循环,节点进入队列的同时将节点的左右孩子入列
        if (Q.front()->lchild != nullptr) {
            Q.push(Q.front()->lchild);
        }

        if (Q.front()->rchild != nullptr) {
            Q.push(Q.front()->rchild);
        }

        std::cout << Q.front()->data << " ";
        Q.pop();
    }
}

注意:无论是前序、中序还是后序,通常都是先左子树,后右子树,变化的只是根节点的位置。


完整代码:

#include <iostream>
#include <queue>

using ElemType = char;

struct BiTNode {
    struct BiTNode* lchild;
    struct BiTNode* rchild;
    ElemType data;
};

using BiTree = BiTNode*;

BiTNode* createNode(ElemType data) {
    BiTNode* node = new BiTNode;
    node->data = data;
    node->lchild = nullptr;
    node->rchild = nullptr;
    return node;
}

void preOrder(const BiTree &T) {
    //前置遍历
    if (T != nullptr) {
        std::cout << T->data << " ";
        preOrder(T->lchild);
        preOrder(T->rchild);
    }
}

void inOrder(const BiTree &T) {
    //中置遍历
    if (T != nullptr) {
        inOrder(T->lchild);
        std::cout << T->data << " ";
        inOrder(T->rchild);
    }
}

void PostOrder(const BiTree &T) {
    //后置遍历
    if (T != nullptr) {
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        std::cout << T->data << " ";
    }
}

void LevelOrder(const BiTree &T) {
    //层级遍历
    if (T == nullptr) {
        return;
    }

    std::queue<BiTree> Q;   //创建一个队列
    Q.push(T);

    while (!Q.empty()) {    
        //队列不为空就一直循环,节点进入队列的同时将节点的左右孩子入列
        if (Q.front()->lchild != nullptr) {
            Q.push(Q.front()->lchild);
        }

        if (Q.front()->rchild != nullptr) {
            Q.push(Q.front()->rchild);
        }

        std::cout << Q.front()->data << " ";
        Q.pop();
    }
}

void destroyTree(BiTree node) {
    //后置遍历释放内存,先释放左子树,后右子树,最后释放根节点
    if (node != nullptr) {
        destroyTree(node->lchild); 
        destroyTree(node->rchild); 
        delete node;               
    }
}

int main() {
    //           A
    //         /   \
    //        B     C
    //       / \   / \
    //      D   E F   G

    BiTNode* A = createNode('A');
    BiTNode* B = createNode('B');
    BiTNode* C = createNode('C');
    BiTNode* D = createNode('D');
    BiTNode* E = createNode('E');
    BiTNode* F = createNode('F');
    BiTNode* G = createNode('G');

    A->lchild = B;  A->rchild = C; 
    B->lchild = D;  B->rchild = E; 
    C->lchild = F;  C->rchild = G; 

    std::cout << "前置遍历: ";
    preOrder(A);
    std::cout << std::endl;

    std::cout << "中置遍历: ";
    inOrder(A);
    std::cout << std::endl;

    std::cout << "后置遍历: ";
    PostOrder(A);
    std::cout << std::endl;

    std::cout << "层级遍历: ";
    LevelOrder(A);
    std::cout << std::endl;

    destroyTree(A);
    return 0;
}

输出结果:

前置遍历: A B D E C F G 
中置遍历: D B E A F C G 
后置遍历: D E B F G C A 
层级遍历: A B C D E F G 

最近睡眠相当不规律啊,再这样下去真要进入凉爽的夏夜了 _(┐「ε:)_

牢广