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

目录

  • [1. 前言](#1. 前言)
  • [2. 二叉树的实现](#2. 二叉树的实现)
    • [2.1 创建一棵树](#2.1 创建一棵树)
    • [2.2 前序遍历](#2.2 前序遍历)
      • [2.2.1 分析](#2.2.1 分析)
      • [2.2.2 代码实现](#2.2.2 代码实现)
      • [2.2.3 递归展开图](#2.2.3 递归展开图)
    • [2.3 中序遍历](#2.3 中序遍历)
      • [2.3.1 分析](#2.3.1 分析)
      • [2.3.2 代码实现](#2.3.2 代码实现)
      • [2.3.3 递归展开图](#2.3.3 递归展开图)
    • [2.4 后序遍历](#2.4 后序遍历)
      • [2.4.1 分析](#2.4.1 分析)
      • [2.4.2 代码实现](#2.4.2 代码实现)
      • [2.4.3 递归展开图](#2.4.3 递归展开图)
    • [2.5 求节点个数](#2.5 求节点个数)
      • [2.5.1 分析](#2.5.1 分析)
      • [2.5.2 代码实现](#2.5.2 代码实现)
    • [2.6 求叶子节点个数](#2.6 求叶子节点个数)
      • [2.6.1 分析](#2.6.1 分析)
      • [2.6.2 代码实现](#2.6.2 代码实现)
    • [2.7 求树高度](#2.7 求树高度)
      • [2.7.1 分析](#2.7.1 分析)
      • [2.7.2 代码实现](#2.7.2 代码实现)
    • [2.8 求第K层节点的个数](#2.8 求第K层节点的个数)
      • [2.8.1 分析](#2.8.1 分析)
      • [2.8.2 代码实现](#2.8.2 代码实现)

1. 前言

在前面的博客中写了有关二叉树的介绍,那这次来写关于用C语言来实现与二叉树有关的一些操作。

与之前链表和顺序表不同的是,这里不实现增删查改。

2. 二叉树的实现

2.1 创建一棵树

直接手动创建一棵树,也就是直接malloc所有的节点。

直接创建6个节点,然后让node1的数据直接是1,让node2的数据直接是2,依次下去。

然后直接让node1的left = node2,它的right = node4;就按照上面的图来构建。

代码如下:

c 复制代码
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}TreeNode;

TreeNode* CreateTree()
{
	TreeNode* node1 = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node1);

	TreeNode* node2 = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node2);
	
	TreeNode* node3 = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node3);
	
	TreeNode* node4 = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node4);
	
	TreeNode* node5 = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node5);
	
	TreeNode* node6 = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node6);

	node1->data = 1;
	node2->data = 2;
	node3->data = 3;
	node4->data = 4;
	node5->data = 5;
	node6->data = 6;


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

但是这个代码局限性太大,已经是写固定了的代码,不好再修改,下面这种会好一些。

不用管空。

想要其它形状的可以修改代码,做一定的增加或者就行。

代码如下:

c 复制代码
TreeNode* BuyTreeNode(int x)
{
	TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
	assert(node);

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

	return node;
}

TreeNode* CreateTree()
{
	TreeNode* node1 = BuyTreeNode(1);
	TreeNode* node2 = BuyTreeNode(2);
	TreeNode* node3 = BuyTreeNode(3);
	TreeNode* node4 = BuyTreeNode(4);
	TreeNode* node5 = BuyTreeNode(5);
	TreeNode* node6 = BuyTreeNode(6);
	
	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	
	return node1;
}

2.2 前序遍历

2.2.1 分析

前序遍历 (Preorder Traversal 亦称先序遍历)------访问根结点的操作发生在遍历其左右子树之前。

就实现这颗树的前序遍历。

先根,然后左子树,再右子树,初学时把NULL也带上,方便理解。

也就是下面这样。

先访问根,然后找左子树,左子树又得拆成根和左子树,一直到空。使用递归来实现。

2.2.2 代码实现

c 复制代码
void PrevOrder(TreeNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

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

结果和分析的一样:

2.2.3 递归展开图

2.3 中序遍历

2.3.1 分析

中序遍历 (Inorder Traversal)------访问根结点的操作发生在遍历其左右子树之中(间)。

同样以上面那棵树为例子。

先左子树,再根,再右子树。

这里遇到根先不是NULL,先走它的左子树,是空就打印返回。

2.3.2 代码实现

c 复制代码
void InOrder(TreeNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

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

结果与分析的是一样的:

2.3.3 递归展开图

2.4 后序遍历

2.4.1 分析

.后序遍历(Postorder Traversal)------访问根结点的操作发生在遍历其左右子树之后。

同样是以上面那棵树为例子,它的后序遍历就是:

先访问它的左子树,然后右子树,最后才是根。

要当左右都为空时才访问第一个节点。

2.4.2 代码实现

c 复制代码
void PostOrder(TreeNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

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

递归展开方式也是一样的

2.4.3 递归展开图

2.5 求节点个数

2.5.1 分析

只要节点不为空,就加加,然后再调用左子树,右子树。

用全局的size,每次调用前先置空一些。

局部的使用不了,因为不能置空,再调用一次就会再上次的基础上累计。

同样是这课树节点数为6。

2.5.2 代码实现

c 复制代码
int size = 0;
void TreeSize(TreeNode* root)
{
	if (root == NULL)
		return;

	++size;

	TreeSize(root->left);
	TreeSize(root->right);
}

int main()
{  
	TreeNode* root = CreateTree();
    size = 0;
	TreeSize(root);
	printf("TreeSize:%d\n", size);
    return 0;
}

还有另一种实现:把树拆成左子树加右子树加1.

代码如下:

c 复制代码
int TreeSize(TreeNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) +
		TreeSize(root->right) + 1;
}

结果还是一样的。

采用的就是分治法

2.6 求叶子节点个数

2.6.1 分析

先得判断一下树是不是空树,不是才能就行进行。

不是空树,而且左右节点都为空,就是叶子节点,就返回1;

不是空,也不是叶子节点就采用分治,树的节点就等于左右叶子节点的和。

同样是这棵树,叶子节点就是3.

2.6.2 代码实现

c 复制代码
int TreeLeafSize(TreeNode* root)
{
	// 空 返回0
	if (root == NULL)
		return 0;
	// 不是空,是叶子 返回1
	if (root->left == NULL
		&& root->right == NULL)
		return 1;

	// 不是空 也不是叶子  分治=左右子树叶子之和
	return TreeLeafSize(root->left) +
		TreeLeafSize(root->right);
}
int main()
{
	TreeNode* root = CreateTree();
	printf("TreeLeafSize:%d\n", TreeLeafSize(root));
	return 0;
}
	

和分析的一样叶子节点个数就是3.

2.7 求树高度

2.7.1 分析

先要判断一下树是不是空树,是就为0。

不是空树,就要判断一下左子树和右子树那个更高,然后高的那个就加1。

同样以这棵树计算,这棵树的高度就是3

2.7.2 代码实现

c 复制代码
int TreeHeight(TreeNode* root)
{
	if (root == NULL)
		return 0;
	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

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

int main()
{
	TreeNode* root = CreateTree();
	printf("TreeHeight:%d\n", TreeHeight(root));
	return 0;
}
c 复制代码
int TreeHeight(TreeNode* root)
{
	if (root == NULL)
		return 0;

	return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

这里使用fmax返回大的数,需要包一个头文件<math.h>

结果也是一样的。

2.8 求第K层节点的个数

2.8.1 分析

同样采用分治。

如果是空树就返回0;

如果不为空,k=1,第一层就返回1;

如果不为空,且k>1,就返回左子树的k-1层加上右子树的k-1层。

同样以这棵树计算,k>1就说明再第一层的下面。这棵树的第三层的节点数就是,第二层的左加第二层的右;第二层的左又转化成第一层的左加第一层的右,为空就返回0。

2.8.2 代码实现

c 复制代码
int TreeLevelK(TreeNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return TreeLevelK(root->left, k - 1)
		+ TreeLevelK(root->right, k - 1);
}
int main()
{
	TreeNode* root = CreateTree();
	printf("TreeLevelK:%d\n", TreeLevelK(root, 3));
	return 0;
}

结果如下:

有问题请指出,大家一起进步!

相关推荐
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
搬砖的小码农_Sky5 小时前
C语言:数组
c语言·数据结构
先鱼鲨生7 小时前
数据结构——栈、队列
数据结构
一念之坤7 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年7 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王7 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
liujjjiyun8 小时前
小R的随机播放顺序
数据结构·c++·算法
ahadee9 小时前
蓝桥杯每日真题 - 第19天
c语言·vscode·算法·蓝桥杯
Theliars9 小时前
C语言之字符串
c语言·开发语言
Reese_Cool9 小时前
【数据结构与算法】排序
java·c语言·开发语言·数据结构·c++·算法·排序算法