数据结构详解(其八) 二叉树

如何由中序遍历和后序遍历推出前序遍历?

1.由后续遍历确定头结点。

2.根据头结点在中序遍历中的位置划分出左右子树

3.循环上诉两步画出完整二叉树。

4.由二叉树写成前序遍历

 BinaryTree.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include"Queue.h"

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;//存储左子树的地址
	struct BinaryTreeNode* right;//存储右子树的地址
	BTDataType data;//存储数据
}BTNode;

BTNode* BuyNode(BTDataType x);//创建节点函数

void PreOrder(BTNode* root);//前序遍历
void InOrder(BTNode* root);//中序遍历
void PostOrder(BTNode* root);//后序遍历

int TreeSize(BTNode* root);//计算节点个数
int TreeLeafSize(BTNode* root);//计算叶子节点个数
int TreeKLevel(BTNode* root, int k);//计算第k层的节点个数

int TreeDepth(BTNode* root);//求二叉树的深度(高度)

BTNode* TreeFind(BTNode* root, BTDataType x);//查找二叉树中为x的结点

void TreeDestroy(BTNode* root);//销毁函数

void LevelOrder(BTNode* root);//二叉树的层序遍历
bool TreeComplete(BTNode* root);//判断一颗树是否是完全二叉树

BinaryTree.c

#include "BinaryTree.h"



BTNode* BuyNode(BTDataType x)//创建节点函数
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	assert(newnode);//malloc开辟空间有可能失败需要检查

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

	return newnode;
}

void PreOrder(BTNode* root)//前序遍历
{
	if (root == NULL)//遇到空时打印 #
	{
		printf("# ");
		return;
	}

	printf("%d ", root->data);//打印根
	PreOrder(root->left);//访问左子树
	PreOrder(root->right);//访问右子树
}
void InOrder(BTNode* root)//中序遍历
{
	if (root == NULL)//遇到空时打印 #
	{
		printf("# ");
		return;
	}

	InOrder(root->left);//访问左子树
	printf("%d ", root->data);//打印根
	InOrder(root->right);//访问右子树
}
void PostOrder(BTNode* root)//后序遍历
{
	if (root == NULL)//遇到空时打印 #
	{
		printf("# ");
		return;
	}

	PostOrder(root->left);//访问左子树
	PostOrder(root->right);//访问右子树
	printf("%d ", root->data);//打印根
}

int TreeSize(BTNode* root)//计算节点个数
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;//经典的后序遍历
}

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);
}

int TreeKLevel(BTNode* root, int k)//计算第k层的节点个数
{
	assert(k >= 1);//一定要检查传入K的范围。

	if (root == NULL) //递归一定要设置结束条件
		return 0;
	if (k == 1)
		return 1;

	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}

int TreeDepth(BTNode* root)//求二叉树的深度(高度)
{
	if (root == NULL) //递归一定要设置结束条件
		return 0;

	int leftDepth = TreeDepth(root->left);
	int rightDepth = TreeDepth(root->right);

	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

BTNode* TreeFind(BTNode* root, BTDataType x)//查找二叉树中第一个为x的结点
{
	if (root == NULL)
		return NULL;

	if (root->data == x)
		return root;

	//return TreeFind(root->left, x) || TreeFind(root->right, x);//不能这样写,NULL也会被返回

	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;

	return NULL;
	
}

void TreeDestroy(BTNode* root)//销毁函数
{
	if (root == NULL)
		return;
	TreeDestroy(root->left);
	TreeDestroy(root->right);
	free(root);//销毁左右子树后,再销毁根节点(经典后序)
}

void LevelOrder(BTNode* root)//二叉树的层序遍历
{
	Queue q;//创建一个队列
	QueueInit(&q);//初始化队列

	if (root)
		QueuePush(&q, root);//如果节点不为空,节点入队
	
	while (!QueueEmpty(&q))//如果队列不为空,继续遍历
	{
		BTNode* front = QueueFront(&q);//取出队头节点
		printf("%d ", front->data);//打印
		QueuePop(&q);//出队列

		if(front->left)
			QueuePush(&q, front->left);//如果左孩子节点不为空,左孩子节点入队
		if (front->right)
			QueuePush(&q, front->right);//如果右孩子节点不为空,右孩子节点入队
	}
	putchar(10);//换行

	QueueDestroy(&q);//使用完后一定要记得销毁队列。
}

bool TreeComplete(BTNode* root)//判断一颗树是否是完全二叉树
{
	Queue q;//创建一个队列
	QueueInit(&q);//初始化队列

	if (root)
		QueuePush(&q, root);//如果节点不为空,节点入队

	while (!QueueEmpty(&q))//如果队列不为空,继续遍历
	{
		BTNode* front = QueueFront(&q);//取出队头节点
		QueuePop(&q);//出队列 (Pop的是链式队列的结点,和结点里的内容(二叉树的节点)无关)
		
		if (front == NULL)//遇到NULL,跳出循环
			break;
		else
		{
			QueuePush(&q, front->left);//无论左孩子节点为不为空,左孩子节点入队
			QueuePush(&q, front->right);//无论右孩子节点为不为空,右孩子节点入队
		}	
	}

	//如果队列不为空,且队列中的所有元素全为空,则是完全二叉树
	while (!QueueEmpty(&q))//如果队列不为空,继续遍历
	{
		BTNode* front = QueueFront(&q);//取出队头节点
		QueuePop(&q);//出队列

		if (front)//如果在空后遇到非空
		{
			QueueDestroy(&q);//销毁队列
			return false;
		}
	}

	//如果顺利队列清空,说明在层序遍历中没有遇到 NULL 后还有 非NULL 的情况,证明该树是完全二叉树。
	QueueDestroy(&q);//使用完后一定要记得销毁队列。
	return true;
}

BinaryTreeTest.c(测试用例)

测试用例里构建的二叉树:

#include"BinaryTree.h"

int main()
{
	//建立一颗二叉树。
	BTNode* root = BuyNode(1);
	BTNode* n2 = BuyNode(2);
	BTNode* n3 = BuyNode(3);
	BTNode* n4 = BuyNode(4);
	BTNode* n5 = BuyNode(5);
	BTNode* n6 = BuyNode(6);
	BTNode* n7 = BuyNode(7);

	root->left = n2;
	root->right = n4;
	n2->left = n3;
	n2->right = n7;
	n4->left = n5;
	n4->right = n6;

	//前序遍历
	printf("前序遍历:");
	PreOrder(root);
	putchar(10);
	//中序遍历
	printf("中序遍历:");
	InOrder(root);
	putchar(10);
	//后序遍历
	printf("后序遍历:");
	PostOrder(root);
	putchar(10);

	//计算节点个数
	printf("该树有%d个节点。\n",TreeSize(root));
	//计算叶子节点个数
	printf("该树有%d个叶子节点。\n", TreeLeafSize(root));

	//求二叉树的深度(高度)
	printf("该树的高度为(设根节点的高度为1):%d\n", TreeDepth(root));

	//计算第k层的节点个数
	printf("你想要计算第几层的节点:");
	int k = 0;
	scanf("%d", &k);
	printf("该树第%d层有%d个节点。\n", k, TreeKLevel(root, k));

	//查找二叉树中第一个为x的结点
	printf("你想要查找二叉树中的哪个节点,请输入节点存储的值:");
	int x = 0;
	scanf("%d", &x);
	BTNode* f = TreeFind(root, x);
	if (f != NULL)
		printf("二叉树中第一个为%d的节点的地址为:%p。\n", f->data, f);
	else
		printf("未找到该节点\n");


	//二叉树的层序遍历
	printf("层序遍历:");
	LevelOrder(root);

	//判断一棵树是否是完全二叉树。
	if(TreeComplete(root))
		printf("该树是一颗完全二叉树\n");
	else
		printf("该树不是一颗完全二叉树\n");


	//销毁函数
	TreeDestroy(root);
	return 0;
}

结果展示: 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烛火萤辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值