当前位置: 首页 > 编程日记 > 正文

二叉树(C++):创建,前中后序遍历(递归+非递归),获取叶子节点个数,获取树的高度

文章目录

        • 前言
        • 创建二叉树
        • 先序遍历
        • 中序遍历
        • 后序遍历
        • 获取叶子节点个数
        • 获取树的高度
        • 测试代码

前言

现有如下二叉树:
在这里插入图片描述
关于二叉树的相关操作,我们能够发现二叉树从根节点到子节点,以及每个中间节点基本都能够拆分为若干个子节点的操作,且每个子节点的操作都和其头节点操作一致。
所以我们针对二叉树的操作都可以使用分治算+回溯/归并算法进行

完整测试代码见文末


创建二叉树

二叉树数据结构:

typedef struct tree
{char data;struct tree *left;struct tree *right;
}Tree,*TreeNode;

我们使用先序方式,创建如上二叉树:
输入如下: ABD***CE**FG***
创建过程

/*创建二叉树*/
void createTree(TreeNode *root) {char val = 0;cin >> val; //持续输入,直到完成一个二叉树的构建if (val == '*') {//输入为*则代表当前节点为空(*root) = NULL;} else {(*root) = (Tree *)malloc(sizeof(tree));if ((*root) == NULL) {cout << "create node failed " << endl;exit(-1);} else {(*root)->data = val;//为输入的节点赋值createTree(&(*root)->left);//分治左孩子节点createTree(&(*root)->right);//分治右孩子节点}}
}

先序遍历

先序遍历二叉树指:先遍历二叉树的根节点,再遍历当前根节点所有左子树,再遍历当前根节点所有右子树

因为这个过程针对子节点的遍历和根节点是没有任何区别的,所以可以使用分治进行处理

/*递归先序遍历*/
void preOrder(Tree *root) {if (root == NULL) {return;}cout << root->data;preOrder(root->left);preOrder(root->right);
}

同样可以使用栈进行非递归的先序遍历,即
栈可以保存遍历过程中的左节点,因为先序遍历是先访问根节点,其次就是左节点

while(p) {cout << p ->data; //访问根节点s.push(p); //保存左子节点p = p->left;
}

接着再弹栈,直到获取一个右节点

while(!s.empty()) {p = s.top();s.pop();p = p -> right;
}

接着再重复对右节点进行同样的访问操作,具体过程如下

/*非递归先序遍历*/
void preOrderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {cout << p ->data;s.push(p);p = p->left;}while(!s.empty()) {p = s.top();s.pop();p = p -> right;}}cout << endl;
}

中序遍历

中序遍历二叉树是指:先访问左节点,中间访问根节点,最后访问右节点
分治过程如下:

void inorder(Tree *root) {if (root == NULL) {return;}inorder(root -> left);cout << root -> data;inorder(root -> right);
}

中序遍历二叉树的非递归方式和先序类似,支持访问的时机是在先访问第一轮所有的左节点,再获取右节点之前进行根节点的访问,实现过程如下:

/*非递归中序遍历*/
void inorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();cout << p->data;s.pop();p = p->right;}}cout << endl;
}

后序遍历

后序遍历二叉树是指:先访问左节点,再访问右节点,最后访问根节点
分治过程如下:

/*递归后序遍历*/
void lastorder(Tree *root) {if (root == NULL) {return;}lastorder(root -> left);lastorder(root -> right);cout << root -> data;
}

非递归的访问过程和先序/中序遍历有差异,因为后序遍历需要优先访问完左节点、右节点
所以根节点的访问前提是:

  1. 右子节点为空
  2. 右子节点已经访问过

所以实现的过程中需要保存已经访问过的右子节点

void lastorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;Tree *lastvisit = NULL;//保存已经访问过的右子节点/*先获取到左子节点*/while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();s.pop();/*右节点已经为空或者已经访问过,那么认为右节点已经访问完,可以访问根节点了*/if (p -> right == NULL || p ->right == lastvisit) {cout << p->data;lastvisit = p;} else {//否则,将右节点以及右节点的子节点入栈从而继续访问s.push(p);p = p -> right;/*每获取到一个非空右节点,就将该右节点的左节点放入栈中*/while(p) {s.push(p);p = p -> left;}}}cout << endl;
}

获取叶子节点个数

叶子节点的条件就是:左右子树都为空
此时返回值应该为1
分治+归并获取叶子节点的个数

int getLeavesNode(Tree *root) {if (root == NULL) {return 0;} else {if (root -> left == NULL && root ->right == NULL) {return 1;}return getLeavesNode(root -> left) + getLeavesNode(root -> right);}
}

获取树的高度

树的高度为左右子节点的 层数较大的一个数值
实现过程如下:

int heightTree(Tree *root) {int height = 0;if (root == NULL) {return 0;} else {int l_height = heightTree(root -> left);int r_height = heightTree(root -> right);height = l_height > r_height? l_height +1 :r_height+1;}return height;
}

测试代码

#include <iostream>
#include <stack>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>using namespace std;typedef struct tree
{char data;struct tree *left;struct tree *right;
}Tree,*TreeNode;/*创建二叉树*/
void createTree(TreeNode *root) {char val = 0;cin >> val;if (val == '*') {(*root) = NULL;} else {(*root) = (Tree *)malloc(sizeof(tree));if ((*root) == NULL) {cout << "create node failed " << endl;exit(-1);} else {(*root)->data = val;createTree(&(*root)->left);createTree(&(*root)->right);}}
}/*递归先序遍历*/
void preOrder(Tree *root) {if (root == NULL) {return;}cout << root->data;preOrder(root->left);preOrder(root->right);
}/*非递归先序遍历*/
void preOrderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {cout << p ->data;s.push(p);p = p->left;}while(!s.empty()) {p = s.top();s.pop();p = p -> right;}}cout << endl;}/*递归中序遍历*/
void inorder(Tree *root) {if (root == NULL) {return;}inorder(root -> left);cout << root -> data;inorder(root -> right);
}/*非递归中序遍历*/
void inorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();cout << p->data;s.pop();p = p->right;}}cout << endl;
}/*递归后序遍历*/
void lastorder(Tree *root) {if (root == NULL) {return;}lastorder(root -> left);lastorder(root -> right);cout << root -> data;
}void lastorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;Tree *lastvisit = NULL;while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();s.pop();/*右节点已经为空或者已经访问过,那么认为右节点已经访问完,可以访问根节点了*/if (p -> right == NULL || p ->right == lastvisit) {cout << p->data;lastvisit = p;} else {//否则,将右节点以及右节点的子节点入栈从而继续访问s.push(p);p = p -> right;while(p) {s.push(p);p = p -> left;}}}cout << endl;
}int getLeavesNode(Tree *root) {if (root == NULL) {return 0;} else {if (root -> left == NULL && root ->right == NULL) {return 1;}return getLeavesNode(root -> left) + getLeavesNode(root -> right);}
}int heightTree(Tree *root) {int height = 0;if (root == NULL) {return 0;} else {int l_height = heightTree(root -> left);int r_height = heightTree(root -> right);height = l_height > r_height? l_height +1 :r_height+1;}return height;
}int main(int argc, char const *argv[])
{/* code */TreeNode root;cout << "construct the tree " << endl;createTree(&root);cout << "previous order recursion " << endl;preOrder(root);cout << "\nprevious order no recursion " << endl;preOrderNoRecur(root);cout << "inorder recursion " << endl;inorder(root);cout << "\ninorder no recursion " << endl;inorderNoRecur(root);cout << "lastorder recursion " << endl;lastorder(root);cout << "\nlastorder no recursion " << endl;lastorderNoRecur(root);cout << "height of the tree is " << heightTree(root) << endl;cout << "num leaves of the tree is " << getLeavesNode(root) << endl;return 0;
}

输出如下:

#输入
construct the tree 
ABD***CE**FG***
#输出
previous order recursion 
ABDCEFG
previous order no recursion 
ABDCEFG
inorder recursion 
DBAECGF
inorder no recursion 
DBAECGF
lastorder recursion 
DBEGFCA
lastorder no recursion 
DBEGFCA
height of the tree is 4
num leaves of the tree is 3

相关文章:

6月11号=》121页-125页

6.1  样式单概述 W3C已经给出了两种样式单语言的推荐标准&#xff0c;一种是级联样式单CSS(Cascading Style Sheets)&#xff0c; 另一种是可扩展样式单语言XSL(eXtensible Stylesheet Language)。 6.1.1  CSS CSS主要提供如下两个功能&#xff1a; 1&#xff1a;对页面的字…

linux cp sync,通过SSH使用Rsync传输文件,复制和同步文件及目录

在本文中&#xff0c;我们将解释如何通过SSH使用rsync复制文件。当涉及在网络上的系统之间传输文件时&#xff0c;Linux和Unix用户可以使用许多工具&#xff0c;最流行的数据传输协议是SSH和FTP&#xff0c;虽然FTP很受欢迎&#xff0c;但总是喜欢使用SSH&#xff0c;因为它是传…

【Java笔记】C++与Java的对比

接口&#xff1a; C可以多重继承&#xff0c;而Java不可以。但是Java里一个类可以声明实现多个接口。

cf792b循环链表

头尾链接一下就好&#xff0c; /* 1 2 3 4 5 6 7:4 5 6 7 1 2 3:2 3 5 6 7 1:5 6 7 1 3:6 7 1 3:1 3 7 */ #include<bits/stdc.h> using namespace std; int main(){int n,k,q[200],nxt[200],p,pre,tot;scanf("%d%d",&n,&k);for(int i1;i&…

二叉树:路径之和 Path Sum

给定一个二叉树与整数sum&#xff0c;找出所有从根节点到叶结点的路径&#xff0c;这些路 径上的节点值累加和为sum 即创建一个二叉树&#xff0c;要求二叉树中有一个路径从根节点到叶节点到路径加起来代表到和为 给定的sum 如下二叉树 给定路径之和为18&#xff0c;则需要输…

从零开始编写自己的C#框架(16)——Web层后端父类

从零开始编写自己的C#框架&#xff08;16&#xff09;——Web层后端父类 原文:从零开始编写自己的C#框架&#xff08;16&#xff09;——Web层后端父类 本章节讲述的各个类是后端系统的核心之一&#xff0c;涉及到系统安全验证、操作日志记录、页面与按键权限控制、后端页面功能…

c语言中的普通字符包括什么,【判断题】C语言中的字符常量通常有两种形式:普通字符和转义字符。...

【判断题】C语言中的字符常量通常有两种形式:普通字符和转义字符。更多相关问题&#xff0d;&#xff0d;&#xff0d;Can you speak French&#xff1f;&#xff0d;&#xff0d;&#xff0d;Yes, but only____.A&#xff0e;a littleB&#xff0e;littleC&#xff0e;muchD&a…

Codeforces Round #104 (Div. 2) E DP(01背包模型) +组和+除法取模求逆元

题意&#xff1a; 规定只包含4或7的数为幸运数字&#xff0c;给定n个数的序列&#xff0c;求他的子序列&#xff0c;使得该子序列的长度为k并且满足该子序列中不存在相同的两个幸运数字。问一共寻在多少种可能。&#xff08;只要该数的下标不同则认为是不同的序列&#xff09; …

django 增加验证邮箱功能

在user文件夹下新建python包&#xff0c;utils 在包内新建文件email_send.py,其中包括验证字符串随机码的产生&#xff0c;数据库的存储和email的发送 # -*- coding: utf-8 -*- # 作者&#xff1a;神秘藏宝室 # 日期&#xff1a;2019/1/1 22:21 from random import Random from…

二叉树:最近的公共祖先 Lowest Common Ancestor of a Binary Tree

已知二叉树&#xff0c;求二叉树中给定的两个节点的最近公共祖先。 最近公共祖先: 两节点v与w的最近公共祖先u&#xff0c;满足在树上最低(离根最 远)&#xff0c;且v,w两个节点都是u的子孙。 如上二叉树&#xff0c;6和8号节点的公共祖先有4&#xff0c;1&#xff1b;但是最近…

VS不显示最近打开的项目

VS2012不显示最近打开的项目 解决方法&#xff0c; 在"运行"中输入 " gpedit.msc"打开后在"用户配置"-"管理模板"-"任务栏和开始菜单" 然后将用户配置-->管理模板-->不保留最近打开文档的历史 将此选项设置为禁用 源…

河科大c语言上机实验答案,2016年河南科技学院信息工程学院C语言上机编程考研复试题库...

一、选择题1&#xff0e; 以下选项中&#xff0c;能用作数据常量的是( )。答:D【解析】A 项错误&#xff0c;十六进制数用数学0和字符x (或大写字母X )开头&#xff1b;B 项错误&#xff0c;八进制整数常量以数字0开始&#xff0c;有效数字为0〜7; C项错误&#xff0c;C 语言中…

无符号数溢出之后

2019独角兽企业重金招聘Python工程师标准>>> [rootcentos ~]# cat test.c #include <stdio.h>int main() {unsigned short i 0x0;while(1){printf("%u \n",i);if(i 0) //溢出之后 又会回到 0 所以不会 死循环break;} } 转载于:https://my.oschin…

加载BeanFactory

前言 上一篇文章讲述了ApplicationContext扩展功能的之一&#xff1a;环境准备。这篇文章接着讲述ApplicationContext的扩展功能-----加载BeanFactory&#xff0c;也就是初始化BeanFactory&#xff0c;并进行XML文件的读取。 加载BeanFactory obtainFreshBeanFactory方法从字面…

t-top 命令详解

前言 展示操作系统进程信息。动态得&#xff0c;实时得展示正在运行的操作系统进程信息。 所显示的系统摘要信息的类型以及为进程显示的信息的类型&#xff0c;顺序和大小都是用户可配置的&#xff0c;并且可以使配置在重新启动后保持不变。该程序为流程操作提供了一个有限的交…

怎么看懂c语言程序,求讲解一下这个程序,我看了1个小时都没有看懂,

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼# include #define N 9void fun(int a[], int n){ int i,j, max, min, px, pn, t;for (i0; i{/**********found**********/max min ___a[i]__;px pn i;for (ji1; j/**********found**********/if (max<___a>{ max a[j];…

【转】Winform输入法控制

来源&#xff1a;http://blog.itpub.net/23109131/viewspace-630576 想实现输入法切换&#xff1a;思路&#xff0c;找出当前系统所有输入法总个数&#xff0c;当前输入法在总输入法中的索引&#xff0c;通过改变索引值&#xff0c;来切换输入法 void input() {//变全角为半角的…

vector与结构体联合使用 在磁盘中生成.txt 文件

一下纯属个人总结、欢迎拍砖&#xff01;谢谢 我意思到以练促进学习C编程基础是很有帮助的 这篇文章是我为了熟悉掌握文件流和STL中的vector以及结构体三个只知识点所写的代码&#xff1a; #include <string> #include <stdlib.h> #include <iostream> #incl…

SQL Server 2008 R2如何开启数据库的远程连接

SQL Server 2008 R2如何开启数据库的远程连接 转载于:https://www.cnblogs.com/macT/p/10213025.html

二分法:二分查找(递归+非递归)实现

二分查找又称折半查找&#xff0c;首先&#xff0c;假设表中元素是按升序排列&#xff0c;将 表中间位置的关键字与查找关键字比较: 如果两者相等&#xff0c;则查找成功;否则利用中间位置将表分成前、后两个子表: 1)如果中间位置的关键字大于查找关键字&#xff0c;则进一步查…

mongodb数据库的一些常用命令列表

超级用户相关&#xff1a;use admin#增加或修改用户密码db.addUser(ixigua,pwd)#查看用户列表db.system.users.find()#用户认证db.auth(ixigua,pwd)#删除用户db.removeUser(mongodb)#查看所有用户show users#查看所有数据库show dbs#查看所有的collectionshow collections#查看…

c语言函数库哪里keyk,[精品]C语言库函数(字母G-K)-教案.doc

[精品]C语言库函数(字母G-K)-教案C语言库函数(字母G-K)- -??????????????????????????????????????(G类字母) - 1函数名: gcvt 功 能: 把浮点数转换成字符串 用 法: char *gcvt(double value, int ndigit, char *buf); 程序例: #include…

超链接调用js函数

<a href"javascript:gouwu()" ><span class"Buy" id"buyButton"></span></a>超链接调用js前面要加javascript:****************************SuppressWarningsJ2SE 提供的最后一个批注是 SuppressWarnings。该批注的作用…

iOS 轻击、触摸和手势的检测

一、检测捏合手势( UIPinchGestureRecognizer): //设定一个实例变量存储手指之间的其起始距离 property (assign, nonatomic) CGFloat initialFontSize;//调用&#xff1a;UIPinchGestureRecognizer *pinch [[UIPinchGestureRecognizeralloc]initWithTarget:selfaction:select…

二分法:search insert position 插入位置

问题描述&#xff1a; 给定一个排序数组nums(无重复元素)与目标值target&#xff0c;如果target在nums里 出现&#xff0c;则返回target所在下标&#xff0c;如果target在nums里未出现&#xff0c;则返回target应该 插入位置的数组下标&#xff0c;使得将target插入数组nums后&…

c语言课程设计学生籍贯信息记录簿,C语言课程设计 学生籍贯信息记录簿设计.doc...

C语言与程序设计课程设计学生籍贯信息记录簿设计学 院 信息工程班 级 物联1301班学 号 131408119姓 名 滕玲一&#xff0e;设计目的该软件主要是编辑一个学生籍贯信息记录簿记录每个学生信息&#xff0c;包括&#xff1a;学号、姓名、籍贯。具体功能&#xff1a;1.创建信息链表…

SharePoint使用BCS开发你第一个应用程序(三)

SharePoint使用BCS开发你第一个应用程序&#xff08;三&#xff09; 创建外部内容类型。 创建外部内容类型有三种不同方式&#xff1a;1. 在记事本上手写XML代码&#xff08;不推荐&#xff09;。2. 使用SharePoint Designer 2010 创建&#xff08;推荐&#xff09;。3. 使用VS…

Java Coverage(Cobertura)工具

首先是下载Cobertura的jar包了&#xff0c;这个工具底层是JCoverage&#xff0c;熟悉Jcoverage的对这个也不会陌生的。 Cobertura官网 http://cobertura.sourceforge.net/ 大家可以了解很多东西&#xff0c;比如现在的作者啊什么&#xff0c;这里就不介绍了 然后点Download&…

Java 内部类及其原理

Java中实现内部类 内部类相信大家都用过很多次了&#xff0c;就不说它是怎么用的了。 内部类 1.成员内部类 需要注意的是&#xff0c; 当成员内部类拥有和外部类同名的成员变量或这方法时&#xff0c; 默认情况下访问的是内部类的成员&#xff0c; 如要访问外部类的同名成员&am…

二分法:查找区间search for a range

问题描述&#xff1a; 给定一个排序数组nums(nums中有重复元素)与目标值target&#xff0c;如果 target在nums里出现&#xff0c;则返回target所在区间的左右端点下标&#xff0c;[左端点, 右端点]&#xff0c;如果target在nums里未出现&#xff0c;则返回[-1, -1]。 例如: ar…