【数据结构】二叉树的基本操作

目录:

  • 二叉树的基本操作
    • 1. 二叉树的创建
      • 1.1. 顺序存储
    • 2. 二叉树的初始化
    • 3. 二叉树插入节点
    • 4. 二叉树的遍历
      • 4.1. 递归遍历
      • 4.2. 层序遍历
      • 4.3. 非递归遍历

二叉树的基本操作

1. 二叉树的创建

二叉树的存储方式哦同样有两种,一种是顺序存储,一种是链式存储。

1.1. 顺序存储

#define MAXSIZE 100
struct TreeNode{int data;bool isEmpty;
}
TreeNode t[MAXSIZE];
```·
与其他数据结构类似,树的结构同样是先来一个结点,再来一个树的整体。
在树的结构体中,data表示数据域,用来存放树的节点的数据,isEmpty表示树的这个节点是否为空。对树的节点声明以后,再创建一个以节点类型为数组元素类型的数组,这样树的结构就定义好了。但由于顺序二叉树对于空间的浪费和查询的困难,顺序二叉树只适合于完全二叉树,所以我们一般使用链式二叉树。### 链式存储一个典型的存储结构如下```c
typedef struct BTNode{int data;struct node *lchild;struct node *rchild;
}BTNode,*BTree;

该结构采用的是二叉树的左右链表示,即一个结构体中有三部分,一部分是二叉树节点本事的数据,其他两部分是指向二叉树下一个节点的指针,一个指向左子树,一个指向右子树。
其中data为数据域,left和right为指针域,分别指向左孩子和右孩子。

2. 二叉树的初始化

二叉树的初始化只需要创建一个二叉树,并让他等于NULL即可。

void InitBTree(BTree *root)
{*root=NULL;
}

如果我们要对根节点进行初始化的话,可以采取以下的方式:

(*root)=(BTree)malloc(sizeof(BTNode));
(*root)->lchild=NULL;
(*root)->rchild-NULL;
(*root)->data=2;

3. 二叉树插入节点

如果需要对一个二叉树插入一个节点,我们只需要申请内存然后赋值即可。

BTNode *p=(BTNode *)malloc(sizeof(BTNode));
p->data=2;
p->lchild=NULL;
p->rchild=NULL;
root->lchild=p;

4. 二叉树的遍历

二叉树的遍历有四种基本的方式,分别为先序遍历,中序遍历,后序遍历和层次遍历。其中每一种方式又有两种方式,分别为递归和非递归。

4.1. 递归遍历

递归遍历的方式比较简单,只需要按照先序遍历的顺序,依次递归遍历二叉树即可,并且不同遍历方式的代码相似。

void firstTree(BTree BT)//先序遍历递归
{if(BT!=NULL){printf("%c",BT->data);displayTree(BT->left);displayTree(BT->right);}elseprintf("#");
}
void middleTree(BTree BT)//中序遍历递归
{if(BT!=NULL){displayTree(BT->left);printf("%c",BT->data);displayTree(BT->right);}elseprintf("#");
}
void lastTree(BTree BT)//后序遍历递归
{if(BT!=NULL){displayTree(BT->left);displayTree(BT->right);printf("%c",BT->data);}elseprintf("#");
}

4.2. 层序遍历

层序遍历的基本原理是借助队列的形式,当一个节点被读入以后,我们先将其压入队列末尾。接下来如果队列元素不空的话,我们就将队头的节点弹出,然后访问其值,并且将其左右子树压入队列末尾。以此类推循环往复,就达到了层序遍历的目的。
具体代码实现如下

void levelOrder(BTree BT)
{LinkQuene Q;InitQuene(Q);BTree p;EnQuene(Q,BT);while(!isEmpty(Q)){DeQueneu(Q,p);visit(p);if(p->lchild!=NULL)EnQuene(Q,p->lchild);if(p->rchild!=NULL)EnQuene(Q,p->rchild);}
}

4.3. 非递归遍历

非递归遍历需要通过栈的操作来进行,
示例代码如下:

//前序遍历
void firstTree(BTNode* root)
{if (root == NULL)return;BTNode* p = root;stack<BTNode*> s;  //创造一个栈,用来存放树节点while (!s.empty() || p!=NULL){//如果p不为空的话,酒将p压入栈中,然后让p指向左子树while (p!=NULL){printf("%c",p->data);s.push(p);p = p->lchild;}//当p为空时,说明根和左子树都遍历完了,该进入右子树了if (!s.empty()){p = s.top();s.pop();p = p->rchild;}}
}

//中序遍历
void middleTree(BTNode* root)
{if (root == NULL)return;BTNode* p = root;stack<BTNode*> s;  //创造一个栈,用来存放树节点while (!s.empty() || p!=NULL){//如果p不为空的话,酒将p压入栈中,然后让p指向左子树while (p!=NULL){s.push(p);p = p->lchild;}//当p为空时,说明根和左子树都遍历完了,该进入右子树了if (!s.empty()){p = s.top();s.pop();printf("%c",p->data);p = p->rchild;}}
}

其中前序遍历和中序遍历的方式较为相似,只需要先建立一个栈,然后将访问到的节点存入栈中,节点一直向左指向,直到节点为空。
当节点为空时让指针指向栈顶元素并弹出,然后开始右子树的访问。
前序遍历和中序遍历的区别仅仅在于打印数据的时间不同。

而后序遍历则更加复杂一点

//后序遍历
void PostOrderWithoutRecursion(BTNode* root)
{if (root == NULL)return;stack<BTNode*> s;BTNode *p=root;//p用来表示当前访问的节点BTNode *q=NULL;//q用来表示上一个访问的节点//先把p移动到左子树最下边while (p!=NULL){s.push(P);p = p->lchild;}while (!s.empty()){//此时让p已经为空了,先从栈中提取一个元素赋给pp = s.top();//现在p的值就是最左下角的节点s.pop();if (p->rchild == NULL || p->rchild == q) //如果右子树为空或者刚访问过右子树{printf("%c",p->data);q = p;//每次输出值以后,修改上一次访问的节点}else if(p->lchild==q)//如果左子树已经访问过了{s.push(p);//让根结点入栈p = p->rchild; //进入右子树while (p!=NULL){s.push(p);p = p->lchild;}}}
}

后序遍历需要两个指针,其中一个指针指向的是当前访问的元素,另一个指针指向的是上次访问过的元素。
这样是为了保证左右子树都访问过了以后在访问根节点:当我们访问过左子树以后,弹出根节点,然后需要判断右子树是否访问过或者右子树是否为空,如果是的话就访问根节点,否则就将右子树的根节点压入栈中,然后再访问右子树的根节点的左子树,直到右子树为空或者右子树被访问过,就返回去访问根节点弹栈。

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

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

相关文章

SpringBoot vue云办公系统

SpringBoot vue云办公系统 系统功能 云办公系统 登录 员工资料管理: 搜索员工 添加编辑删除员工 导入导出excel 薪资管理: 工资账套管理 添加编辑删除工资账套 员工账套设置 系统管理: 基础信息设置 部门管理 职位管理 职称管理 权限组管理 操作员管理 开发环境和技术 开发语…

选择适合户外篷房企业的企业云盘解决方案

“户外篷房企业用什么企业云盘好&#xff1f;Zoho WorkDrive企业网盘可以帮助户外篷房企业实现文档统一管理、提高工作效率、加强团队协作&#xff0c;并且支持各种文件类型的预览和编辑。” S公司是一家注重管理规范的大型户外篷房企业&#xff0c;已经有10余年的经验。作为设…

string和const char*参数类型选择的合理性对比

在编程中&#xff0c;我们经常需要处理字符串类型的参数。在C中&#xff0c;有两种常见的表示字符串的参数类型&#xff0c;即string和const char*。本文将对比这两种参数类型的特点&#xff0c;分析其在不同情况下的合理性&#xff0c;以便程序员能够根据实际需求做出正确的选…

Docker安装ActiveMQ

ActiveMQ简介 官网地址&#xff1a;https://activemq.apache.org/ 简介&#xff1a; ActiveMQ 是Apache出品&#xff0c;最流行的&#xff0c;能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,…

次方计数的拆贡献法(考虑组合意义)+限定类问题善用值域与位置进行ds:1006T3

对于多次方的计数问题可以考虑拆贡献。 题目问 ∣ S ∣ 3 |S|^3 ∣S∣3&#xff0c; ∣ S ∣ |S| ∣S∣ 表示选的点数。相当于在 ∣ S ∣ |S| ∣S∣ 中选了3次&#xff0c;也就是选了3个可相同的点。 先考虑3个不相同点的贡献&#xff0c;对应任意3个点&#xff0c;必然会对…

【小工具-生成合并文件】使用python实现2个excel文件根据主键合并生成csv文件

1 小工具说明 1.1 功能说明 一般来说&#xff0c;我们会先有一个老的文件&#xff0c;这个文件内容是定制好相关列的表格&#xff0c;作为每天的报告。 当下一天来的时候&#xff0c;需要根据新的报表文件和昨天的报表文件做一个合并&#xff0c;合并的时候就会出现有些事新增…

【BI看板】Superset2.0+图表二次开发初探

Superset图表功能也很丰富了&#xff0c;但一些个性化的定制需求就需要二次开发了。网上二开的superset版本大多是0.xxx版本的或1.5xxx版本&#xff0c;本次用的是2.xxx。 源码相关说明 源码目录 superset-2.0\superset-frontend\plugins\plugin-chart-echarts 插件相关资料 官…

【重拾C语言】六、批量数据组织(二)线性表——分类与检索(主元排序、冒泡排序、插入排序、顺序检索、对半检索)

目录 前言 六、批量数据组织——数组 6.4 线性表——分类与检索 6.4.1 主元排序 6.4.2 冒泡排序 6.4.3 插入排序 6.4.4 顺序检索&#xff08;线性搜索&#xff09; 6.4.5 对半检索&#xff08;二分查找&#xff09; 算法比较 前言 线性表是一种常见的数据结构&#xf…

在linux下预览markdown的方法,转换成html和pdf

背景 markdown是一种便于编写和版本控制的格式&#xff0c;但却不便于预览——特别是包含表格等复杂内容时&#xff0c;单纯的语法高亮是远远不够的——这样就不能边预览边调整内容&#xff0c;需要找到一种预览方法。 思路 linux下有个工具&#xff0c;叫pandoc&#xff0c…

Go Gin Gorm Casbin权限管理实现 - 2. 使用Gorm存储Casbin权限配置以及`增删改查`

文章目录 0. 背景1. 准备工作2. 权限配置以及增删改查2.1 策略和组使用规范2.2 用户以及组关系的增删改查2.2.1 获取所有用户以及关联的角色2.2.2 角色组中添加用户2.2.3 角色组中删除用户 2.3 角色组权限的增删改查2.3.1 获取所有角色组权限2.3.2 创建角色组权限2.3.3 修改角色…

Spring MVC工作原理

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Qt model/view 理解01

在 Qt 中对数据处理主要有两种方式&#xff1a;1&#xff09;直接对包含数据的的数据项 item 进行操作&#xff0c;这种方法简单、易操作&#xff0c;现实方式单一的缺点&#xff0c;特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作&#xff0c;如果现实方式改…

10.1select并发服务器以及客户端

服务器&#xff1a; #include<myhead.h>//do-while只是为了不让花括号单独存在&#xff0c;并不循环 #define ERR_MSG(msg) do{\fprintf(stderr,"%d:",__LINE__);\perror(msg);\ }while(0);#define PORT 8888//端口号1024-49151 #define IP "192.168.2.5…

【16】c++设计模式——>建造者(生成器)模式

什么是建造者模式? 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许你构造复杂对象步骤分解。你可以不同的步骤中使用不同的方式创建对象&#xff0c;且对象的创建与表示是分离的。这样&#xff0c;同样的构建过程可以创建不同的表…

React Hooks —— ref hooks

什么是Hooks Hooks从语法上来说是一些函数。这些函数可以用于在函数组件中引入状态管理和生命周期方法。 React Hooks的优点 简洁 从语法上来说&#xff0c;写的代码少了上手非常简单 基于函数式编程理念&#xff0c;只需要掌握一些JavaScript基础知识与生命周期相关的知识不…

python:openpyxl 读取 Excel文件,显示在 wx.grid 表格中

pip install openpyxl openpyxl-3.1.2-py2.py3-none-any.whl (249 kB) et_xmlfile-1.1.0-py3-none-any.whl (4.7 kB) 摘要&#xff1a;A Python library to read/write Excel 2010 xlsx/xlsm files pip install wxpython4.2 wxPython-4.2.0-cp37-cp37m-win_amd64.whl (18.0 M…

微擎小程序获取不到头像和昵称解决方案

这是一个使用微擎小程序的代码示例&#xff0c;其中包含了获取用户头像和昵称的功能。以下是解决方案&#xff1a; 首先&#xff0c;在<button>标签上添加open-type"chooseAvatar"属性&#xff0c;并绑定bindchooseavatar事件&#xff1a; <button class&qu…

数据结构-快速排序-C语言实现

引言&#xff1a;快速排序作为一种非常经典且高效的排序算法&#xff0c;无论是工作还是面试中广泛用到&#xff0c;作为一种分治思想&#xff0c;需要熟悉递归思想。下面来讲讲快速排序的实现和改进。 老规矩&#xff0c;先用图解来理解一下&#xff1a;&#xff08;这里使用快…

MATLAB中syms函数使用

目录 语法 说明 示例 创建符号标量变量 创建符号标量变量的向量 创建符号标量变量矩阵 管理符号标量变量的假设 创建和评估符号函数 syms函数的作用是创建符号标量和函数&#xff0c;以及矩阵变量和函数。 语法 syms var1 ... varN syms var1 ... varN [n1 ... nM] …

指数分布优化器(EDO)(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…