【数据结构】二叉树OJ题

本文介绍了多种二叉树相关的算法实现,包括检查单值二叉树、判断两棵树是否相同、对称性检查、翻转二叉树、前序遍历、查找子树、计算第k层节点数、搜索特定值的节点、层序遍历以及判断是否为完全二叉树。这些算法基于递归和分治策略,适用于二叉树的数据结构操作。
摘要由CSDN通过智能技术生成

单值二叉树

  • 判断根结点与左右子结点值是否相等
  • 使用分治判断左右子树是否为单值二叉树
  • 检查到叶子节点后返回真
//单值二叉树
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);
}

 

检查两颗树是否相同

  • 先判断结构是否相同,即该结点是否都不为空
  • 再判断两当前结点值是否相等
//相同的树
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
	//两树同时检查到空结点返回真
	if (p == q && q == NULL)
	{
		return true;
	}
	//两棵树当前结点只有一个不为空
	//结构不同,返回假
	if (p == NULL || q == NULL)
	{
		return false;
	}
	//两棵树当前结点值不相等,返回假
	if (q->val != p->val)
	{
		return false;
	}
	//对两棵树当前结点的左右子树进行分治
	return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

 

对称二叉树

  • 直接使用判断相同树的实现
  • 改为对左子树的左子树与右子树的右子树相比较
//对称二叉树
//直接使用相同树的实现
//改为对左子树的左子树与右子树的右子树相比较
bool isSameTree2(struct TreeNode* p, struct TreeNode* q) {
	if (p == q && q == NULL)
	{
		return true;
	}
	if (p == NULL || q == NULL)
	{
		return false;
	}
	if (q->val != p->val)
	{
		return false;
	}
	return isSameTree2(p->left, q->right) && isSameTree2(p->right, q->left);
}
bool isSymmetric(struct TreeNode* root) {

	return isSameTree2(root->left, root->right);
}

 

翻转二叉树

  • 交换父节点的左右子结点,
  • 再对子结点执行相同操作,以此递归

在这里插入图片描述

struct TreeNode* invertTree(struct TreeNode* root){
    if (root == NULL)
    {
        return NULL;
    }
    struct TreeNode* tmp = root->left;
    root->left = root->right;
    root->right = tmp;
    root->left = invertTree(root->left);
    root->right = invertTree(root->right);
    return root;
}

 

二叉树的前序遍历

  • 先访问根结点再遍历左右子树
  • 这里返回数组的下标 i 注意通过传地址实现值得累加
  • 也可直接将 returnSize 作为下标,不用另外定义下标 i,用法相同
//前序遍历二叉树
int TreeSize(struct TreeNode* root)
{
	return root == 0 ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

void PreOrder(struct TreeNode* root, int* ret, int* pi)
{
	if (root == NULL)
		return;

	ret[*pi] = root->val;
	(*pi)++;
	PreOrder(root->left, ret, pi);
	PreOrder(root->right, ret, pi);
	return;
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
	int size = TreeSize(root);
	int* ret = (int*)malloc(size * sizeof(int));
	int i = 0;
	PreOrder(root, ret, &i);
	*returnSize = size;
	return ret;
}

 

另一颗树的子树

  • 判断每个结点为根结点的子树是否与 subRoot 相同
  • 不相等则继续往下判断以其左右子结点为根结点的子树是否与 subRoot 相同
    在这里插入图片描述
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
	//两树同时检查到空结点返回真
	if (p == q && q == NULL)
	{
		return true;
	}
	//两棵树当前结点只有一个不为空
	//结构不同,返回假
	if (p == NULL || q == NULL)
	{
		return false;
	}
	//两棵树当前结点值不相等,返回假
	if (q->val != p->val)
	{
		return false;
	}
	//对两棵树当前结点的左右子树进行分治
	return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

int TreeSize(struct TreeNode* root)
{
	return root == 0 ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(TreeSize(root) < TreeSize(subRoot))
    {
        return false;
    }
    if(isSameTree(root, subRoot))
    {
        return true;
    }
    return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}

 

二叉树第k层的结点个数

  • 二叉树第k层即子树的k-1层,以此分治
  • 子树为空返回0
  • 递归到k层,若有结点则计数该结点,返回1
//求二叉树第k层的结点个数
int TreeKLevel(BTNode* root, int k)
{

	if (root == NULL)
	{
		return 0;
	}
	//递归到第k层且结点存在时,计数该结点,返回1
	if (k == 1)
	{
		return 1;
	}
	//对子树的k-1层进行分治
	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}

 

查找二叉树中值为x的结点

  • 又需要判断返回值,同时也需要返回这个值时,最好提前记录返回值,避免多次调用
//查找二叉树中值为x的结点
BTNode* BinaryTreeFind(BTNode* root, char x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	//左子树找
	BTNode* leftret = BinaryTreeFind(root->left, x);
	if (leftret)
	{
		return leftret;
	}
	//右子树找
	BTNode* rightret = BinaryTreeFind(root->right, x);
	if (rightret)
	{
		return rightret;
	}
	return NULL;
}

 

层序遍历

  • 依托队列实现
  • 首先将根结点入队列
  • 出队列,同时记录队头值,并将其左右子结点入队列
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	//根结点入队列
	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
	//出队列,同时记录队头值
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->data);
	//将其左右子结点入队列
		if (front->left)
			QueuePush(&q, front->left);

		if (front->right)
			QueuePush(&q, front->right);
	}

	QueueDestroy(&q);
}

 

判断是否为完全二叉树

  • 先进行层序遍历,遇到空结点就停止
  • 如果队列中存在有效元素,则不为完全二叉树
    在这里插入图片描述
bool TreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	//先进行层序遍历,遇到空结点就停止
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
			break;
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}
	//检查队列中是否还存在有效数据
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

 

二叉树的构建及遍历

  • 参考字符串为前序,自然也通过前序构建
  • 遇到 ‘#’ 则只向后移动字符串指针,返回空
// 二叉树的构建及遍历
// 二叉树的构建及遍历
BTNode* FormTree(char* pc, int* pi)
{
	//遇到'#'返回空指针,继续向后遍历字符串
	if (pc[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	//遇到非'#'则开始构建树,同样按照前序构建
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	node->data = pc[*pi];
	(*pi)++;
	node->left = FormTree(pc, pi);
	node->right = FormTree(pc, pi);
	return node;
}
//中序打印
void InOrder1(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder1(root->left);
	printf("%c ", root->data);
	InOrder1(root->right);
}

int main() {
	char ch[100] = { 0 };
	while (scanf("%s", ch) != EOF)
	{
		int i = 0;
		BTNode* tree = FormTree(ch, &i);
		InOrder1(tree);
		printf("\n");
	}

	return 0;
}

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值