【数据结构】二叉树的实现

如有不懂的地方,可翻阅我之前文章哦!

个人主页小八哥向前冲~

所属专栏数据结构【c语言】

目录

前言

二叉树的遍历

前序遍历

中序遍历

后序遍历

总结点数

二叉树的高度

第k层叶子数

查找x值

叶子总数

左(右)孩子数

树的销毁

总代码


前言

前一章我们学习了堆,并且了解了什么是树。简单来说,堆就是一个二叉树,现在我们来真正了解一下二叉树!

以这棵树为例:

我们如何用链式结构来表示一颗二叉树呢?不错,结构体

根据二叉树的节点特点,可以将每个部分分为左孩子节点,右孩子节点和根节点,于是我们可以这样来描述它:

cpp 复制代码
typedef struct TreeNode
{
	struct TreeNode* left;//左孩子节点
	struct TreeNode* right;//右孩子节点
	TDatatype val;//节点数值
}TNode;

现在我们手搓一个二叉树(上图为例),来进行深入研究!

cpp 复制代码
//创建节点
TNode* BuyNode(TDatatype x)
{
	TNode* node = (TNode*)malloc(sizeof(TNode));
	if (node == NULL)
	{
		perror("malloc failed!");
		return NULL;
	}
	node->left = node->right = NULL;
	node->val = x;
	return node;
}
//手动创建一个二叉树
TNode* CreateTree()
{
	TNode* node1 = BuyNode(1);
	TNode* node2 = BuyNode(2);
	TNode* node3 = BuyNode(3);
	TNode* node4 = BuyNode(4);
	TNode* node5 = BuyNode(5);
	TNode* node6 = BuyNode(6);

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

	return node1;
}

二叉树的遍历

我们知道链表如何遍历,那么一颗链式树是怎么遍历的呢?

这里有三种遍历方法------前,中,后序遍历!

前序遍历

前序遍历是按照:根,左子树,右子树的方式层层遍历的

(上图为例)前序遍历结果为:1 2 3 NULL NULL NULL 4 5 NULL NULL 6 NULL NULL。

代码:

cpp 复制代码
//前序遍历  根 左子树 右子树
void Preoder(TNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->val);
	Preoder(root->left);
	Preoder(root->right);
}

当根走完,再走左子树遍历,再走右子树遍历,直到全部走完!(递归方式走完)

中序遍历

中序遍历按照:左子树,根,右子树的的方式遍历

(上图为例)中序遍历结果:NULL 3 NULL 2 NULL 1 NULL 5 NULL 4 NULL 6 NULL 。

代码:

cpp 复制代码
//中序遍历  左子树 根 右子树
void Inoder(TNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	Inoder(root->left);
	printf("%d ", root->val);
	Inoder(root->right);
}

先走左子树遍历,再走根遍历,再走右子树遍历,直到全部递归走完!

后序遍历

后序遍历按照:左子树,右子树,根方式遍历。

(上图为例)后序遍历结果:NULL NULL 3 NULL 2 NULL NULL 5 NULL NULL 6 4 1。

代码:

cpp 复制代码
//后序遍历  左子树 右子树 根
void Afteroder(TNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	Afteroder(root->left);
	Afteroder(root->right);
	printf("%d ", root->val);
}

先走左子树遍历,再走右子树遍历,最后走根!直到递归走完!

总结点数

我们不难知道:总结点数==左子树节点数+右子树节点数+1(根本身)。

如果根为空,节点数就是0。

代码

cpp 复制代码
//节点数
int TreeSize(TNode* root)
{
	//每个部分可以看成:左子树+右子树+1(自身)
	return root == NULL ? 0 : TreeSize(root->left) +
		TreeSize(root->right) + 1;
}

二叉树的高度

分析 :树的高度==左右子树中高的那个子树的高度+1。

代码

cpp 复制代码
int HeightTree(TNode* root)
{
	//高的子树+1就是高度
	if (root == NULL)
		return 0;
	int leftheight = HeightTree(root->left);
	int rightHeight = HeightTree(root->right);
	return leftheight > rightHeight ?
		leftheight + 1 : rightHeight + 1;
}

第k层叶子数

分析:第k层叶子数==第k层的左子树的叶子数+第k层的右子树的叶子数。

如果第k层的叶子为空,那就没有这个叶子!

代码

cpp 复制代码
//第k层树的节点数 
int LeafKSize(TNode* root, int k)
{
	//第k层:左子树+右子树的叶子数
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return LeafKSize(root->left, k - 1) + LeafKSize(root->right, k - 1);
}

查找x值

思路:先找左子树,如果有返回,没有再去右子树查找,有的话返回,没有返回空。

代码

cpp 复制代码
//查找值为x的节点
TNode* TreeFind(TNode* root, TDatatype x)
{
	if (root == NULL)
		return NULL;
	if (root->val == x)
		return root;
	TNode* node1 = TreeFind(root->left,x);
	//左子树没找到,就去右子树找
	if (node1)
		return node1;
	//在右子树找
	return TreeFind(root->right, x);
}

叶子总数

思路 :叶子总数==左子树叶子总数+右子树叶子总数。

我们要判断某个节点是不是叶子,这个节点的左右孩子是否都为NULL就行!

代码

cpp 复制代码
//叶子数
int LeafSize(TNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return LeafSize(root->left) + LeafSize(root->right);
}

左(右)孩子数

以统计左孩子数为例:

我们知道:左孩子数==左子树中的左孩子数+右子树中的左孩子数

思路

遍历左子树和右子树,如果有左孩子就记下来!

代码

cpp 复制代码
//左孩子数
int LeftSize(TNode* root)
{
	int count = 0;
	if (root == NULL)
		return 0;
	else
	{
		//如果有左孩子,数量就存起来
		if (root->left)
			count++;
	}
	//遍历一遍,最后再加总数
	return LeftSize(root->left) + LeftSize(root->right) + count;
}

树的销毁

销毁树节点要注意一个点就是:需要先销毁左子树节点,再销毁右子树节点,最后销毁根节点!

代码

cpp 复制代码
//二叉树的销毁
void TreeDestroy(TNode* root)
{
	if (root == NULL)
		return;
	TreeDestroy(root->left);
	TreeDestroy(root->right);
	free(root);
}

总代码

Tree.h文件

cpp 复制代码
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>


typedef int TDatatype;
typedef struct TreeNode
{
	struct TreeNode* left;
	struct TreeNode* right;
	TDatatype val;
}TNode;

//创建节点
TNode* BuyNode(TDatatype x);
//创建一个二叉树
TNode* CreateTree();
//前序遍历   根 左子树 右子树
void Preoder(TNode* root);
//中序遍历   左子树 根 右子树
void Inoder(TNode* root);
//后序遍历   左子树 右子树 根
void Afteroder(TNode* root);
//节点数
int TreeSize(TNode* root);
//叶子数
int LeafSize(TNode* root);
//第k层树的节点数 
int LeafKSize(TNode* root,int k);
//查找值为x的节点
TNode* TreeFind(TNode* root, TDatatype x);
//二叉树的销毁
void TreeDestroy(TNode* root);
//二叉树的高度
int HeightTree(TNode* root);
//左孩子数
int LeftSize(TNode* root);

Tree.c文件

cpp 复制代码
//创建节点
TNode* BuyNode(TDatatype x)
{
	TNode* node = (TNode*)malloc(sizeof(TNode));
	if (node == NULL)
	{
		perror("malloc failed!");
		return NULL;
	}
	node->val = x;
	node->left = node->right = NULL;
	return node;
}
//创建一个二叉树
TNode* CreateTree()
{
	TNode* node1 = BuyNode(1);
	TNode* node2 = BuyNode(2);
	TNode* node3 = BuyNode(3);
	TNode* node4 = BuyNode(4);
	TNode* node5 = BuyNode(5);
	TNode* node6 = BuyNode(6);

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

	return node1;
}
//前序遍历   根 左子树 右子树
void Preoder(TNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->val);
	Preoder(root->left);
	Preoder(root->right);
}
//中序遍历   左子树 根 右子树
void Inoder(TNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	Inoder(root->left);
	printf("%d ", root->val);
	Inoder(root->right);
}
//后序遍历   左子树 右子树 根
void Afteroder(TNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	Afteroder(root->left);
	Afteroder(root->right);
	printf("%d ", root->val);
}
//节点数
int TreeSize(TNode* root)
{
	//每个部分可以看成:左子树+右子树+1(自身)
	return root == NULL ? 0 : TreeSize(root->left) +
		TreeSize(root->right) + 1;
}
//叶子数
int LeafSize(TNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return LeafSize(root->left) + LeafSize(root->right);
}
//第k层树的节点数 
int LeafKSize(TNode* root, int k)
{
	//第k层:左子树+右子树的叶子数
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return LeafKSize(root->left, k - 1) + LeafKSize(root->right, k - 1);
}
//查找值为x的节点
TNode* TreeFind(TNode* root, TDatatype x)
{
	if (root == NULL)
		return NULL;
	if (root->val == x)
		return root;
	TNode* node1 = TreeFind(root->left,x);
	//左子树没找到,就去右子树找
	if (node1)
		return node1;
	//在右子树找
	return TreeFind(root->right, x);
}
//二叉树的销毁
void TreeDestroy(TNode* root)
{
	if (root == NULL)
		return;
	TreeDestroy(root->left);
	TreeDestroy(root->right);
	free(root);
}
//二叉树的高度
int HeightTree(TNode* root)
{
	//高的子树+1就是高度
	if (root == NULL)
		return 0;
	int leftheight = HeightTree(root->left);
	int rightHeight = HeightTree(root->right);
	return leftheight > rightHeight ?
		leftheight + 1 : rightHeight + 1;
}
//左孩子数
int LeftSize(TNode* root)
{
	int count = 0;
	if (root == NULL)
		return 0;
	else
	{
		//如果有左孩子,数量就存起来
		if (root->left)
			count++;
	}
	//遍历一遍,最后再加总数
	return LeftSize(root->left) + LeftSize(root->right) + count;
}

这期递归较多,比较难理解,有难度!

相关推荐
轩情吖6 分钟前
二叉树-堆(补充)
c语言·数据结构·c++·后端·二叉树··排序
九亿AI算法优化工作室&17 分钟前
GWO优化LSBooST回归预测matlab
人工智能·python·算法·机器学习·matlab·数据挖掘·回归
爱是小小的癌2 小时前
Java-数据结构-优先级队列(堆)
java·前端·数据结构
sjsjs112 小时前
【数据结构-字典树】力扣14. 最长公共前缀
数据结构·leetcode
python算法(魔法师版)2 小时前
基于机器学习鉴别中药材的方法
深度学习·线性代数·算法·机器学习·支持向量机·数据挖掘·动态规划
JNU freshman3 小时前
力扣第435场周赛讲解
算法·leetcode·蓝桥杯
眼镜哥(with glasses)3 小时前
蓝桥杯python基础算法(2-2)——基础算法(B)——模拟(上)
算法
赵鑫亿4 小时前
7.DP算法
算法·dp
iqay4 小时前
【C语言】填空题/程序填空题1
c语言·开发语言·数据结构·c++·算法·c#
程序猿编码4 小时前
自定义命令执行器:C++中命令封装的深度探索(C/C++实现)
linux·c语言·c++·网络安全·shell·命令行