第十章:C语言数据结构与算法初阶之链式二叉树

news2024/9/20 12:37:48

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、链式二叉树的定义
  • 二、链式二叉树的实现
  • 三、链式二叉树的遍历
    • 1、前序遍历/先根遍历
    • 2、中序遍历/中根遍历
    • 3、后序遍历/后根遍历
    • 4、层序遍历
    • 5、前/中/后序遍历的关系
  • 四、节点个数以及高度等
    • 1. 二叉树节点的个数
    • 2. 二叉树叶子节点个数
    • 3. 求树的高度/深度
    • 4. 求第k层的节点个数
    • 5. 二叉树查找值为x的节点
  • 五、 二叉树的创建和销毁
    • 1. 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
    • 2. 二叉树销毁
    • 3. 判断二叉树是否是完全二叉树
  • 总结


前言

用链表来实现二叉树。


一、链式二叉树的定义

每个节点用结构体来表示,其中有每个节点都有指向左右孩子节点的指针,如果没有孩子则为NULL。

二、链式二叉树的实现

typedef  int BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

三、链式二叉树的遍历

链式二叉树的增删查改没有价值。
搜索二叉树的增删查改有价值。
搜索二叉树又可以引申出平衡搜索树(AVL树+红黑树)
在这里插入图片描述
任何一个树都可以分出三部分:根节点、左子树、右子树。
空树不能再分了:NULL。

管理思维/分治思想:一个节点的遍历 = 左孩子节点的遍历 + 右孩子节点的遍历 + 该节点
所以每个节点都要遍历,左右孩子节点的遍历组成父节点的遍历,如果是空节点则遍历就是NULL
遍历一个节点就是遍历这个节点为根的树

1、前序遍历/先根遍历

遍历顺序:根、左子树、右子树

void PrevOrder(BTNode* root)
{
	if (!root)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2、中序遍历/中根遍历

遍历顺序:左子树、根、右子树

void InOrder(BTNode* root)
{
	
	if (!root)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

3、后序遍历/后根遍历

遍历顺序:左子树、右子树、根

void PostOrder(BTNode* root)
{
	if (!root)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

4、层序遍历

遍历顺序:一层一层走
运用队列:出一层,带下一层

void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root) QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		printf("%d ", front->data);
		//队列出上一层,带下一层
		QueuePop(&q);

		if (front->left)
		{
			QueuePush(&q, front->left);
		}

		if (front->right)
		{
			QueuePush(&q, front->right);
		}
	}
	QueueDestory(&q);
}

5、前/中/后序遍历的关系

前序/后序:确定根
中序:确定左右子树

四、节点个数以及高度等

1. 二叉树节点的个数

int TreeSize(BTNode* root)
{
	if (!root)
	{
		return 0;
	}
	return TreeSize(root->left) + TreeSize(root->right) + 1;
}

2. 二叉树叶子节点个数

int TreeLeafSize(BTNode* root)
{
	if (!root) return 0;
	if (root->left || root->right)
	{
		return TreeLeafSize(root->left) + TreeLeafSize(root->right);
	}
	else
	{
		return 1;
	}
}

3. 求树的高度/深度

int TreeHeight(BTNode* root)
{
	if (!root) return 0;
	
	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

4. 求第k层的节点个数

int TreeKlevelSize(BTNode* root, int k)
{
	if (!root) return 0;

	if (k == 1) return 1;

	if (k > 1) return TreeKlevelSize(root->left, k-1) 
		+ TreeKlevelSize(root->right, k-1);
}

5. 二叉树查找值为x的节点

BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (!root) return NULL;

	if (root->data == x) return root;
	
	BTNode* leftnode = TreeFind(root->left, x);
	if (leftnode) return leftnode;

	BTNode* rightnode = TreeFind(root->right, x);
	if (rightnode) return rightnode;	
	
	return NULL;
}

五、 二叉树的创建和销毁

1. 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

BTNode* rebuildTree(char* str, int* pi) {
    if (str[*pi] == '#') {
        (*pi)++;
        return NULL;
    }
    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    root->val = str[(*pi)++];

    root->left = rebuildTree(str, pi);
    root->right = rebuildTree(str, pi);
    return root;
}

2. 二叉树销毁

void TreeDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);
}

3. 判断二叉树是否是完全二叉树

bool TreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front == NULL)//遇到空就可以开始判断
		{
			break;
		}
		else
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}

	}

	while (!QueueEmpty(&q))
	{//出现空后,如果后面全是空的话就是完全二叉树
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestory(&q);
			return false;
		}
	}
	QueueDestory(&q);
	return true;
}

总结

链式二叉树是用链表来实现二叉树,用递归来遍历二叉树。
水激石则鸣,人激志则宏。——秋瑾

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

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

相关文章

Java面试知识点复习​_kaic

一、后端基础 1.Java基础、集合、线程、异常(自定义异常)流 2.mysql、redis、mongodb(为什么使用) 3.ssm、springboot、springcloud、mybatis-plus 1.接口和抽象类的区别 二、前端基础 1.事件 三、实习和项目 1.博客项目的日志配置(切面&a…

flutter tabBar 的属性及自定义实现

flutter tabBar 的属性及自定义实现 前言一、TabBar是什么?二、TabBar 自定义三、 Tab 自定义总结 前言 在Flutter中,TabBar的indicatorPadding属性用于设置指示器的内边距,而不是用于调整指示器和文字之间的间距。要调整TabBar中指示器和文字…

Field ‘非主键_id‘ doesn‘t have a default value

参考文章 Field ‘非主键_id‘ doesn‘t have a default value 的sql报错有两种情况 1.如果id是主键的话,一般是主键没有添加自增导致的错误 2.如果报错的是非主键id 那么是数据库设置错误 前端请求参数根本没有传入business_id 但是数据库报错 解决方法 把数据库数据限制n…

python 第九章 常用操作

系列文章目录 第一章 初识python 第二章 变量 第三章 基础语句 第四章 字符串str 第五章 列表list [] 第六章 元组tuple ( ) 第七章 字典dict {} 第八章 集合set {} 文章目录 系列文章目录9.1公共操作运算符 合并* 复制判断数据是否存在 公共方法len()delmax()min()rangeenume…

css实现文档目录(中间分割线宽度不定)

css实现文档目录(中间分割线宽度不定) 先上图片看效果 布局 数据 css样式 其实挺简单的,flex直接搞定

十六、centos7 下给python3创建虚拟环境

十五、centos7 下给python3创建虚拟环境 1.先说下为什么要创建虚拟环境 python3安装完成后,安装第三方库 pip3 install requests -i https://pypi.doubanio.com/simple提示如下让使用虚拟环境,不使用,即便是安装,也不能使用已经…

长连接和短链接详解

长连接和短链接详解 日常工作和生活中接触到的软件系统大多数情况下是由多个进程共同协作进行的,所以,了解进程之间如何进行高效的通信至关重要。 进程之间的通信有不少方式包括管道(包括无名管道和命名管道)、消息队列、信号量、…

Vue3在外部js文件获取Vue实例对象中的方法

刚开始想用getCurrentInstance 获取 发现这玩意只能写在setUp里面 然后百度发现在外部js文件只能先引入main.js在使用,这里注意要先将app实例导出 然后在外部js引用 就能获取到实例对象了 这点跟Vue2还是有很大区别

【SLAM14讲】 SLAM数学基础

一、向量 我们确定一个坐标系,也就是一个线性空间的基 (e1, e2, e3), 那就可以谈论向量 a 在这组基下的坐标了: 1.1 内积 内积可以描述向量间的投影关系 1.2 外积 外积的方向垂直于这两个向量,大小为 |a| |b|sin 〈a, b〉&…

【生态系统服务】构建生态安全格局--权衡与协同动态分析--多情景模拟预测--社会价值评估

生态系统服务 生态系统服务(ecosystem services)是指人类从生态系统获得的所有惠益,包括供给服务(如提供食物和水)、调节服务(如控制洪水和疾病)、文化服务(如精神、娱乐和文化收益…

vite + vue3 + tailwindcss

要在Vite Vue3中使用Tailwind CSS 创建项目 pnpm create vite在项目根目录中打开终端,并运行以下命令安装Tailwind CSS和相关依赖: pnpm install tailwindcss postcss autoprefixer执行 npx tailwindcss init,自动生成配置文件在tailwind.c…

【Unity3D】选中物体消融特效

1 消融特效原理 当前实现消融特效的方法主要有 Alpha 测试消融、clip(或 discard)消融,它们的本质都是随机丢弃一些片元,以实现消融效果。 1)噪声纹理 为模拟随机效果,可以通过对噪声纹理进行采样实现&…

Linux操作系统详解

文章目录 引言1. 认识Linux1.1 操作系统概述1.2 认识Linux1.3 虚拟机介绍1.4 远程连接Linux操作系统1.5 WSL1.6 虚拟机快照 2. Linux基础命令2.1 Linux的目录结构2.2 命令入门2.3 目录切换相关命令(cd/pwd)2.4 相对路径,绝对路径和特殊路径符…

当某个微服务重启后,GateWay网关访问服务出现503的问题

因为开发阶段可能需要经常重启微服务,但有时会莫名奇妙返回503 Service Unavailable 由于从springcloud2020版本开始,弃用了Ribbon,因此Alibaba在2021及之后版本的nacos中删除了Ribbon的jar包,因此无法通过loadbalancer路由到指定…

SpringBoot使用AOP

Spring相信大家都学过,就不多述了。 自定义注解,注解的类中所有的接口都会执行AOP增强,注解的接口会执行AOP增强。 注解类: package xin.students.examManagement.annotation.springConfiguration;import java.lang.annotation…

tensorboard 如何导出数据

tensorboard 如何导出数据 场景描述:有时候在第一遍跑实验的时候,由于epoch和内部循环变量的原因,做出来的图可能不是我们想要的,这个时候,需要自己导出数据并且重新画图,本文介绍如何导出数据道json或csv格…

超声波功率放大器在超声驱动技术中的应用

超声波功率放大器是一种能够将低功率信号放大到足够高的电平的电子器件。在超声驱动技术中,超声波功率放大器被广泛应用于超声波发生器、超声波换能器和超声波传感器等部件中,以保证这些部件的正常工作和高效性能。 超声波功率放大器在超声驱动技术中的应…

C++primer(第五版)第十二章(动态内存)

C中内存包含静态内存,栈内存,自由空间(堆). 静态内存用于保存局部的static(静态)对象,以及定义于任何函数以外的变量(全局变量). 栈内存用来保存定义在函数内的非static对象,由编译器自动创建和销毁. 程序可以用堆来存储动态分配的对象,同时也需要由我们来显式地销毁. 12.1…

【第四天学习】数组

数组批量数据处理 数组的定义 速度是一个相同类型的用同一个标识符封装到一起的基本数据类型,可以使用一个统一的速度名或者是索引来唯一确定速度中的每个元素,它的执行效率非常高。 数组中每一个变量称为数组的元素,数组能够容纳元素的数…

Centos7安装wordpress图文教程

宝塔面板安装WordPress有两种方法: 自己手动安装(推荐)宝塔后台一键部署跳转提示 推荐使用手动安装,因为一键部署的WordPress版本不是最新的,而且自己上传的文件比较放心。 第一步,上传WordPress安装包 …