暴力数据结构之二叉树(初阶)

递归是一种很重要的思想,他可以帮助我们将大问题细分为许多个小问题,从而拆解问题,使得问题简单化,本篇博客主要利用的就是递归的思想,将整棵树的问题拆解为许多个根节点与左右子树的简单问题。

1. 二叉树遍历

总体核心思路:核心逻辑为递归调用,即分治思想,将问题不断拆解,从初始根节点与左右子树依次向下分解,直到叶子结点不可再分。

1.1 前序遍历

前序遍历主要是以 先根节点 再左子树 再右子树为逻辑遍历, 以例图为例

前序遍历后为:A B D NULL NULL NULL C NULL E NULL NULL

cs 复制代码
BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

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

	return node;
}
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
1.2 中序遍历

核心逻辑:以左子树 根节点 右子树的顺序遍历

中序遍历后结果为:NULL D NULL B NULL A NULL C NULL E NULL

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

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
1.3 后序遍历

核心逻辑:以左子树 右子树 根节点 的顺序遍历

中序遍历后结果为:NULL NULL D NULL B NULL NULL NULL E C A

cs 复制代码
void BehendOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

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

2. 树的计算

2.1 计算全部节点个数

计算全部节点就是遍历整棵树后计算所有节点即可,不递归的方法就是使用全局变量或者传一个指针参数,这二者均有局限,所以主要介绍递归。

非递归:

cs 复制代码
int size = 0;
int TreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	else
		++size;

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

	return size;
}

void TreeSize(BTNode* root, int* psize)
{
	if (root == NULL)
		return 0;
	else
		++(*psize);

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

递归:依旧是将大问题分解为小问题,然后直到无法分解为止,将遍历整棵树看做遍历一个根节点与左子树和右子树,逐层拆解。

cs 复制代码
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}
2.2 计算叶子节点个数

首先空树没有叶子节点,直接返回返回0,是叶子结点返回1,不是叶子结点就递归返回他的左子树与右子树,逐层拆解到叶子节点。

cs 复制代码
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.3 计算树的高度

这里保存左右子树的高度,防止递归导致栈溢出。即分别求左子树与右子树的告诉,返回较大的值加一。

但是可以使用fmax来取出二者较大值,也是一种新思路。

cs 复制代码
 有效率问题
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	return TreeHeight(root->left) > TreeHeight(root->right) ?
		TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}

int fmax(int x, int y)
{
	return x > y ? x : y;
}

int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}
cs 复制代码
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ?
		leftHeight + 1 : rightHeight + 1;
}
2.4 计算第K层的节点数

递归:空树返回空,第零层即只有根节点返回1,其余的拆解为左子树与右子树的问题,依次递归。

cs 复制代码
int KTreeSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if(k == 0)
		return 1;
	return KTreeSize(root->left, k - 1) + KTreeSize(root->right, k - 1);
}

3. Leetcode 练习

965.单值二叉树

思路解析: 判断是否为单值二叉树就是判断所有节点的值是否相同。但是依次遍历判断有些麻烦,所以这里可以使用反证法,即只要找到不符合的节点就直接返回false,并结合递归的方法,将大问题分解为小问题。

具体解析:首先空树符合单值二叉树,直接返回true,其次判断左子树,先判断是否存在,之后判断其节点对应的值是否与根节点对应的值相同,右子树同理,最后返回递归的值。

cs 复制代码
bool isUnivalTree(struct TreeNode* root)
{
    if(root == NULL)
       return true;

    if(root->left && root->left->val != root->val)
       return false;

    if(root->right && root->right->val != root->val)
       return false;

    return isUnivalTree(root->left) && isUnivalTree(root->right);
}
相关推荐
汀、人工智能4 分钟前
[特殊字符] 第57课:搜索旋转排序数组
数据结构·算法·数据库架构·图论·bfs·搜索旋转排序数组
倦王8 分钟前
力扣日刷47
算法·leetcode·职场和发展
MicroTech202511 分钟前
突破量子数据加载瓶颈,MLGO微算法科技推出面向大规模量子计算的分治态制备技术
科技·算法·量子计算
码王吴彦祖13 分钟前
顶象 AC 纯算法迁移实战:从补环境到纯算的完整拆解
java·前端·算法
SccTsAxR17 分钟前
算法基石:手撕离散化、递归与分治
c++·经验分享·笔记·算法
wuweijianlove18 分钟前
算法测试中的数据规模与时间复杂度匹配的技术4
算法
Q741_14743 分钟前
每日一题 力扣 3655. 区间乘法查询后的异或 II 模拟 分治 乘法差分法 快速幂 C++ 题解
c++·算法·leetcode·模拟·快速幂·分治·差分法
The_Ticker44 分钟前
印度股票实时行情API(低成本方案)
python·websocket·算法·金融·区块链
夏乌_Wx1 小时前
剑指offer | 2.4数据结构相关题目
数据结构·c++·算法·剑指offer·c/c++
AI成长日志2 小时前
【笔面试算法学习专栏】哈希表基础:两数之和与字母异位词分组
学习·算法·面试