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);
        }
    }
}
相关推荐
晓蛋5 天前
c语言指的是什么意思
c语言·编译器·编程开发·集成开发环境·程序实例
倒头就睡的小比特5 天前
算法竞赛C++常用的STL
c++·算法
weilx12345 天前
C++笔记-文件IO-<fcntl.h>
c++
傲世仙尊5 天前
目录即文件-Ext文件系统收尾篇
linux·c语言
牵猫散步的鱼儿5 天前
重载、重写(覆盖)、重定义区别
c语言
phltxy5 天前
C 语言指针:从内存地址到灵活的数据访问
c语言
Smileyqp沛沛5 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
m0_547486665 天前
《数据结构教程》全套 PPT课件2026
数据结构
C语言小火车5 天前
C/C++ 为什么需要编译器?
开发语言·c++
phltxy5 天前
C 语言中的数据存储:从类型到二进制位
c语言