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

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

个人主页小八哥向前冲~

所属专栏数据结构【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;
}

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

相关推荐
cdut_suye2 分钟前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
南城花随雪。9 分钟前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
dundunmm25 分钟前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神25 分钟前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做27 分钟前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
捕鲸叉27 分钟前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
Noah_aa37 分钟前
代码随想录算法训练营第五十六天 | 图 | 拓扑排序(BFS)
数据结构
KpLn_HJL1 小时前
leetcode - 2139. Minimum Moves to Reach Target Score
java·数据结构·leetcode
只做开心事1 小时前
C++之红黑树模拟实现
开发语言·c++
程序员老冯头3 小时前
第十五章 C++ 数组
开发语言·c++·算法