数据结构 | 二叉树的概念及前中后序遍历(二)

简介: 数据结构 | 二叉树的概念及前中后序遍历(二)

数据结构 | 二叉树的概念及前中后序遍历(一):https://developer.aliyun.com/article/1426944

五、二叉树的性质

  1. 每个节点最多有两个子节点: 每个节点最多有两个子节点,左子节点和右子节点。
  2. 每个节点有零个、一个或两个子节点: 这意味着一个节点可以是叶节点(没有子节点)、有一个子节点,或者有两个子节点。
  3. 左子树和右子树是有序的: 对于二叉搜索树(BST),左子树中的每个节点的值都小于该节点的值,右子树中的每个节点的值都大于该节点的值。
  4. 树的高度: 树的高度是从根节点到最深叶节点的最长路径。一棵有n个节点的二叉树的高度最多为n,最少为log₂(n+1)。
  5. 最后一层节点集中在左侧: 在完全二叉树中,最后一层的节点从左到右排列,缺失的位置只会出现在最右边。
  6. 满二叉树: 一棵高度为h且有2^h - 1个节点的二叉树被称为满二叉树。
  7. 最后一层节点集中在左侧: 在完全二叉树中,最后一层的节点从左到右排列,缺失的位置只会出现在最右边。
  8. 满二叉树: 一棵高度为h且有2^h - 1个节点的二叉树被称为满二叉树。

六、二叉树的存储结构

6.1 顺序存储结构

  • 在顺序存储结构中,使用数组来表示二叉树。具体的方式是按照从上到下、从左到右的顺序将二叉树的节点依次存储在数组中。如果一个节点的编号为i,则其左子节点的编号为2i,右子节点的编号为2i+1。

例如:

1
       / \
      2   3
     / \ / \
    4  5 6  7
  • 对应的顺序存储结构为:
[1, 2, 3, 4, 5, 6, 7]
  • 这里数组的索引从1开始,根节点对应索引1,而左子节点和右子节点的关系则按照 2i 和 2i+1 的规则排列。

6.2 链式存储结构

  • 在链式存储结构中,每个节点通过指针或引用指向其左子节点和右子节点。这样的存储结构更加直观,也更容易实现。节点的定义如下:
struct TreeNode {
    int data; // 节点的数据
    TreeNode* left; // 指向左子节点的指针
    TreeNode* right; // 指向右子节点的指针
};
      1
       / \
      2   3
     / \ / \
    4  5 6  7

每个节点的 leftright 指针分别指向其左子节点和右子节点。这种存储结构更直观,但相对于顺序存储结构,可能会占用更多的内存空间。

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
  struct BinTreeNode* _pLeft; // 指向当前节点左孩子
  struct BinTreeNode* _pRight; // 指向当前节点右孩子
  BTDataType _data; // 当前节点值域
}
// 三叉链
struct BinaryTreeNode
{
  struct BinTreeNode* _pParent; // 指向当前节点的双亲
  struct BinTreeNode* _pLeft; // 指向当前节点左孩子
  struct BinTreeNode* _pRight; // 指向当前节点右孩子
  BTDataType _data; // 当前节点值域
};

6.3 二叉树的顺序结构及实现

  • 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

七、二叉树链式结构的实现

  • 在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。
  • 我们先回顾一下二叉树的概念:
  1. 空树
  2. 非空:根节点,根节点的左子树、根节点的右子树组成的。

从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。

八、二叉树的遍历【重点】

8.1 前序、中序以及后序遍历

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。简单来说就是访问顺序就是根 左子树 右子树
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。简单来说就是访问顺序就是 左子树 根 右子树
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。简单来说就是访问顺序就是 左子树 右子树 根

构建一棵树

BTNode* BuyTreeNode(int x)
{
  BTNode*node = (BTNode*)malloc(sizeof(BTNode));
  assert(node);
  node->data = x;
  node->left = NULL;
  node->right = NULL;
  return node;
}
BTNode* CreateTree()
{
  BTNode* node1 = BuyTreeNode(1);
  BTNode* node2 = BuyTreeNode(2);
  BTNode* node3 = BuyTreeNode(3);
  BTNode* node4 = BuyTreeNode(4);
  BTNode* node5 = BuyTreeNode(5);
  BTNode* node6 = BuyTreeNode(6);
  node1->left = node2;
  node1->right = node4;
  node2->left = node3;
  node4->left = node5;
  node4->right = node6;
  return node1;
}

二叉树的前序遍历

void BinaryTreePrevOrder(BTNode* root)
{
  if (root == NULL)
  {
    printf("NULL ");
    return;
  }
  printf("%d ", root->data);
  BinaryTreePrevOrder(root->left);
  BinaryTreePrevOrder(root->right);
}

二叉树中序遍历

void BinaryTreeInOrder(BTNode* root)
{
  if (root == NULL)
  {
    printf("NULL ");
    return;
  }
  BinaryTreeInOrder(root->left);
  printf("%d ", root->data);
  BinaryTreeInOrder(root->right);
}

二叉树后序遍历

void BinaryTreePostOrder(BTNode* root)
{
  if (root == NULL)
  {
    printf("NULL ");
    return;
  }
  BinaryTreePostOrder(root->left);
  BinaryTreePostOrder(root->right);
  printf("%d ", root->data);
}

测试

int main()
{
  BTNode* root = CreateTree();
  printf("二叉树前序遍历:\n");
  BinaryTreePrevOrder(root);
  printf("\n");
  printf("二叉树中序遍历:\n");
  BinaryTreeInOrder(root);
  printf("\n");
  printf("二叉树后序遍历:\n");
  BinaryTreePostOrder(root);
  printf("\n");
  return 0;
}
{

c6e59771153f1b9e5fa028fc6132c437_516bdb2b34134cbeb4977c7013f0314c.png

相关文章
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
546 10
 算法系列之数据结构-二叉树
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
620 12
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
369 10
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
790 3
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
机器学习/深度学习 存储 算法
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
510 4
|
数据采集 存储 算法
【C++数据结构——图】图的遍历(头歌教学实验平台习题) 【合集】
本文介绍了图的遍历算法,包括深度优先遍历(DFS)和广度优先遍历(BFS)。深度优先遍历通过递归方式从起始节点深入探索图,适用于寻找路径、拓扑排序等场景;广度优先遍历则按层次逐层访问节点,适合无权图最短路径和网络爬虫等应用。文中提供了C++代码示例,演示了如何实现这两种遍历方法,并附有测试用例及结果,帮助读者理解和实践图的遍历算法。
948 0
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
474 59
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
1221 77
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
316 0
栈区的非法访问导致的死循环(x64)

热门文章

最新文章