【数据结构】树与二叉树遍历算法的应用(求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子)

目录

  • 求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子
    • 应用一:统计二叉树中叶子结点个数的算法
      • 写法一:使用静态变量
      • 写法二:传入 count 作为参数
      • 写法三:不使用额外变量
    • 应用二:二叉树存放表达式
    • 应用三:求二叉树的高
    • 应用四:复制二叉树
    • 应用五:二叉树的建立
    • 应用六:交换二叉树每个结点的左右孩子
      • Swap 函数(先序遍历):
      • Swap 函数(中序遍历)××× 不可行:
      • Swap 函数(后序遍历):
  • 求叶子节点个数、求树高、复制二叉树、创建二叉树完整代码示例

求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子

  1. 遍历二叉树的应用都是基于递归法实现的,递归的知识点以及例题可以参考文章: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)
  2. 树与二叉树知识点可参考:【数据结构】树与二叉树(递归法先序、中序、后序、层次遍历二叉树、二叉树的建立以及求树高的方法)

注:本文二叉树的结构体定义为(采用二叉链表的定义):
在这里插入图片描述

//采用二叉链表的定义
typedef struct TreeNode{int data;//数据域TreeNode *rchild;//右孩子指针TreeNode *lchild;//左孩子指针
}TreeNode, *BiTree;
//注意结构体名称别写错!!!

应用一:统计二叉树中叶子结点个数的算法

写法一:使用静态变量

  • 函数使用了一个静态局部变量 count 来统计叶子节点的数量。
  • 每次调用函数时,count 的值都会保持,并且在遇到叶子节点时自增。
int LeafCount(BiTree T){static int count=0; // 静态局部变量,保持在函数调用之间的值if(T){if((T->lchild==NULL)&&(T->rchild==NULL)){count++; // 每当遇到叶子节点,count自增}else{LeafCount(T->lchild);LeafCount(T->rchild);}}return count; // 返回叶子节点数
}

写法二:传入 count 作为参数

  • 函数将 count 作为参数传递,并通过引用进行修改。
int LeafCount(BiTree T, int &count) {if (T) {if (T->lchild == NULL && T->rchild == NULL)count++;else {LeafCount(T->lchild, count);LeafCount(T->rchild, count);}}return count;
}

写法三:不使用额外变量

  • 函数直接通过递归计算叶子节点的数量,不使用额外的变量。
  • 当遇到空树,返回 0;当遇到叶子节点,返回 1;否则,递归计算左右子树的叶子节点数,并返回它们的和。
int LeafCount3(BiTree T){  if (!T) return 0;	// 空树叶子结点个数为0if (!T->lchild && !T->rchild) return 1; // 找到一个叶节点return LeafCount3(T->lchild) + LeafCount3(T->rchild);	// 否则为左右叶子结点个数之和
}

应用二:二叉树存放表达式

二叉树存放表达式 :

波兰式: +*dj/e+hi
中缀表示: d*j+e/(h+i)
逆波兰式: dj*ehi+/+

在这里插入图片描述

应用三:求二叉树的高

求二叉树深度算法(后序遍历)
m a x { 左子树深度 + 1 ,右子树深度 + 1 } max\{左子树深度+1,右子树深度+1\} max{左子树深度+1,右子树深度+1}

算法实现原理:

  1. 函数 Get_Height 接收一个指向树节点的指针 node 作为参数,表示要计算高度的二叉树的根节点。

  2. 首先,检查传入的节点是否为空。如果是空节点(即 node == NULL),那么树的高度为 0,因此函数直接返回 0。

  3. 如果节点不为空,则进入递归过程。它通过分别递归调用 Get_Height 函数来计算左子树和右子树的高度。

  4. 递归的终止条件就是当遇到叶子节点时,即左子节点和右子节点都为 NULL,这时高度为 0。

  5. 在每一层递归中,通过比较左子树的高度和右子树的高度,选择其中较大的一个,然后加上根节点,就得到了以当前节点为根的子树的高度。

  6. 最终,根据左右子树的高度计算出的最大高度加上根节点,就是整棵树的高度。

  7. 然后,返回return Tree_Height这个树的高度。

//求二叉树的高
int Get_Height(TreeNode* node) {if (node == NULL) return 0;//终止条件:如果为空节点,返回0,表示高度为0int Left_Height = Get_Height(node->lchild);//递归求左子树高度int Right_Hegiht = Get_Height(node->rchild);//递归求右子树高度int Tree_Height = 1 + (Left_Height > Right_Height?Left_Height:Right_Height);//计算树高return Tree_Height;
}

应用四:复制二叉树

复制二叉树采用后序遍历的方法来实现的,具体实现原理如下:

  1. 结点生成GetTreeNode函数):

    • GetTreeNode函数用于创建一个二叉树的结点。
    • 它接收三个参数:
      • item:表示结点的数据值。
      • lptr:表示左子树的指针。
      • rptr:表示右子树的指针。
    • 在函数内部,它首先分配一个新的结点(Q)的内存空间。
    • 然后,将传入的数据值、左子树指针和右子树指针分别赋值给新结点的对应字段。
    • 最后,返回新创建的结点。
  2. 后序遍历CopyTree函数):

    • CopyTree函数用于复制一个二叉树。
    • 如果需要复制的二叉树的结点为空,直接返回NULL
    • 否则,递归地复制左子树和右子树:
      • 如果左子树非空,调用CopyTree函数复制左子树。
      • 如果右子树非空,调用CopyTree函数复制右子树。
    • 创建一个新的结点,将原结点的数据值、复制的左子树和复制的右子树分别赋值给新结点的对应字段。
    • 返回复制后的新二叉树。

代码示例:

// 生成一个二叉树的结点
TreeNode* GetTreeNode(int item, TreeNode *lptr , TreeNode *rptr ){BiTree Q;if ( !(Q = (TreeNode*)malloc(sizeof(TreeNode))) ) {exit(1);}Q-> data = item;Q-> lchild = lptr;    Q-> rchild = rptr;return Q;
}//后序遍历 
TreeNode *CopyTree(TreeNode *T) {  //如果需要复制的二叉树的结点为空 就直接退出 BiTree newlptr=NULL;BiTree newrptr=NULL;BiTree newT=NULL;if (!T)    return NULL;if (T->lchild ) newlptr = CopyTree(T->lchild);//复制左子树if (T->rchild ) newrptr = CopyTree(T->rchild);//复制右子树newT = GetTreeNode(T->data, newlptr, newrptr);return newT;
} // CopyTree

注意:在给定的代码中,CopyTree 函数用于复制一个二叉树。它会递归地复制二叉树的每个节点,并且生成一个新的二叉树。在这个过程中,新的二叉树和原始二叉树的节点是独立的,它们的内存地址不同。这是因为 CopyTree 函数中调用 GetTreeNode 函数,该函数每次都会动态分配内存以创建新的节点。

所以,复制后的二叉树和原始二叉树之间的节点地址没有任何关系,它们是相互独立的。修改复制后的二叉树的节点不会影响原始二叉树。

应用五:二叉树的建立

以先序序列定义一棵二叉树:输入所要建立的二叉树的先序序列,建立二叉链表。
在输入的二叉树的先序序列中,加入空树明确表示"#"

在这里插入图片描述

按先序遍历序列建立二叉树的二叉链表
已知先序 序列为:ABC##DE##F###

二叉树的建立的算法:

typedef struct TreeNode{int data;//数据域TreeNode *rchild;//右孩子指针TreeNode *lchild;//左孩子指针
}TreeNode, *BiTree;//二叉树的建立的算法(按先序遍历序列建立)
void CreateBiTree(BiTree &T) {char ch; scanf("%c",&ch);if (ch=='#') T = NULL;else {T = (TreeNode *)malloc(sizeof(TreeNode)); T->data = ch;      // 生成根结点CreateBiTree(T->lchild); // 构造左子树CreateBiTree(T->rchild); // 构造右子树}
}

应用六:交换二叉树每个结点的左右孩子

以上代码实现了交换二叉树每个节点的左右孩子的功能,分别使用了先序、中序和后序遍历的方式。

遍历二叉树算法的变式:

  1. Swap 函数(先序遍历):

    • 从根节点开始,先交换当前节点的左右孩子。
    • 然后递归地对左子树和右子树执行相同的操作。
  2. Swap2 函数(中序遍历):

    • 与先序遍历不同,中序遍历中需要先对左子树进行操作,然后交换当前节点的左右孩子,最后对右子树进行操作。
    • 但是这个实现方式是错误的,因为在交换左子树之后,对右子树进行操作时,右子树的结构已经发生了变化,导致结果错误。
  3. Swap3 函数(后序遍历):

    • 与先序遍历类似,但是是在遍历完左右子树之后再交换当前节点的左右孩子。
    • 这样可以保证在交换左右孩子时,左右子树的结构不会被改变。

通过上述分析,正确的交换方式是采用先序或后序遍历,中序遍历方式不适合这个场景。

Swap 函数(先序遍历):

//前序
void Swap(BiTree& T){//(先序遍历) if(T){//根节点 if(T->lchild||T->rchild){BiTree p;p= T->lchild;T->lchild = T->rchild;T->rchild = p;}Swap(T->lchild);Swap(T->rchild);}
}

Swap 函数(中序遍历)××× 不可行:

//中序的不行 
void Swap2(BiTree& T){//(中序遍历) if(T){//根节点 Swap2(T->lchild);if(T->lchild||T->rchild){BiTree p;p= T->lchild;T->lchild = T->rchild;T->rchild = p;}Swap2(T->rchild);}
}

Swap 函数(后序遍历):

//后序
void Swap3(BiTree& T){//(后序遍历) if(T){//根节点 Swap3(T->lchild);Swap3(T->rchild);if(T->lchild||T->rchild){BiTree p;p= T->lchild;T->lchild = T->rchild;T->rchild = p;}}}

求叶子节点个数、求树高、复制二叉树、创建二叉树完整代码示例

输入示例:ABC##DE##F###

#include<iostream>
using namespace std;typedef struct TreeNode{int data;//数据域TreeNode *rchild;//右孩子指针TreeNode *lchild;//左孩子指针
}TreeNode, *BiTree;//二叉树的建立的算法(按先序遍历序列建立)
void CreateBiTree(BiTree &T) {char ch; scanf("%c",&ch);if (ch=='#') T = NULL;else {T = (TreeNode*)malloc(sizeof(TreeNode));T->data = ch;      // 生成根结点CreateBiTree(T->lchild); // 构造左子树CreateBiTree(T->rchild); // 构造右子树}
}//求叶子结点 
int LeafCount(BiTree T){static int count=0;//或者定义成全局变量 /*这里使用局部静态变量*/if(T){if((T->lchild==NULL)&&(T->rchild==NULL)){//判断T是否为叶子结点count++;//每次递归调用//当T为叶子时,count自加}else{//递归:求T左、右子树上的叶子结点数LeafCount(T->lchild);LeafCount(T->rchild);}}return count;
}//求叶子节点的写法三 
int LeafCount3(BiTree T){  if (!T) return 0;	//空树叶子结点个数为0if (!T->lchild && !T->rchild) return 1; //若根节点没有左右孩子叶子结点个数为1return LeafCount3(T->lchild) + LeafCount3(T->rchild);	//否则为左右叶子结点个数之和
}//求树高 
int Get_Height(BiTree node){//递归 求树高 if(node==NULL) return 0;else{int Left_Height = Get_Height(node->lchild);int Right_Height = Get_Height(node->rchild);int Tree_Height = 1 + (Left_Height > Right_Height?Left_Height:Right_Height);//计算树高return Tree_Height;}}
//先序遍历 
void xxbl(BiTree T){if(T){//递归调用的结束条件printf("%c",T->data);//访问结点xxbl(T->lchild);//遍历左子树xxbl(T->rchild);//遍历右子树}}
//中序遍历 
void zxbl(BiTree T){if (T) {zxbl(T->lchild); printf("%c",T->data); zxbl(T->rchild);}
}
//后序遍历 
void hxbl(BiTree T){if(T){hxbl(T->lchild); hxbl(T->rchild); printf("%c",T->data);}
}// 
// 生成一个二叉树的结点
TreeNode* GetTreeNode(int item, TreeNode *lptr , TreeNode *rptr ){BiTree Q;if ( !(Q = (TreeNode*)malloc(sizeof(TreeNode))) ) {exit(1);}Q-> data = item;Q-> lchild = lptr;    Q-> rchild = rptr;return Q;
}//后序遍历 
TreeNode *CopyTree(TreeNode *T) {  //如果需要复制的二叉树的结点为空 就直接退出 BiTree newlptr=NULL;BiTree newrptr=NULL;BiTree newT=NULL;if (!T)    return NULL;if (T->lchild ) { newlptr = CopyTree(T->lchild);//复制左子树} if (T->rchild ){ newrptr = CopyTree(T->rchild);//复制右子树} newT = GetTreeNode(T->data, newlptr, newrptr);return newT;
} // CopyTreeint main(){BiTree T;//例如输入:ABC##DE##F### 来创建二叉树 CreateBiTree(T);cout<<"先序:"; xxbl(T);cout<<endl;cout<<"中序:"; zxbl(T);cout<<endl;cout<<"后序:"; hxbl(T);cout<<endl;cout<<"树高为:" ;cout<<Get_Height(T)<<endl;cout<<"叶子节点的个数为:";cout<<LeafCount3(T)<<endl; //复制二叉树BiTree Q;Q=CopyTree(T); cout<<"复制后的二叉树 以先序输出:"; xxbl(Q);cout<<endl;//修改一下Q 左子树根节点的数据 观察原本T 是否改变 Q->lchild->data='Z';cout<<"修改的二叉树 Q以先序输出:"; xxbl(Q);cout<<endl;cout<<"T先序:"; xxbl(T);cout<<endl;return 0; 
} 

感谢您的阅读!

  1. 遍历二叉树的应用都是基于递归法实现的,递归的知识点以及例题可以参考文章: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)
  2. 树与二叉树知识点可参考:【数据结构】树与二叉树(递归法先序、中序、后序、层次遍历二叉树、二叉树的建立以及求树高的方法)

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

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

相关文章

Python学习从0到1 day25 第二阶段 SQL ② Python操作数据库

少年有梦&#xff0c;不应至于心动&#xff0c;更要付诸行动 —— 24.4.12 pymysql 除了使用图形化工具以外&#xff0c;我们也可以使用编程语言来执行SQL从而操作数据库 在Python中&#xff0c;使用第三方库&#xff1a;pymysql来完成对MySQl数据库的操作 安装 pip install py…

什么是面向对象思想?

面向对象不是一种技术&#xff0c;而是一种思想。它指导我们以什么形式组织代码&#xff0c;以什么思路解决问题。 面向对象编程&#xff0c;是一种通过对象方式&#xff0c;把现实世界映射到计算机世界的编程方法。 面向对象解决问题的思路&#xff1a;把构成问题的事物分解成…

Go——网络编程

一. 互联网协议介绍 网络基础——网络传输基本流程_网络传输过程-CSDN博客 应用层HTTP协议-CSDN博客 传输层UDP/TCP协议_udp报文提供的确认号用于接收方跟发送方确认-CSDN博客 网络层IP协议-CSDN博客 链路层以太网详解_以太网数据链路层-CSDN博客 二. Socket编程 Socket是…

中国省级人口结构数据集(2002-2022年)

01、数据简介 人口结构数据不仅反映了地域特色&#xff0c;更是预测地区未来发展趋势的重要工具。在这些数据中&#xff0c;总抚养比、少年儿童抚养比和老年人口抚养比是三大核心指标。 少儿抚养比0-14周岁人口数/15-64周岁人口数 老年抚养比65周岁及以上人口数/15-64周岁人…

SpringBoot编写一个SpringTask定时任务的方法

1&#xff0c;在启动类上添加注解 EnableScheduling//开启定时任务调度 2&#xff0c; 任务&#xff08;方法&#xff09;上也要添加注解&#xff1a; Scheduled(cron " 0 * * * * ? ") //每分钟执行一次 域&#xff1a; 秒 分 时 日 月 周 &#xff08;年&#…

03-JAVA设计模式-外观模式

外观模式 什么是外观模式 外观模式&#xff08;Facade Pattern&#xff09;是面向对象设计模式中的一种&#xff0c;它为子系统中的一组接口提供了一个统一的高级接口&#xff0c;使得子系统更容易使用。外观模式定义了一个高层接口&#xff0c;让子系统更容易使用。子系统中…

【JS进阶】第四天

JavaScript 进阶 - 第 4 天 深浅拷贝 浅拷贝 首先浅拷贝和深拷贝只针对引用类型&#xff0c;因为简单类型直接拷贝值了 浅拷贝&#xff1a;拷贝的是地址&#xff0c;只拷贝一层 常见方法&#xff1a; 拷贝对象&#xff1a;Object.assgin() / 展开运算符 {…obj} 拷贝对象…

Linux_ubuntu使用常见问题解决

文章目录 1.安装好了搜狗输入法却只能输出英文&#xff1a; 1.安装好了搜狗输入法却只能输出英文&#xff1a; 1.浏览器搜索搜狗输入法&#xff0c;下载好安装包 终端输入下列命令安装&#xff0c;找不到文件可以cd到该安装包的目录文件下&#xff1a; sudo dpkg -i sogoupin…

自定义vue-cli 实现预设模板项目

模板结构 主要包括四个部分&#xff1a; preset.jsonprompts.jsgenerator/index.jstemplate/ 项目最终结构 preset.json preset.json 中是一个包含创建新项目所需预定义选项和插件的 JSON 对象&#xff0c;让用户无需在命令提示中选择它们&#xff0c;简称预设&#xff1b;…

从 0 搭建公司Jenkins服务 Centos7

从 0 搭建公司Jenkins服务 Centos7 安装 (运维人员) 安装环境 配置DNS安装JDK17安装Jenkins安装Docker安装GIT安装Ansible启动Jenkins安装插件配置凭据配置共享库配置 (开发经理)使用 (开发、测试人员) 安装 (运维人员) 安装环境 配置DNS 新安装系统的服务器无法解析域名&a…

云计算重要概念之:虚拟机、网卡、交换机、路由器、防火墙

一、虚拟机 (Virtual Machine, VM) 1.主流的虚拟化软件&#xff1a; 虚拟化软件通过在单个物理硬件上创建和管理多个虚拟环境&#xff08;虚拟机&#xff09;&#xff0c;实现资源的高效利用、灵活部署、隔离安全以及便捷管理&#xff0c;是构建云计算和现代化数据中心的核心…

B端:弹窗的场景、类型、 选择策略串讲,让你的设计有理有据。

B端产品在什么情况下使用弹窗&#xff0c;弹窗又分为哪些类型&#xff0c;该如何选择合理的弹窗形式&#xff0c;很多小伙伴都是跟着感觉走&#xff0c;本文告诉你依据。 一、弹窗及其场景 在B端系统中&#xff0c;"B端"通常指的是面向企业&#xff08;Business&am…

VMware Workstation部署最新版OpenWrt 23.05.3

正文共&#xff1a;1456 字 51 图&#xff0c;预估阅读时间&#xff1a;2 分钟 我们之前介绍了如何在VMware Workstation上安装OpenWrt&#xff08;软路由是啥&#xff1f;OpenWrt又是啥&#xff1f;长啥样&#xff1f;在VMware装一个瞅瞅&#xff09;&#xff0c;也介绍了如何…

十分钟学懂Java并发

并发简介 我们学到的基本上都是有关顺序编程的知识&#xff0c;即程序中所有事物在任意时刻都只能执行一个步骤。 编程问题中相当大的一部分都可以通过使用顺序编程来解决。然而&#xff0c;对于某些问题&#xff0c;如果能够并发地执行程序中的多个部分&#xff0c;则会变得非…

lua学习笔记19(面相对象学习的一点总结)

print("*****************************面相对象总结*******************************") object{} --实例化方法 function object:new()local obj{}self.__indexselfsetmetatable(obj,self)return obj end-------------------------如何new一个对象 function object:…

1688商品详情接口技术深探:解锁电商数据新纪元,实现业务自动化飞跃

1688商品详情接口技术解析 一、引言 随着电子商务的快速发展&#xff0c;越来越多的企业开始关注如何利用API接口获取商品详情信息&#xff0c;以实现数据的自动化处理和业务的快速拓展。1688作为国内知名的B2B电商平台&#xff0c;其商品详情接口成为了众多企业关注的焦点。…

三小时使用鸿蒙OS模仿羊了个羊,附源码

学习鸿蒙arkTS语言&#xff0c;决定直接通过实践的方式上手&#xff0c;而不是一点点进行观看视频再来实现。 结合羊了个羊的开发思路&#xff0c;准备好相应的卡片素材后进行开发。遇到了需要arkTS进行解决的问题&#xff0c;再去查看相应的文档。 首先需要准备卡片对应的图片…

什么是JAVA面向对象

一&#xff0c;什么是面向对象&#xff1a; 我们以前的项目都是面向过程的&#xff0c;一个完整的项目所有的代码都写在一个类里 这就叫面向过程。 面向对象&#xff0c;是指在写大型项目时&#xff0c;多人分工合作&#xff0c;为了代码看上去简洁美观&#xff0c;会将不同的…

2023-2024年科技行业主要变化趋势梳理与总结

一、主要大额并购案例并购原因 &#xff08;一&#xff09;产品线补充与业务市场拓展&#xff08;如VMware、Activision Blizzard并购案&#xff09; &#xff08;二&#xff09;技术整合&#xff08;如Spunk并购案&#xff09;、 &#xff08;三&#xff09;优化运营以期溢…

MFC:手写一个模态对话框程序

我们知道&#xff0c;在MFC中&#xff0c;要生成一个模态对话框程序&#xff0c;只要按着VS的提示&#xff0c;拖拖拽拽就能生成一个这样的程序&#xff0c;效率非常高。这里&#xff0c;我们反其道而行之&#xff0c;自己写一个这样的程序&#xff0c;这个程序与自动生成的程序…