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

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

                 个人主页小八哥向前冲~

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

目录

前言

二叉树的遍历

前序遍历

中序遍历

后序遍历

总结点数

二叉树的高度

第k层叶子数

查找x值

叶子总数

左(右)孩子数

树的销毁

总代码


前言

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

以这棵树为例:

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

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

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

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

//创建节点
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

代码:

//前序遍历  根 左子树 右子树
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 

代码:

//中序遍历  左子树 根 右子树
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

 代码:

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

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

总结点数

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

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

代码

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

二叉树的高度

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

代码

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层的叶子为空,那就没有这个叶子!

代码

//第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值

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

代码

//查找值为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就行!

代码

//叶子数
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);
}

左(右)孩子数

以统计左孩子数为例:

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

思路

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

代码

//左孩子数
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;
}

树的销毁

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

代码

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

总代码

Tree.h文件

#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文件

//创建节点
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;
}

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

  • 56
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 43
    评论
评论 43
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值