二叉树链式结构的实现

news2024/9/20 15:07:05

文章目录

1.前置说明

2.二叉树的遍历


文章内容

1.前置说明

       学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在我们对于二叉树的了解还处于初级阶段,所以我们手动创建一棵简单的二叉树,以便进入二叉树操作学习,等深入了解二叉树之后,我们再来研究二叉树真正建立的方法。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#include "Queue.h"



typedef int BTDataType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;

}BTNode;


BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->left = NULL;
	newnode->right = NULL;

	return newnode;
}


BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);
//  BTNode* node7 = BuyNode(7);


	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
//	node5->right = node7;

	return node1;
}

注意:上述代码并不是创建二叉树的方式

再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是:

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

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

2.二叉树的遍历

 2.1 前序、中序以及后序遍历

      学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

 按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历

1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

访问根的时候决定了其到底是什么遍历。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

   递归问题,我们第一个要想的是在哪里展开递归,第二个便是回退的时机,我们想要的得到的结果是什么,这导致我们要施加什么回退的条件来结束递归。回退又可以分为递归的程序结束完回退,以及符合回退条件时回退

每一个节点都可以看成根节点,每一个节点都有其左子树和右子树。

前序遍历递归图解:(先访问根,在遍历)

 

 

     

//前序
void PreOrder(BTNode* root)
{

	if (root == NULL)
	{
		printf("# ");
		return;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);

}

中序遍历:(先遍历,在访问根节点)

 


//中序
void InOrder(BTNode* root)
{

	if (root == NULL)
	{
		printf("# ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);

}

后序遍历:(最后访问根)

//后序
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);

}
2.2二叉树节点数量

   在判断当前节点不为空的时候count++

   return在count++之前,所以逻辑上当当前节点为空时候,就返回了,count并不会++。

 

要注意的是,这里我们要定义一个全局变量count ,方便我们计数

int count = 0;
void TreeSize1(BTNode* root)
{

	if (root == NULL)
	{
		return;
	}

	count++;
	TreeSize1(root->left);
	TreeSize1(root->right);

}

main函数里 count 要初始化,全局变量谁都能用,避免出现差错。

int main()
{
	count = 0;
	TreeSize1(root);
	printf("TreeSize1:%d\n", count);
    return 0;
}

 第二种思路:

与第一种思路相似,遇到空就返回,不过使用了三目操作符,更加简单。

int TreeSize2(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize2(root->left) + TreeSize2(root->right) + 1;
}
2.3叶子节点的数量

  叶子节点是左右节点都为空的节点。这个定义就是回退是的条件。

  当 当前节点既不为空,左孩子节点,右孩子节点也都不为空时,继续开展递归,当前节点的左孩子右孩子都为空时(此时为叶子节点),或当前节点为为空,便回退。

//叶子节点数量
//递归往往是回退的时候才带值的
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	if (root->left == NULL && root->right == NULL)//左子树右子树都为空是叶子节点的条件
	{
		return 1;
	}

	return TreeLeafSize(root->left) + TreeLeafSize(root->right);

}
2.4二叉树第k层节点的数量

     要找到确定第k层节点的数量,就要先找到第k层,我们这里从第一层开始,没有第0层。

     函数递归展开后其本身并不知道当前是第几层,这时候我们就需要一个函数变量来告诉函数是第几层。

      求根节点的第k层就是求其左右子树的第k-1层,在把左右子树看成根节点,就是求k-2层......

依次下去当k等于1 时,当前层数的节点就是我们要求的

        

//k层节点
//通过控制k 来控制递归
int TreeKLevel(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)//通过k控制递归的层数,程序到达这里,首先要root != null 要进去就要符合条件
	{
		return 1;
	}

	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);

}
 2.5查找值为x的数

        查找x并不需要遍历全部的二叉树,当找到对应的x之后我们要停止遍历二叉树。

        停止遍历二叉之后,我们还要把x值所在节点的地址给带回去。

//查找x
//找到就返回,如在左子树里面找到,直接返回不需要再去右子树里面

BTNode* TreeFind(BTNode* root, int x)
{
	if (root == NULL)
	{
		return NULL;
	}

	if (root->data == x)
	{
		return root;
	}

	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
	{
		return ret1;//假如再次分支找到了,程序不会往下走,直接返回了
	}

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

	return NULL;
}
2.6二叉树的深度

        当前二叉树的深度可以转化成左子树右子树的中最高的那一颗+1。而左右子树的高度又可以转化为他们子树中最高的那一颗+1......

       从最深的那一层的节点开始找出他们最深的左右子树返回给上一层。

2.7二叉树的销毁 

        二叉树的销毁符合后序遍历,先访问在左右子树,在销毁。free要放到遍历完右子树后,如果先free而不是先遍历的话,就会造成野指针的问题。

        

//销毁
void TreeDestroy(BTNode* root)
{
	if (root == NULL)
	{
		return ;
	}

	TreeDestroy(root->left);
	TreeDestroy(root->right);

	free(root);
	
}

        

 

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

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

相关文章

文本编辑器Vim常用操作和技巧

文章目录 1. Vim常用操作1.1 Vim简介1.2 Vim工作模式1.3 插入命令1.4 定位命令1.5 删除命令1.6 复制和剪切命令1.7 替换和取消命令1.8 搜索和搜索替换命令1.9 保存和退出命令 2. Vim使用技巧 1. Vim常用操作 1.1 Vim简介 Vim是一个功能强大的全屏幕文本编辑器&#xff0c;是L…

Java—实现多线程程序 | 入门

目录 一、前言 二、基本概念 进程 线程 三、Java多线程实现 java.lang.Thread类 获取线程名字及对象 获取main进程名 Thread currentThread() 四、线程优先级 设置优先级 一、前言 前期入门学习的代码中&#xff0c;全部都是单线的程序&#xff0c;也就是从头到尾…

Windows商店引入SUSE Linux Enterprise Server和openSUSE Leap

在上个月的Build 2017开发者大会上&#xff0c;微软宣布将SUSE&#xff0c;Ubuntu和Fedora引入Windows 商店&#xff0c;反应出微软对开放源码社区的更多承诺。 该公司去年以铂金会员身份加入Linux基金会。现在&#xff0c;微软针对内测者的Windows商店已经开始提供 部分Linux发…

JavaScript——为什么静态方法不能调用非静态方法

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

C++中的const成员变量和成员函数

在类中&#xff0c;如果你不希望某些数据被修改&#xff0c;可以使用const关键字加以限定。const 可以用来修饰成员变量和成员函数。 const成员变量 const 成员变量的用法和普通 const 变量的用法相似&#xff0c;只需要在声明时加上 const 关键字。初始化 const 成员变量只有…

VUE笔记(六)vue路由

一、路由的简介 1、实现生活中的路由 路由&#xff1a;路由其实就是一个key-value对应关系 路由器&#xff1a;用于管理多个路由关系的设备被称为路由器 2、前端的路由 目前使用的前端项目都是单页面的应用&#xff08;SPA&#xff09;&#xff0c;一个项目中只有一个html页…

网络学生用品商店系统设计与实现(论文+源码)_kaic

摘 要 随着互联网的发展&#xff0c;人们的生活发生了巨大的变化&#xff0c;给人们的生活、工作等方面带来了相当大的提高&#xff0c;电子化成为了节约成本、调高效率的代名词。电子商务是利用微电脑技术和网络通讯技术进行的商务活动&#xff0c;买卖双方通过网络所进行各…

亚马逊云科技 云技能孵化营 初识机器学习

目录 前言 一、课程介绍 二、什么是机器学习 三、机器学习算法进阶过程 四、亚马逊云科技能给我们什么 总结 前言 近期参加了“亚马逊云科技 云技能孵化营”&#xff0c;该孵化营的亚马逊云科技培训与认证团队为开发者准备了云从业者的精要知识及入门课程&#xff0c;帮助…

python 面试题--3(15题)

目录 Python中的生成器是什么&#xff1f;如何创建一个生成器&#xff1f; 解释Python中的递归函数及其使用场景。 Python中的迭代器和可迭代对象有什么区别&#xff1f; 什么是Python中的模块和包&#xff1f;它们有什么区别&#xff1f; 如何在Python中处理异常&#xf…

提升团队效率!探索多款热门一站式团队协作工具

“常见的几种团队协作工具有&#xff1a;Zoho Projects、Slack、Microsoft Teams、Asana、Trello等。” 团队协作已经成为了企业、组织和个人工作的重要组成部分。为了提高工作效率和协同能力&#xff0c;各种团队协作工具应运而生。本文将介绍团队协作工具的功能以及常见的几种…

E. Nastya and Potions - 记忆化搜索

分析&#xff1a; dfs永远都需要记忆化搜索&#xff0c;也算是优化技巧吧&#xff0c;首先不知道哪种方法更加好&#xff0c;本质就是找每种材料的最小费用&#xff0c;能通过几种费用更少的材料代替就可以将费用优化成更小&#xff0c;这也就需要dfs来找最小费用&#xff0c;但…

vue 实现word文档页面内预览docx-preview 和 vue-office

1.先下载引入 npm i docx-preview --save import { renderAsync } from docx-preview;2.使用 fetch(url) .then((response) > {let docData response.blob(); //将文件转换成bolb形式//选择要渲染的元素let childRef document.getElementsByClassName("childRef&qu…

单片机学习-蜂鸣器如何发出声音

硬件电路 软件编写 ①发出声音 #include "reg52.h" typedef unsigned int u16; // 重新定义 类型 typedef unsigned char u8; // 重新定义 类型sbit BEEP P2^5; //定义 P2第五个管教 为BEEP // 延时函数 void delay_time(u16 times) {while(times--); } vo…

从探索到明确,比特币与美股等传统资产相关性如何?

早期阶段&#xff0c;比特币经历了一段摸索和模仿的时期&#xff0c;这是因为当比特币刚刚出现时&#xff0c;比特币的价值和用途在这一阶段并不明确&#xff0c;人们对其性质和潜力还不太了解。 然而&#xff0c;随着时间的推移&#xff0c;比特币去中心化、固定供应上限等特点…

jmeter 性能测试用 csv

⏩很多人在使用 jmeter 做接口测试、自动化测试和性能测试时&#xff0c;都喜欢用 CSV 数据文件设置功能&#xff0c;来读取准备好的测试数据。虽然这种方法并不是最优方案&#xff0c;在我们的性能测试课程中&#xff0c;讲解了更优的方案&#xff0c;但是&#xff0c;没有上过…

红蓝攻防:浅谈削弱WindowsDefender的各种方式

前言 随着数字技术的日益进步&#xff0c;我们的生活、工作和娱乐越来越依赖于计算机和网络系统。然而&#xff0c;与此同时&#xff0c;恶意软件也日趋猖獗&#xff0c;寻求窃取信息、破坏系统或仅仅为了展现其能力。微软Windows&#xff0c;作为世界上最流行的操作系统&…

关于JAVA程序的内存分布

目录 1.Java程序运行时内存说明 2.JVM内存划分 3.Java中数据类型 4.Java中的String 5.结合HelloWorld分析java程序内存分布 1.Java程序运行时内存说明 编写的.java程序文件需要java编译器javac转成.class文件&#xff0c;然后通过jvm&#xff08;名为java的可执行程序&…

智慧能源助力绿色发展

居民生活是碳排放的重要贡献源&#xff0c;作为居民生活的主要场所&#xff0c;社区是低碳城市建设的重要空间载体。推动低碳社区建设&#xff0c;逐渐打造低碳生活方式&#xff0c;是低碳社会建设的重要内容之一。智慧新能源公共设施助力碳中和&#xff0c;用于各社区改造&…

【RuoYi移动端】uni-app如何发布h5网站?

一、登录D-Cloud开发者中心 开发者中心https://dev.dcloud.net.cn/二、创建应用 三、填写和提交创建应用 四、复制APPID

strcmp 的使用和模拟

目录 函数介绍&#xff1a; 头文件&#xff1a; 语法&#xff1a; 代码演示&#xff1a; 函数模拟&#xff1a; 函数介绍&#xff1a; strcmp是比较大小的函数。从字符串开始进行比较&#xff0c;如果两个相同位置的字符相同&#xff0c;那么继续往下进行比较&#xff0c;…