【数据结构】二叉树链式结构的实现(三)

目录

一,二叉树的链式结构

二,二叉链的接口实现

        1,二叉链的创建

        2,接口函数

        3,动态创立新结点

        4,创建二叉树

        5,前序遍历

        6,中序遍历

        7,后序遍历

三,结点个数以及高度等

        1,接口函数

        2,结点个数

        3,叶子结点个数

        4,二叉树高度

        5,二叉树第k层结点个数

        6,二叉树查找值为x的结点


一,二叉树的链式结构

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系;

通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。

链式结构又分为二叉链和三叉链,这里我们学习二叉链;

 二叉树是:

1,空树

2,非空:根节点,根节点的左子树、根节点的右子树组成的。

从图示中可以看出,二叉树定义是递归式的也称递归树,因此后序基本操作中基本都是按照该概念实现的;

 二叉链结构图示;

二,二叉链的接口实现

        1,二叉链的创建

typedef int BTDataType;
//二叉链
typedef struct BinaryTreeNode
{BTDataType data; // 当前结点值域	struct BinaryTreeNode* left; // 指向当前结点左孩子struct BinaryTreeNode* right; // 指向当前结点右孩子
}BTNode;

首先创建一个结构体表示二叉链data是当前结点的值域,BTDataType是储存的值的数据类型;

left是指向当前结点左孩子right是指向当前结点右孩子

这里的BTDataTypeint的重命名,也可以说是数据类型的重命名,这样统一化方便后续更改;

        2,接口函数

//动态创立新结点
BTNode* BuyNode(BTDataType x);
//创建二叉树
BTNode* GreatBTree();
//前序遍历
void PrevOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后序遍历
void PostOrder(BTNode* root);

这是以上要实现的接口函数;

        3,动态创立新结点

//动态创立新结点
BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));assert(newnode);newnode->data = x;newnode->left = NULL;newnode->right = NULL;return newnode;
}

后面创立新结点时直接调用此函数,一定要向堆区申请空间,这样函数结束空间会保留不会被回收;

data赋新值,leftright都指向空,再返回结点指针即可;

        4,创建二叉树

//创建二叉树
BTNode* GreatBTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}

然后我们申请结点来构造二叉树,通过链接将新结点链接起来;

创建的二叉树结构图示如下:

        5,前序遍历

//前序遍历
void PrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}

二叉树的前序,中序,后续遍历都是同一种思路:

1. 前序遍历(Preorder Traversal 亦称先序遍历)——根结点---->左子树--->右子树

2. 中序遍历(Inorder Traversal)——左子树--->根结点--->右子树

3. 后序遍历(Postorder Traversal)——左子树--->右子树--->根结点

这里要用到递归思想:这里NULLN表示,建议画图来理解,一层一层遍历下去;

前序遍历:

先访问根结点(1)然后访问其左子树(2)打印 1

此时根结点为(2)然后访问其左子树(3)打印1 2

此时根结点为(3)然后访问其左子树(NULL)打印1 2 3

此时根结点为(NULL)return NULL到(3),然后访问(3)的右子树(NULL)打印1 2 3 N

此时根结点为(NULL)return NULL到(3),此时对(3)也就是对(2)的左子树的访问结束了,然后访问(2)的右子树(NULL);打印1 2 3 N N

此时根结点为(NULL)return NULL到(2),此时对(2)也就是对(1)的左子树访问结束了,然后访问(1)的右子树(4)打印1 2 3 N N N

此时根结点为(4)然后访问其左子树(5)打印1 2 3 N N N 4

此时根结点为(5)然后访问其左子树(NULL)打印1 2 3 N N N 4 5

此时根结点为(NULL)return NULL到(5)然后访问(5)的右子树(NULL)打印1 2 3 N N N 4 5 N

此时根结点为(NULL)return NULL到(5)此时对(5)也就是对(4)的左子树的访问结束了,然后访问(4)的右子树(6)打印 1 2 3 N N N 4 5 N N

此时根结点为(6)然后访问其左子树(NULL)打印1 2 3 N N N 4 5 N N 6

此时根结点为(NULL)return NULL到(6)然后访问(6)的右子树(NULL)打印1 2 3 N N N 4 5 N N 6 N

此时根结点为(NULL)return NULL到(6),此时对(6)也就是对(4)的右子树的访问结束了,此时对(4)也就是对(1)的右子树的访问结束了,此时对(1)的访问也结束了,前序遍历也就结束了;打印1 2 3 N N N 4 5 N N 6 N N

图解思路示例:

    

BTNode* root = GreatBTree();
//前序遍历
PrevOrder(root);

这就是前序遍历;

        6,中序遍历

//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

中序遍历:左子树--->根结点--->右子树

跟前序遍历思路一致,就是换了一下访问的顺序,按照前序遍历的思路来就完事了;

//中序遍历
InOrder(root);
printf("\n");

        7,后序遍历

//后序遍历
void PostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

后序遍历:左子树--->右子树--->根结点

思路还是一致的,就是换了一下访问顺序,前,中,后序遍历的思路都是一致的,只要搞清楚其中一个就全部拿捏了;

//后续遍历
PostOrder(root);
printf("\n");

 这里对二叉链的基础遍历就实现完全了,有人说还有一个层序遍历,这个遍历需要用到队列,目前C语言阶段实现太过于繁琐,后序博主会补上;

三,结点个数以及高度等

像此类问题也都是递归问题,更加看重我们对函数栈帧的理解;

        1,接口函数

//结点个数
int	SumNode(BTNode* root);
//叶子结点个数
int LeafNode(BTNode* root);
//二叉树高度
int HeightTree(BTNode* root);
//二叉树第k层结点个数
int BTreeLeveSize(BTNode* root, int k);
//二叉树查找值为x的结点
BTNode* BTreeFine(BTNode* root, int x);

以上是要实现的函数;

        2,结点个数

//结点个数
int SumNode(BTNode* root)
{return root == NULL ? 0 : SumNode(root->left) + SumNode(root->right) + 1;
}

递归其实说难也难,说不难也不难,是有技巧在里面的;

1,大事化小:根结点为(1)的二叉树的结点总和==>左子树(2)的结点总和加上右子树(4)的结点总和再加上本身的结点个数1,然后根结点为(2)的结点总和==>左子树(3)的总和加上NULL1,这就是规律;【(1)=(2)+(4)+1 】

2,结束条件,当结点为NULL时返回0

//结点个数
printf("%d\n", SumNode(root));

        3,叶子结点个数

//叶子结点个数
int LeafNode(BTNode* root)
{if (root == NULL){return 0;}if (root->left==NULL && root->right==NULL){return 1;}else{return LeafNode(root->left) + LeafNode(root->right);}
}

 

大事化小:求根结点为(1)的二叉树的叶子节点的个数==>其左子树(2)加上其右子树(4)的叶子节点的个数;【(1)=(2)+(4)

结束条件:当结点为NULL时返回0,当结点的左右子树都为NULL时返回1;

        4,二叉树高度

//二叉树高度
int HeightTree(BTNode* root)
{if (root == NULL){return 0;}int left = HeightTree(root->left);int right = HeightTree(root->right);return left > right ? left + 1 : right + 1;
}

大事化小:求根结点为(1)的二叉树的高度==>其左子树(2)与右子树(4)中高的一颗的高度加上本身的高度1;【(1)=(2)>(4)?(2)+1:(4)+1 】

结束条件:当结点为NULL时返回0;

//二叉树高度
printf("%d\n", HeightTree(root));

        5,二叉树第k层结点个数

//二叉树第k层结点个数
int BTreeLeveSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BTreeLeveSize(root->left, k - 1)  + BTreeLeveSize(root->right, k - 1);
}

大事化小:求根结点为(1)的二叉树第K层的结点个数==>其左子树(2)加上右子树(4)中第K-1层结点的个数;【(1)=(2)+(4)

结束条件:当结点为NULL时返回0,K等于1时返回1;

//二叉树第k层结点个数
printf("%d\n", BTreeLeveSize(root,3));

        6,二叉树查找值为x的结点

//二叉树查找值为x的结点
BTNode* BTreeFine(BTNode* root, int x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}if (BTreeFine(root->left, x) == NULL){return BTreeFine(root->right, x);}else{return BTreeFine(root->left, x);}
}

大事化小:查找根结点为(1)的二叉树中值为x的结点==>查找其左子树(2)与右子树(4)中值为x的结点;

结束条件:当结点为NULL时返回NULL当结点的值为x时返回该结点;

思路:所以当其中一个子树不为NULL时就是所求的结点,如果左子树不为空则返回左子树的结点,否则返回右子树的结点,如果左右都为空那也返回右子树的结点;

//二叉树查找值为x的结点
BTNode* ret = BTreeFine(root, 6);
printf("%d\n", ret->data);ret = BTreeFine(root, 3);
printf("%d\n", ret->data);

到这里就结束了,通过这些题目也充分的认识了二叉树(递归树),这就是递归算法,还是要多画图来理解,递归基层的知识就是函数栈帧的创建与销毁

第三阶段就到这里了,这阶段带大家了解一下二叉树(递归树)的递归思想;

后面博主会陆续更新;

如有不足之处欢迎来补充交流!

完结。。


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

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

相关文章

Mojo 语言官网

Mojo面向 AI 开发者的新型编程语言,无缝支持CPU、GPU,兼容Python,跟Python类似的语法,但是比Python快68000倍。目前Mojo仅支持Ubuntu,暂不支持Windows和Mac,可以在Mojo Playground先体验一下。 Mojo 语言…

【LeetCode-简单题KMP】459. 重复的子字符串

文章目录 题目方法一:移动匹配方法二:KMP算法 题目 方法一:移动匹配 class Solution {//移动匹配public boolean repeatedSubstringPattern(String s) {StringBuffer str new StringBuffer(s);//ababstr.append(s);//拼接一份自己 abababab…

day44:C++ day4,拷贝赋值、友元、常成员、运算符重载

一、仿照string类&#xff0c;完成myString 类 mystring.h #ifndef MYSTRING_H #define MYSTRING_H#include <iostream> #include <cstring>using namespace std;class myString { private:char *str; //记录c风格的字符串int size; //记录字…

北大C++课后记录:文件读写的I/O流

前言 文件和平常用到的cin、cout流其实是一回事&#xff0c;可以将文件看作一个有限字符构成的顺序字符流&#xff0c;基于此&#xff0c;也可以像cin、cout读键盘数据那样对文件进行读写。 读写指针 输入流的read指针 输出流的write指针 注&#xff1a;这里的指针并不是普…

使用scp命令失败出错

使用scp命令失败出错&#xff0c;无反应。 解决&#xff1a; 1.使用ifconfig查看目标主机公网IP地址 ifconfig需使用公网ip 2.配置免密登录 可参考 远程登录ssh ssh-copy-id root目标主机ip再次尝试scp命令。 SCP&#xff08;Secure Copy&#xff09;是一个用于在本地主机和…

uni-app:通过ECharts实现数据可视化-如何引入项目

效果 引入文件位置 代码 <template><view id"myChart"></view> </template> <script> import echarts from /static/js/echarts.js // 引入文件 export default {mounted() {// 初始化EChartsconst myChart echarts.init(document…

RabbitMQ消息可靠性(一)-- 生产者消息确认

前言 在项目中&#xff0c;引入了RabbitMQ这一中间件&#xff0c;必然也需要在业务中增加对数据安全性的一层考虑&#xff0c;来保证RabbitMQ消息的可靠性&#xff0c;否则一个个消息丢失可能导致整个业务的数据出现不一致等问题&#xff0c;对系统带来巨大的影响&#xff0c;…

发现某设备 adb shell ps 没有输出完整信息

某错误示例 并不是都使用 -ef 参数查找都能够返回完整信息&#xff0c;某些版本设备不适用 -ef 也不会返回完整信息。 简单兼容 简单兼容不同版本 Android 设备查找进程列表&#xff0c;没有通过脚本判断 Android 版本&#xff0c;如有兴趣可以自己修改。 :loop adb shell…

使用docker创建minio镜像并上传文件,提供demo

使用docker创建minio镜像并上传文件&#xff0c;提供demo 1. 整体描述2. 环境搭建2.1 windows环境搭建2.2 docker部署 3. spring集成3.1 添加依赖3.2 配置文件3.3 创建config类3.4 创建minio操作类3.5 创建启动类3.6 测试controller 4. 测试操作4.1 demo运行4.2 页面查看4.3 上…

普中51-数码管实验

文章目录 数码管实验**静态数码管实验**动态数码管实验多位数码管简介数码管动态显示原理74HC245 和74HC138芯片介绍74HC245 芯片简介74HC138 芯片简介 代码如下&#xff1a; 数码管实验 如图所示&#xff1a; 从上图可看出&#xff0c;一位数码管的引脚是 10 个&#xff0c;…

c++11的一些新特性

c11 1. {}初始化2. 范围for循环3. final与override4. 右值引用4.1 左值引用和右值引用4.2 左值引用与右值引用比较 5. lambda表达式6. 声明6.1 auto6.2 decltype6.3 nullptr 7. 可变参数模版 1. {}初始化 在C中&#xff0c;使用花括号初始化的方式被称为列表初始化。列表初始化…

C++:初始化列表,static成员,友元,内部类

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》 文章目录 前言一、初始化列表二、static成员三、友元四、内部类总结 前言 本篇博客作为C&#xff1a;初始化列表&#xff0c;static成员&#xff0c;友元&#xff0c;内部类的知识总结。 一…