【数据结构与算法】二叉树的知识讲解

这篇具有很好参考价值的文章主要介绍了【数据结构与算法】二叉树的知识讲解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

 一,二叉树的结构深入认识

 二,二叉树的遍历

 三,二叉树的基本运算

3-1,计算二叉树的大小

3-2,统计二叉树叶子结点个数

3-3,计算第k层的节点个数

3-4,查找指定值的结点


一,二叉树的结构深入认识

        二叉树是不可随机访问的,二叉树的结构是通过双亲结点与孩子结点之间的连接进行遍历访问,因此,二叉树的结构是用链式结构来存储的。如下:

二叉树的结构

#include <stdio.h>
#include <stdlib.h>
typedef struct Tree {
    int val;//数据
    struct Tree* leftchild;//左孩子结点
    struct Tree* rightchild;//右孩子结点
}Tree;

        要说明的是,学习二叉树的结构不跟栈和队列之类的一样用于增删查改,二叉树没有这些操作,二叉树的运用比较复杂,下面会依次讲解。


 二,二叉树的遍历

        二叉树的遍历有:前序遍历,中序遍历,后序遍历,层序。通常,在这些遍历算法中除了层序遍历外,其它的遍历都要运用递归结构。

        1,前序遍历(也称先序遍历)——访问根结点的操作发生在遍历其左右子树之前,即遍历的

顺序为:根,左子树,右子树。

        2,中序遍历——访问根结点的操作发生在遍历其左右子树之间。即遍历的顺序为:左子树,根,右子树。

        3,后序遍历——访问根结点的操作发生在遍历其左右子树之后。即遍历的顺序为:左子树,右子树,根。

        4,层序遍历——从左到右一层一层的遍历,此遍历非常简单,就如从开始到结尾的遍历顺序表一样。

        注意:这里要说明的是,以上的遍历除了层序遍历外,其它的遍历都是递归式的遍历,可不是单纯普通式按照以上顺序循环式的遍历,正确的遍历如下图:

【数据结构与算法】二叉树的知识讲解,数据结构,算法,c语言,链表,1024程序员节

        说明一下,在二叉树的遍历中,前,中,后遍历的思路基本相同,而层序遍历一般要借助队的结构来实现,本篇文章先不做介绍,后文深入运用时会详细说明。前中后的三种遍历代码如下:

//前序遍历
void FrontOrder(struct Tree* root) {
	//当递归到空结点时退出
	if (root == NULL) {
		return;
	}
	//输出
	fprintf(stdout, "%d ", root->val);
	//递归左子树
	FrontOrder(root->leftchild);
	//递归右子树
	FrontOrder(root->rightchild);
}
//中序遍历
void MiddleOrder(struct Tree* root) {
	//当递归到空结点时退出
	if (root == NULL) {
		return;
	}
	//递归左子树
	MiddleOrder(root->leftchild);
	//输出
	fprintf(stdout, "%d ", root->val);
	//递归右子树
	MiddleOrder(root->rightchild);
}
//后序遍历
void RearOrder(struct Tree* root) {
	//当递归到空结点时退出
	if (root == NULL) {
		return;
	}
	//递归左子树
	RearOrder(root->val);
	//递归右子树
	RearOrder(root->val);
	//输出
	fprintf(stdout, "%d ", root->val);
}

解析:

        递归本身有点不好理解,而上面的递归遍历中,当进行递归遍历时,可看做从此函数的根结点开始不断往下面的左右孩子结点遍历,当递归到根结点为空时结束下一次递归,并返回到此结点的双亲结点,可以说二叉树的递归遍历是不断往下层进行的,只有当遍历到最下层或下层的空结点时才返回,也就是递归遍历是从最后开始,然后不断往回返,直到返回到二叉结构的根节点才结束整个递归程序。

补充:

        函数的递归其实跟我们学习的栈结构一样,递归入函数(即进入函数栈帧)相当于入栈,出函数(即函数栈帧的销毁)相当于出栈。

学习建议:

        遍历思想是学习二叉树的基本,很多二叉树的算法思想都要在此递归遍历的思想上进行开阔的,因此,如果这中递归思路不明白,一定要先理清思路,不建议先往后面看。


三,二叉树的基本运算

        在讲解这一部分内容前,我们要先明白递归中设置局部变量的用法。

二叉树递归设置局部变量的注意:

        在二叉树计数中,我们难免要设定局部变量,而在进行递归返回中可能有些人说函数的返回值会覆盖之前的值,不明白为什么覆盖后的值就是我们想要统计的数值。其实这原理很简单,在讲解二叉树遍历的解析说过,二叉树的递归遍历是不断往下层进行的,只有当遍历到最下层时才返回,也就是递归程序是从最后开始,不断往前返回,当我们递归遍历二叉树时,满足计数的条件会不断往上层返,这时计数的值相当于以此函数中root为根结点的子树的以下计数值,也就是我们要统计的数值。

3-1,计算二叉树的大小

        计算二叉树的大小说白了就是确定有几个不为空的结点,此算法比较简单,我们可直接遍历整个二叉结构不断加一来实现。代码如下:

//统计二叉树中叶子结点的个数
int TreeSize(Tree* root) {
	//当为空结点时说明此时为0
	if (root == NULL) {
		return 0;
	}
	//不断递归遍历,遍历一个结点加1。
	return TreeSize(root->leftchild) + TreeSize(root->rightchild) + 1;
}

        以上代码虽然省力,但可能对于部分人来说比较难理解,展开后的代码如下:

int TreeSize(Tree* root) {
	if (root == NULL) {
		return 0;
	}
	//遍历左子树的结点个数
	int leftsize = TreeSize(root->leftchild);
	//遍历右子树的结点个数
	int rightsize = TreeSize(root->rightchild);
	//返回以此结点为根结点的二叉树结点个数,此二叉树是子二叉树
	return leftsize + rightsize + 1;
}

        对于当初学者笔者建议用展开后的代码,对递归了解比较深入后再用合成版代码。

3-2,统计二叉树叶子结点个数

        此算法与计算二叉树的结点个数方法相似,不同的是,当进行递归遍历时,我们可利用叶子结点的左右孩子都为空的特点来计数,当递归遍历时满足这一特点进行计数,不满足进行递归遍历,代码如下:

int LeavesNodeSize(Tree* root) {
	if (root == NULL) {
		return 0;
	}
    //当此结点是叶子结点时,计数1
	if (root->leftchild == NULL && root->rightchild == NULL) {
		return 1;
	}
	//左孩子结点的叶子结点数
	int count1 = LeavesNodeSize(root->leftchild);
	//右孩子结点的叶子结点数
	int count2 = LeavesNodeSize(root->rightchild);
    //返回当前以root为根结点的子二叉树的叶子结点总个数
	return count1 + count2;
}

        当我们明白以上原理后可进行简化算法,跟之前一样,先理清以上思路再进行简化。如下:

int LeavesNodeSize(Tree* root) {
	if (root == NULL) {
		return 0;
	}
	if (root->leftchild == NULL && root->rightchild == NULL) {
		return 1;
	}
	return LeavesNodeSize(root->leftchild) + LeavesNodeSize(root->rightchild);
}
3-3,计算第k层的节点个数

        记录第k层的二叉树结点也是同理,在递归遍历过程中,往下层递归一次将k减1,当k==1时就递归到了第k层,也就是在此时开始计数,而函数返回值将返回以此函数中的root为根结点的子二叉树的第k层结点数。

int NodeCount(Tree* root, int k) {
	if (root == NULL) {
		return 0;
	}
	//当k == 1 时此时遍历到了第k层,此时计数
	if (k == 1) {
		return 1;
	}
	//以此函数的root为根结点以下的子二叉树第k层的左孩子结点数
	int leftchild = NodeCount(root->leftchild, k - 1);
	//以此函数的root为根结点以下的子二叉树第k层的右孩子结点数
	int rightchild = NodeCount(root->rightchild, k - 1);
	//返回以此函数的root为根结点以下的子二叉树第k层的结点数
	return leftchild + rightchild;
}

        算法合并简化后如下:

int NodeCount(Tree* root, int k) {
	if (root == NULL) {
		return 0;
	}
	if (k == 1) {
		return 1;
	}
	return NodeCount(root->leftchild, k - 1) + NodeCount(root->rightchild, k - 1);
}
3-4,查找指定值的结点

        此算法的坑比较多,首先我们要考虑的是当遍历到要查找的结点时如何停止遍历,并最终返回该结点。要知道一点,当我们要查找的结点在中间时,直接返回是上一次的递归函数,因此,我们要做的是让查找的指定结点不断返回,直到递归结束。

        算法详细步骤如下:

Tree* FoundNode(Tree* root, int x) {
	if (root == NULL) {
		return NULL;
	}
	if (root->val == x) {
		return root;
	}
	Tree* leftchild = FoundNode(root->leftchild, x);
	//当左孩子是我们要找的结点时就不往下继续遍历了,直接返回此结点
	if (leftchild != NULL && leftchild->val == x) {
		return leftchild;
	}
	Tree* rightchild = FoundNode(root->rightchild, x);
	//当左孩子是我们要找的结点时就不往下继续遍历了,直接返回此结点
	if (rightchild != NULL && rightchild->val == x) {
		return rightchild;
	}
	//当查找不到返回NULL
	return NULL;
}

        算法的化简代码如下:

Tree* FoundNode(Tree* root, int x) {
	if (root == NULL) {
		return NULL;
	}
	if (root->val == x) {
		return root;
	}
	Tree* leftchild = FoundNode(root->leftchild, x);
	//当左孩子是我们要找的结点时就不往下继续遍历了,直接返回此结点
	if (leftchild != NULL && leftchild->val == x) {
		return leftchild;
	}
	//遍历右结点,当右孩子是我们要找的结点时返回此结点
	return FoundNode(root->rightchild, x);
}

总结:学习到这里学者们明显感到难度增大了,不过也不用担心,只要我们多多思考并加之练习,其实逻辑也不是那么难,上面的算法程序笔者之所以将步骤展开和步骤合并一并写入,就是为了让大家多多练习以上的思路,其实逻辑也都是一样的,只是为了强化思维罢了。文章来源地址https://www.toymoban.com/news/detail-721216.html

到了这里,关于【数据结构与算法】二叉树的知识讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】二叉树的遍历递归算法详解

    我们来写一个函数 BuyNode(x)函数 用于创建二叉树结点。 用动态开辟函数 malloc 函数进行动态开辟,并强制转换为 BTNode 型,用变量 node 来去管理开辟的空间。 我们初始化结点,其 val 即为传入的参数x,左右指针 left 和 right 都设为NULL。 我们在主函数中创建上面这样一颗二叉树

    2024年01月20日
    浏览(45)
  • 【数据结构和算法15】二叉树的实现

    二叉树是这么一种树状结构:每个节点最多有两个孩子,左孩子和右孩子 重要的二叉树结构 完全二叉树(complete binary tree)是一种二叉树结构,除最后一层以外,每一层都必须填满,填充时要遵从先左后右 平衡二叉树(balance binary tree)是一种二叉树结构,其中每个节点的左

    2024年02月16日
    浏览(34)
  • 【数据结构】【算法】二叉树、二叉排序树、树的相关操作

    树结构是以分支关系定义的一种层次结构,应用树结构组织起来的数据,逻辑上都具有明显的层次关系。 操作系统中的文件管理系统、网络系统中的域名管理、数据库系统中的索引管理等都使用了树结构来组织和管理数据。 树 Tree 是由n个节点组成的有限集合。在任意一颗非

    2024年02月04日
    浏览(53)
  • 数据结构和算法学习记录——平衡二叉树(基本介绍、平衡因子、平衡二叉树的定义、平衡二叉树的高度)

    目录 基本介绍 平衡因子 平衡二叉树  平衡二叉树的高度  什么是平衡二叉树? 以一个例子来解释一下: 搜索树结点按不同的插入次序,将会导致不同的深度和平均查找长度ASL   在二叉搜索树中查找一个元素:  (a)要找到Jan,需要查找一次;要找到Feb,需要查找两次;

    2023年04月26日
    浏览(65)
  • 【数据结构与算法】力扣:二叉树的层序遍历

    给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 示例1: 输入:root = [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]] 示例 2: 输入:root = [1] 输出:[[1]] 示例 3: 输入:root = [] 输出:[] 来源:力扣(LeetCode) 链接:https://leetcode.cn/p

    2024年02月13日
    浏览(46)
  • 【数据结构—二叉树的基础知识介绍和堆的实现(顺序表)】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 1.树概念及结构 1.1树的概念 1.2 树的相关概念  1.3 树的表示 1.4 树在实际中的运用(表示文件系统的目录树结构) 2.二叉树概念及结构 2.1概念 2.2 特殊的二叉树: 2.3 二叉树的存储结构

    2024年02月03日
    浏览(43)
  • 数据结构与算法----详解二叉树的遍历(迭代、递归)

    ❤️ 作者简介 :大家好我是小鱼干儿♛是一个热爱编程、热爱算法的大三学生,蓝桥杯国赛二等奖获得者 🐟 个人主页 :https://blog.csdn.net/qq_52007481 ⭐ 个人社区 :【小鱼干爱编程】 🔥 算法专栏 :算法竞赛进阶指南 💯 刷题网站 :虽然市面上有很多的刷题网站,但是里面

    2024年01月24日
    浏览(54)
  • 数据结构与算法之二叉树: Leetcode 111. 二叉树的最小深度 (Typescript版)

    二叉树的最小深度 https://leetcode.cn/problems/minimum-depth-of-binary-tree/ 描述 就 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。 示例 1 示例 2 提示 树中节点数的范围在 [0, 1 0 5 10^5 1 0 5 ] 内

    2024年02月06日
    浏览(44)
  • 【算法与数据结构】236、LeetCode二叉树的最近公共祖先

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 : 根据定义,最近祖先节点需要遍历节点的左右子树,然后才能知道是否为最近祖先节点。 那么这种需求是先遍历左右节点,然后遍历中间节点,属于左右中的后序遍历模式 。因此

    2024年02月09日
    浏览(38)
  • 【算法与数据结构】222、LeetCode完全二叉树的节点个数

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :利用层序遍历,然后用num++记录节点数量。其他的例如递归法和迭代法也是如此。    层序遍历程序如下 : 复杂度分析: 时间复杂度: O ( n ) O(n) O ( n ) 。 空间复杂度: O ( n )

    2024年02月15日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包