二叉树的基本操作的实现
文章目录
- 树
- 树的定义
- 基本术语
- 二叉树
- 二叉树的定义
- 满二叉树和完全二叉树
- 二叉树的性质
- 二叉树的存储结构
- 顺序存储表示
- 链式存储表示
- 二叉链表
- 三叉链表
- 线索链表
- 遍历二叉树
- 先序遍历
- 中序遍历
- 后序遍历
- 创建二叉树
- 统计二叉树中叶子结点的个数
- 求二叉树树的深度
- 主函数
树
树的定义
树(Tree)是n(n>=0)个结点的有限集。当有限集T为空时称为空树;
当T不为空时,它满足两个条件:
- 有且仅有一个特定的称为根(root)的结点;
- 其余的结点可分为m(m>=0)个互不相交的子集T1,T2,T3…Tm,其中每个子集又是一棵树,并称其为子树(Subtree)。
基本术语
- 树的结点包含一个数据元素及若干指向其子树的分支
- 度为0的结点称为叶子结点(leaf)或终端结点
- 结点所拥有的子树的个数称为该结点的度。结点度的最大值为树的度
- 结点的层次:根为第一层,根的孩子为第二层。树中结点的最大层次称为树的深度
- 树中一个结点的子树的根结点称为这个结点的孩子(child)。这个结点称为它孩子结点的双亲(Parent)。具有同一个双亲的孩子结点互称为兄弟(sibling)。
- 如果将树中结点的各子树看成从左至右是有次序的,则称该树为有序树,否则称为无序树。
二叉树
二叉树的定义
二叉树(Binary Tree)是一种特殊的树型结构,它的特点是每个结点至多只有两棵子树(即二叉树中不存在度数大于2的结点),并且,二叉树的子树有左右之分。
二叉树就是度为2的树吗?
不是!
一棵度为二的有序树与一棵二叉树的区别在于:有序树的结点次序是相对于另一结点而言的,如果有序树中的子树只有一个孩子时,这个孩子结点就无须区分其左右次序,而二叉树无论其孩子数是否为2,均需确定其左右次序,也就是说二叉树的结点次序不是相对于另一结点而言而是确定的。
满二叉树和完全二叉树
满二叉树:深度为k,且有(2^k)-1个结点的二叉树。
完全二叉树:深度为k,结点数为n的二叉树,当且仅当每个结点的编号都与相同深度的满二叉树中从1到n的结点一一对应时,称为完全二叉树。
下面两个二叉树不是完全二叉树,因为没有与相同深度的满二叉树中的结点一 一对应
二叉树的性质
- 在二叉树的第i层上至多有 2i-1个结点。
- 深度为k的二叉树至多有 2k-1个结点(k>1)。
- 对任何一棵二叉树T, 如果其叶结点数为 n0, 度为2的结点数为 n2,则n0=n2+1。
- 具有 n (n >=0) 个结点的完全二叉树的深度为|log2(n)|(取整)+1
- 如果对一棵有n个结点的完全二叉树的结点按层次顺序编号,则对任一结点有:
如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点 i/2(取整)
如果2i>n,则结点i无左孩子;否则其左孩子是结点2i(取整)
如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1(取整)
给个图例,自行体会~
二叉树的存储结构
顺序存储表示
按完全二叉树的结点层次编号,用一组地址连续的存储单元,依编号存放二叉树中的数据元素,结点的相对位置蕴含着结点之间的关系。
如图
它的存储序列为:
链式存储表示
可根据不同的结点结构设计不同形式的链式存储结构
对于下图的二叉树,有几种不同的链式存储结构
二叉链表
二叉树的类型描述
typedef char TElemType;
typedef struct BiNode{TElemType data;struct BiNode* lchild; //左孩子struct BiNode* rchild; //右孩子
}BiNode,*BiTree;
三叉链表
三叉链表的类型描述
typedef char TElemType;
typedef struct BiNode{TElemType data;struct BiNode* lchild; //左孩子struct BiNode* rchild; //右孩子struct BiNode* parent; //父结点
}BiNode,*BiTree;
线索链表
二叉链表中的空链域存储其他有用信息
遍历二叉树
根据某种路径来巡防二叉树中的每一个结点,使得每一个结点均被访问,且只访问一次。二叉树的遍历是对二叉树进行多种操作的基础。
本文采用的是二叉链表的存储结构
如下图所示,有三种遍历方式
- 先序遍历 DLR
- 中序遍历 LDR
- 后序遍历 LRD
再举一个例子
先序遍历
实际上是一种递归算法思想
- 访问根结点
- 先序遍历左子树
- 先序遍历右子树
若遍历二叉树,则需要对二叉树进行一定的操作,这里就对二叉树进行输出操作
status Print(TElemType e)
{ //输出数据值cout << e;return OK;
}void PreOrderTraverse(BiTree T, status (*Print)(TElemType e))
{ //先序遍历算法if (T){Print(T->data);PreOrderTraverse(T->lchild, Print);PreOrderTraverse(T->rchild, Print);}
}
中序遍历
- 中序遍历左子树
- 访问根结点
- 中序遍历右子树
void InOrder(BiTree T, status(*Print)(TElemType e))
{ //中序遍历算法if (T){InOrder(T->lchild, Print);Print(T->data);InOrder(T->rchild, Print);}
}
后序遍历
- 后序遍历左子树
- 后序遍历右子树
- 访问根结点
void PostOrder(BiTree T, status(*Print)(TElemType e))
{ //后序遍历算法if (T){PostOrder(T->lchild, Print);PostOrder(T->rchild, Print);Print(T->data);}
}
创建二叉树
这里默认用先序的方式创建二叉树。
思路如下:
- 首先判断二叉树是否为空(即输入的第一个数据a是否为’#’)。若第一个数据a为空格,则二叉树为NULL;若不为空,进行下列操作
- 为根建立结点,其数据域为a
- 先序创建左子树的二叉树链表
- 先序创建右子树的二叉树链表
(即在满二叉树的相应结点位置如果为空,就输入’#’)
void CreateBiTree(BiTree &T)
{ //先序创建二叉树TElemType a;cin >> a;if (a == '#') T = NULL;else {T = (BiNode*)malloc(sizeof(BiNode));if(!T) exit(0);T->data = a;CreateBiTree(T->lchild);CreateBiTree(T->rchild);}
}
假如要创建如下图的二叉树
则需要输入以下:
ABC##DE#G##F###
统计二叉树中叶子结点的个数
我们先来回顾一下叶子结点的定义:度为0的结点。
故当一个结点左孩子和右孩子都不存在时,这个结点就为叶子结点。
因为要返回叶子结点的个数,所以需在算法中增添一个“计数器”,并将算法中对结点的操作改为:若是叶子结点,则计数器加1。
注意:要为计数器专门定义一个全局变量,默认值为0,不要让它的赋值语句出现在函数体或主函数中!
int num=0; //计数器num为全局变量
void countleaf(BiTree T, int& num)
{ //返回叶子结点的个数if (T){if (!T->lchild && !T->rchild) num++;countleaf(T->lchild, num);countleaf(T->rchild, num);}
}
求二叉树树的深度
当二叉树为空树时,深度为0;当二叉树只有根结点时,深度为1;
其他情况时,求左子树和右子树中深度的最大值,再加1,即为树的深度
int Depth(BiTree T)
{int left, right,h;if (!T) h = 0;else if (!T->lchild && !T->rchild) h = 1;else {left = Depth(T->lchild);right = Depth(T->rchild);h = 1 + (left > right ? left : right);}return h;
}
主函数
void main()
{BiTree T;int i;T = (BiNode*)malloc(sizeof(BiNode));cout << "1.创建二叉树 2.输出(先序) 3.输出(中序) 4.输出(后序) 5.返回叶子结点的个数 6.返回二叉树的深度 7.退出" << endl;while (1){cout << "请输入操作:";cin >> i;switch (i){case 1: cout << "请输入树的结点:"; CreateBiTree(T); break;case 2: cout << "先序遍历输出为:"; PreOrderTraverse(T, Print); cout << endl; break;case 3: cout << "中序遍历输出为:"; InOrder(T, Print); cout << endl; break;case 4: cout << "后序遍历输出为:"; PostOrder(T, Print); cout << endl; break;case 5: cout << "叶子结点的个数为:"; countleaf(T,num); cout<<num << endl; break;case 6: cout << "该二叉树的深度为:" << Depth(T); cout << endl; break;case 7: exit(0); break;default: cout << "请重新输入!" << endl; break;}}
}
运行结果如下:
总而言之,二叉树中,最重要的思想是递归,并且所有操作的基础就是遍历。
我总是喜欢把很多东西慢慢攒起来,等到时机成熟的时候一股脑开启,就像是专门为这一刻准备了这么久一样。这很好,但是这总会给我一种幻觉,仿佛我这一段时间,这些年,甚至这一辈子,就是为此而活的。如今我才明白,这是目标,但不是终极目标,更不是那种达成目标之后如释重负到脱离苦海的感觉。你要知道,人生的终极目标是死亡啊,生活并不是达到高潮就开始享受,堕入低谷就昏天黑日。
一生冗长,不失爱与自由,向死而行的生命都在热烈地生长。
二叉树的基本操作的实现相关推荐
- 二叉树的基本操作(c语言)
二叉树的基本操作 创建二叉树 二叉树的叶子节点 二叉树的节点总数 二叉树的高度 二叉树的基本遍历方法 创建二叉树 代码: // 创建二叉树,使用# void createBiTree(BiTree&a ...
- 二叉树的基本操作之二叉排序树
//二叉树的基本操作之-建立二叉排序树并遍历 #include<stdio.h> #include<string.h> struct Node{Node *lchild;Nod ...
- 二叉树的基本操作及哈夫曼编码/译码系统的实现
二叉树的基本操作及哈夫曼编码/译码系统的实现 实验目的和要求 掌握二叉树的二叉链表存储表示及遍历操作实现方法. 实现二叉树遍历运算的应用:求二叉树中叶结点个数.结点总数.二叉树的高度,交换二叉树的左右 ...
- 树的基本操作代码 c语言,二叉树的基本操作(C语言、源代码)
二叉树的基本操作(源代码) #include "stdio.h" #include "malloc.h" #define MAX 100 typedef str ...
- 手写二叉树的基本操作
本题题目来源是: https://pta.patest.cn/pta/test/1342/exam/3/question/20490 老实说,写二叉树的基本操作写的我心慌意乱,主要原因是总感觉递归学的 ...
- 实现二叉树的基本操作(Java版)
近期研究了一下二叉树,试着用Java语言实现了二叉树的基本操作,下面分享一下实现代码: package com.sf.test;import java.util.ArrayDeque; import ...
- 二叉树的基本操作——数据结构实验报告
一.实验名称:二叉树 二.实验目的 1)熟练掌握二叉树的存储方式的具体实现过程,实现二叉树的基本操作及运算: 2)进一步巩固指针的用法,栈及队列的基本操作,进一步体会递归算法,学会综合应用. 三.实验 ...
- 数据结构实验报告,二叉树的基本操作(C语言)
数据结构实验报告,二叉树的基本操作(C语言) 作者:命运之光 专栏:数据结构 目录 数据结构实验报告,二叉树的基本操作(C语言) 实验六 二叉树的基本操作 一.需求分析 二.概要设计 三.详细设计 四 ...
- 数据结构实验 二叉树的基本操作
数据结构实验 二叉树的基本操作 实验环境: Visual C++ 实验目的: 1.掌握二叉树的定义: 2.掌握二叉树的基本操作,如二叉树的建立.遍历.结点个数统计.树的深 度计算等. 实验内容: 用递 ...
- C语言二叉树的基本操作(超全)
二叉树作为数据结构其实是一个挺有意思的结构,可以有多种应用 我们直接来看一下二叉树的代码: #include<stdlib.h> #include<stdio.h> #incl ...
最新文章
- Otter-入门篇4(单向同步实践)
- 中国移动OnetNet云平台 使用以太网传输数据流步骤
- requests(一): 发送一个json格式的post请求
- Algorithm之OP:OP之GA遗传算法思路理解相关配图资料
- 抽象类可用于创建对象吗_野芝麻,见过吗?可用于肺热咳血、血淋、跌打损伤...
- 如何优雅的链式取值之 MayBe 函子
- 浏览器自带的前进后退按钮禁用
- 【生活科普】这7个影视剧的经典桥段,骗了我们很多年……
- [转载] Java泛型详解:<T>和Class<T>的使用。泛型类,泛型方法的详细使用实例
- JavaScript------表单约束验证DOM方法
- Utility Lambda
- zen3架构_曝Zen 3架构IPC性能将比Zen 2提升10~15%
- win10 更新后指纹不能使用
- 排名 教材 数字电子技术_数字电子技术教材改革及实践
- 2022年低压电工考试题模拟考试题库及模拟考试
- PotPlayer设置最小化的快捷键
- PNAS:植物香豆素塑造拟南芥合成根系微生物组的组成
- MySQL45讲 读书笔记 22讲MySQL有哪些“饮鸩止渴”提高性能的方法
- UOS安装 MySQL5.7
- BlinkOn9 - Layered APIs
热门文章
- 身份证OCR实名认证接口
- dos环境c语言写串口程序,DOS下串口通信程序来传送文件的源代码(转)
- proxmox ve 中文社区_Proxmox VE 部署维护
- Token是什么玩意
- 8*8LED点阵图原理(74HC595芯片使用方法)
- html链接加入qq群,获取QQ群加群链接
- Fastadmin和Easywechat
- SNAT DNAT
- 什么专业的人适合学嵌入式?
- vue编程式导航跳转到当前路由多次执行抛出NavigationDuplicated: Avoided redundant navigation to current location: