C/C++数据结构之二叉树的遍历

概述

二叉树的遍历是指按照某种规则访问二叉树中所有节点的过程。遍历不仅是理解二叉树结构的基础,也是实现各种树操作的前提。二叉树的遍历顺序主要由根节点的访问时机决定,从而形成了三种深度优先遍历方式:前序、中序和后序。此外,还有基于层次的广度优先遍历方式:层序遍历。

深度优先遍历的特点是:沿着树的深度尽可能深地搜索,直到到达叶子节点或无法继续为止,然后回溯。广度优先遍历的特点是:按照树的层次从上到下、从左到右依次访问节点。

深度前序遍历

深度前序遍历的核心特点是:先访问根节点,然后再递归地遍历左子树和右子树。具体访问顺序如下:

1、访问当前节点(根节点)。

2、递归遍历左子树。

3、递归遍历右子树。

考虑下面的二叉树,其前序遍历的结果为:1 → 2 → 4 → 5 → 3。

cpp 复制代码
    1
   / \
  2   3
 / \
4   5

递归法是实现深度前序遍历最直观、最简洁的方式,直接体现了前序遍历的定义,示例代码如下。

cpp 复制代码
void PreorderTree(TreeNode* pRoot)
{
    if (pRoot == NULL)
    {
        return;
    }

    cout << pRoot->nData << " ";

    PreorderTree(pRoot->pLeft);

    PreorderTree(pRoot->pRight);
}

深度前序遍历的时间复杂度为O(n),其中n是树中节点的数量,每个节点恰好被访问一次。空间复杂度为O(h),其中h是树的高度。

深度中序遍历

深度中序遍历的核心特点是:在遍历完左子树后访问根节点,然后再遍历右子树。具体访问顺序如下:

1、递归遍历左子树。

2、访问当前节点(根节点)。

3、递归遍历右子树。

考虑下面的二叉树,其中序遍历的结果为:1 → 2 → 3 → 4 → 5 → 6 → 7。

cpp 复制代码
    4
   / \
  2   6
 / \ / \
1  3 5  7

深度前序遍历采用了递归的方法实现,这里我们采用迭代法来实现深度中序遍历,示例代码如下。

cpp 复制代码
void InorderTreeIterative(TreeNode* pRoot)
{
    stack<TreeNode*> nodeStack;
    TreeNode* pCurrent = pRoot;

    while (pCurrent != NULL || !nodeStack.empty())
    {
        // 一直向左走到底,将路径上的节点压入栈
        while (pCurrent != NULL)
        {
            nodeStack.push(pCurrent);
            pCurrent = pCurrent->pLeft;
        }

        // 此时pCurrent为空,说明到达最左节点
        pCurrent = nodeStack.top();
        nodeStack.pop();

        // 访问该节点
        cout << pCurrent->nData << " ";

        // 转向右子树
        pCurrent = pCurrent->pRight;
    }
}

深度后序遍历

深度后序遍历的核心特点是:最后访问根节点,在遍历完左右子树之后才访问当前节点。具体访问顺序如下:

1、递归遍历左子树。

2、递归遍历右子树。

3、访问当前节点(根节点)。

考虑下面的二叉树,其后序遍历的结果为:4 → 5 → 2 → 3 → 1。

cpp 复制代码
    1
   / \
  2   3
 / \
4   5

使用递归法实现深度后续遍历相对比较简单,可参考下面的示例代码。

cpp 复制代码
void PostorderTree(TreeNode* pRoot)
{
    if (pRoot == NULL) 
    {
        return;
    }

    PostorderTree(pRoot->pLeft);

    PostorderTree(pRoot->pRight);

    cout << pRoot->nData << " ";
}

广度层序遍历

广度层序遍历的核心特点是:按层次访问,从根节点开始,逐层向下,每层从左到右访问所有节点。具体访问顺序如下:

1、访问第1层(根节点)。

2、访问第2层(根的子节点)。

3、访问第3层(第2层节点的子节点)。

4、依此类推,直到最后一层。

考虑下面的二叉树,其层序遍历的结果为:1 → 2 → 3 → 4 → 5 → 6 → 7。

cpp 复制代码
    1
   / \
  2   3
 / \   \
4   5   6
     \
      7

广度层序遍历推荐使用迭代法来实现,最自然的实现方式是使用队列数据结构,遵循"先进先出"的原则,示例代码如下。

cpp 复制代码
void LevelOrder(TreeNode* pRoot)
{
    if (pRoot == NULL)
    {
        return;
    }

    queue<TreeNode*> nodeQueue;
    nodeQueue.push(pRoot);

    while (!nodeQueue.empty())
    {
        // 取出队首节点
        TreeNode* pCurrent = nodeQueue.front();
        nodeQueue.pop();

        // 访问当前节点
        cout << pCurrent->nData << " ";

        // 将左子节点入队(如果存在)
        if (pCurrent->pLeft != NULL)
        {
            nodeQueue.push(pCurrent->pLeft);
        }

        // 将右子节点入队(如果存在)
        if (pCurrent->pRight != NULL)
        {
            nodeQueue.push(pCurrent->pRight);
        }
    }
}
相关推荐
CCCCCCCCharlie7 分钟前
深入解析I/O底层:文件描述符与缓冲区真相
linux·开发语言·c++·算法
自信1504130575917 分钟前
重生之从0开始学习c++之string(下)
c++·学习·stl
Cccp.12330 分钟前
【leetcode】(十三)大数据处理
数据结构·算法·leetcode
学逆向的31 分钟前
C 选择结构的执行效率分析
c语言·开发语言·算法·网络安全
Pniubi1 小时前
力扣70爬楼梯
数据结构·算法·leetcode
wuminyu1 小时前
Continuation::freeze与thaw的x86_64汇编Stack Chunk拆解源码分析
java·linux·c语言·汇编·jvm·c++
kunicoding1 小时前
C++ 策略模式实战:写一个可以“一键换输出“的日志系统
开发语言·c++·策略模式
xiaoye-duck2 小时前
《C++ 项目:手写大模型接入 SDK》项目背景、目标及名词解释
服务器·网络·c++·语言模型
艾莉丝努力练剑2 小时前
【AI大模型接入SDK】ChatServer接口设计规范
网络·c++·人工智能·学习·大模型·设计规范
纪念 2292 小时前
C++算法(三)
开发语言·c++·算法