二叉树(4)——链式二叉树

1 二叉树的概念 

二叉树是

  1. 空树
  2. 非空:根节点,根节点的左子树、根节点的右子树组成的。
  • 二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。

2 二叉树的遍历

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

学习二叉树结构,最简单的方式就是遍历。所谓 二叉树遍历 (Traversal) 是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次 。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历

  1. 前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右子树之前。根 左子树 右子树
  2. 中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)。左子树 根 右子树
  3. 后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后。        左子树 右子树 根
  • 由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树
  • NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

要注意:空NULL才是结束条件,而不是叶子。 只有看到NULL了才不往下遍历。

2.2 二叉树链式结构的实现 

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

2.2.1 手动构建二叉树 

//二叉树节点结构体
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}TreeNode;//手动构建一个二叉树
TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));assert(node);//给出根节点,左右子树记为空node->data = x;node->left = NULL;node->right = NULL;return node;
}TreeNode* CreateTree()
{TreeNode* node1 = BuyTreeNode(1);TreeNode* node2 = BuyTreeNode(2);TreeNode* node3 = BuyTreeNode(3);TreeNode* node4 = BuyTreeNode(4);TreeNode* node5 = BuyTreeNode(5);TreeNode* node6 = BuyTreeNode(6);TreeNode* node7 = BuyTreeNode(7);//连接树node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;node5->right = node7;return node1;
}
  • 注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

2.2.2 二叉树遍历代码实现

//前序
void PrevOrder(TreeNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}//中序
void InOrder(TreeNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}//后序
void PostOrder(TreeNode* root)
{if (root == NULL){printf("N ");return;}PostOrder(root->left);//左PostOrder(root->right);//右printf("%d ", root->data);//根
}int main()
{TreeNode* root = CreateTree();// 二叉树前序遍历PreOrder(node);printf("\n");// 二叉树中序遍历InOrder(node);printf("\n");// 二叉树后序遍历PostOrder(node);}

前序遍历

递归理解:先进入函数,然后递归返回,直到全部返回完毕,函数结束。

中序遍历

 2.2.3 计算二叉树节点个数

方法一:遍历
问题解决
  • 下面这样可以吗?
int TreeSize(TreeNode* root)
{int size = 0;if (root == NULL){return 0;}++size;TreeSize(root->left);TreeSize(root->right);return size;
}


不可以。我们要知道,这样会递归出来很多个栈帧,而每一个栈帧都会创建一个新的size,最后size并没有实现累加。

针对以上问题,我们用静态static int size定义size可以解决问题:不把size放进栈帧,而是放进静态区。

  • 但如果我们再次调用一下函数,会发现size的值变成了14。这是为什么呢?

原因:局部的静态变量只会被初始化一次。静态局部变量生命周期是程序结束,如果我们重复调用TreeSize函数,它会以上一次的结果为初始值进行累加,那么节点个数就会成倍增长。

  • 如果每次用完将size置0呢?

也不可以,因为虽然局部静态变量的生命周期是在全局,但是它的作用域只在当前函数。而在函数里我们并不能找到地方将其置0。

根据以上问题,我们可以用全局变量,每次调用完函数以后将其置0即可。

代码实现
int size = 0;void TreeSize(TreeNode* root)
{if (root == NULL){return;}++size;TreeSize(root->left);TreeSize(root->right);
}int main()
{TreeNode* root = CreateTree();//输出节点个数size的值size = 0;TreeSize(root);printf("TreeSize:%d\n",size);size = 0;TreeSize(root);printf("TreeSize:%d\n", size);size = 0;TreeSize(root);printf("TreeSize:%d\n", size);return 0;
}

方法二:递归 (首选思路)
代码实现
int TreeSize(TreeNode* root)
{if (root == NULL){return 0;}return TreeSize(root->left) + TreeSize(root->right) + 1;
}int main()
{TreeNode* root = CreateTree();printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));
}

也可以用三目运算符简写如下 

int TreeSize(TreeNode* root)
{return root == NULL ? 0 : TreeSize(root->left) +TreeSize(root->right) + 1;
}
思路分析

可看成校长安排数 学校人数问题。 

要控制好子问题分治代码返回条件

  • 分治:根+左子树的节点个数+右子树的节点个数 
  • 返回条件:空树返回0


 2.2.4 计算二叉树叶子节点个数

  • 分治:左子树的叶子节点+右子树的叶子节点
  • 返回条件:若为空树返回0,若为叶子节点则返回1。
代码实现 
// 叶子节点的个数
int TreeLeafSize(TreeNode* root)
{// 空 返回0if (root == NULL)return 0;// 不是空,是叶子 返回1if (root->left == NULL&& root->right == NULL)return 1;// 不是空 也不是叶子  分治=左右子树叶子之和return TreeLeafSize(root->left) +TreeLeafSize(root->right);
}

2.2.5 计算二叉树的高度

  • 分治:左子树和右子树中高的子树+1(每一层都要进行筛选)
  • 返回条件:空树NULL返回0

代码实现
方法一
int TreeHeight(TreeNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
 方法二
#include<math.h>int TreeHeight(TreeNode* root)
{if (root == NULL)return 0;return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

注意:以下这种写法,在OJ里可能会过不去,因为如果数很多很多就会调用次数太多,有大量的重复计算,超出时间限制。

int TreeHeight(TreeNode* root)
{if (root == NULL){return 0;}return TreeHeight(root->left) > TreeHeight(root->right) ? TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}

 下一节我们继续讲解二叉树第K层的节点个数的代码实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/475768.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

N叉树的前序遍历

1.题目 这道题是2024-2-18的签到题&#xff0c;题目难度为简单。 考察的知识点为DFS算法&#xff08;树的前序遍历&#xff09;。 题目链接&#xff1a;N叉树的前序遍历 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历…

天锐绿盾 | 办公终端文件数据\资料防泄密软件

天锐绿盾是一款电脑文件防泄密软件&#xff0c;旨在帮助企业保护其敏感数据免受未经授权的访问和泄露。该软件采用先进的加密技术和文件监控机制&#xff0c;确保企业数据在存储、传输和使用过程中的安全性。 PC地址&#xff1a;https://isite.baidu.com/site/wjz012xr/2eae091…

华清作业day57

效果图&#xff1a; 头文件&#xff1a; #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t; #define PHY_LED1_ADDR 0X50006000 #define…

MySQL之json数据操作

1 MySQL之JSON数据 总所周知&#xff0c;mysql5.7以上提供了一种新的字段格式json&#xff0c;大概是mysql想把非关系型和关系型数据库一口通吃&#xff0c;所以推出了这种非常好用的格式&#xff0c;这样&#xff0c;我们的很多基于mongoDB的业务都可以用mysql去实现了。当然…

【JavaScript】输入输出语法

目录 一、输出语法 二、输入语法 一、输出语法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>D…

【c++】STL之stack和queue详解

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;掌握stack和queue库&#xff0c;了解deque库 >…

Junit测试套件(Test Suite)

0. 什么是测试套件 对多个测试类的统一执行 只有一个测试类 点击一下执行就好有 5个测试类 分别打开 挨个点执行有100个测试类 &#xff1f;&#xff1f;分别点开执行 为100个测试类创建一个测试套件&#xff0c;然后再执行一次测试套件 √ 一个测试套件“囊括“三个测试类…

数据在内存中的存储以及百度笔试题

目录 一.整型家族 什么是大小端存储&#xff08;百度笔试题&#xff09; 大端字节序存储 小端字节序存储 为什么要讨论大小端字节序存储 写一个程序判断是大端还是小端存储&#xff08;百度笔试题&#xff09; 思路&#xff1a;用1去判断&#xff0c;如果返回1则是小端&a…

SHERlocked93 的 2023 年终总结

工作之后感觉一年一年过的太快&#xff0c;没有个记录连回忆都无从回忆起&#xff0c;之前的年终总结&#xff1a; SHERlocked93 的 2022 年终总结SHERlocked93 的 2021 年终总结SHERlocked93 的 2020 年终总结SHERlocked93 的 2019 年终总结SHERlocked93 的 2018 年终总结SHER…

静态时序分析:SDC约束命令set_clock_latency详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 时钟的延迟可以使用set_clock_latency命令设置&#xff0c;这里的时钟延迟包括源延迟(source latency)&#xff0c;即时钟对象到时钟源对象&#xff08;时钟定义…

MyBatisPlus 整合 SpringBoot 遇见的问题

【异常】&#xff1a;Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘udf1’ in ‘field list’… SQL: SELECT id,oper_id,btch_id,udf1, FROM scan_cyber Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘udf1’ in ‘field list’; ,"messag…

CleanMyMac X好不好用?如何下载2024最新版本

CleanMyMac X是一款好用的系统优化软件&#xff0c;具有简洁的界面和多样的功能&#xff0c;能够支持系统垃圾、图片、邮件、iTunes清理&#xff0c;移除恶意软件&#xff0c;优化系统和释放多余空间等。 CleanMyMac X全新版下载如下: https://wm.makeding.com/iclk/?zoneid4…