二叉树的遍历方式(一)

179 阅读3分钟

什么是二叉树

    在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。(维基百科)

1-1.png 上图就是一棵二叉树,我们有四种遍历方式来遍历每一个节点,分别为先序遍历、后序遍历、中序遍历、层序遍历。

二叉树先序遍历

先序遍历二叉树,先访问根节点,再到左子节点,最后是右子节点,上图的访问顺序是0->1->3->4->2->5->6。

使用递归的方案来遍历: MTVideo.GIF

上面动态图是整个遍历的流程

1-2.png

开始遍历根节点,将根节点放入容器中;

1-3.png

接下来访问根节点的左子节点,将子节点放入容器中;

1-4.png

访问1节点的左子节点,将左子节点放入容器中;

1-5.png

3节点没有子节点,返回到1节点访问1节点的右子节点,将右子节点放入容器中;

1-6.png

4节点没有子节点,返回1节点,1节点已经遍历完,再往根节点返回,对根节点的右子节点进行遍历,将根节点的右子节点放入容器中;

1-7.png

访问2节点的左子节点,将左子节点放入容器中;

1-8.png

节点5没有子节点,返回到2节点,访问2节点的右子节点,将右子节点放入容器中;

1-9.png

整棵二叉树的前序遍历完成。

1-10.png

整体的遍历顺序。

LeetCode-144.二叉树的前序遍历为例子

企业微信截图_578487c4-b3be-4ac8-8099-1585f8da3908.png 遍历的代码如下:

class Solution {
public:
    void Search(TreeNode* pNode, vector<int>& vRes) {
        if(pNode == nullptr) {
            return ;
        }
        vRes.push_back(pNode->val);//遍历当前节点
        Search(pNode->left, vRes);//遍历左子节点
        Search(pNode->right, vRes);//遍历右子节点
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> vResult;
        vResult.clear();
        Search(root, vResult);
        return vResult;
    }
};

接下来讲解一下如何使用迭代的方式来进行前序遍历的。

dc7402988a9be9b0afa247f580aecfe4.gif

上图是动态流程。

1-1.png

需要存储结果的容器,使用栈来模拟递归的流程,红色框为遍历栈顶的元素。

1-2.png

将根节点0放入栈中;

1-3.png

开始进行对栈进行操作,栈顶元素是根节点,先访问根节点,根节点放入容器。

1-4.png

然后再进行对根节点子节点进行操作,因为栈的特性是后进选出,前序遍历的顺序是根节点,左子节点,最后右子节点,所以右子节点先进栈;

1-5.png

然后再是根节点的左子节点进栈;

1-6.png

1-7.png

1-8.png

栈顶1节点出栈,放入容器中; 然后将1节点的右子节点放入栈,再到左子节点进栈;

1-9.png

1-10.png

3节点出栈,放入容器,没有子节点,4节点操作一样;

1-11.png

1-12.png

1-13.png

2节点出栈,放入容器,再将右子节点进栈,左子节点进栈;

1-14.png

1-15.png

5节点、6节点出栈,放入容器,两个节点都没有子节点,最后栈为空时,就代表二叉树已经遍历完。

对应的实现代码如下:

class Solution {
public:

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> vResult;
        vResult.clear();
        stack<TreeNode*> s;//使用栈来模拟递归
        s.push(root);//
        while(!s.empty()) {
            TreeNode* pNode = s.top();
            s.pop();
            if(pNode != nullptr) {
                vResult.push_back(pNode->val);//当前节点
                s.push(pNode->right);//栈是先进先出,先将右子节点放入栈
                s.push(pNode->left);//最后放入左子节点,最后放入,下次迭代先访问
            }
        }
        return vResult;
    }
};