当前位置: 首页 > article >正文

数据结构:二叉树部分接口(链式)

目录

二叉树的遍历

 1.通过前序遍历的数据构造二叉树

2.二叉树销毁

3. 二叉树节点个数 

4. 二叉树叶子节点的个数

5.二叉树第k层节点个数

6.二叉树查找值为x的节点

7.二叉树的前/中/后序遍历

8.层序遍历 

 9.判断二叉树是否是完全二叉树


二叉树的遍历

前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

这里的二叉树接口是二叉树部分功能的实现,并不是链式二叉树的增删改查

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode** root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

 1.通过前序遍历的数据构造二叉树

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
//                        a指的是数组       *pi 指的是数组里元素个数
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
//若为'#'则*pi++,并且返回空
	if (a[(*pi)] == '#')
	{
		(*pi)++;
		return NULL;
	}

	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->_data = a[(*pi)++];
	root->_left = BinaryTreeCreate(a,pi);
	root->_right = BinaryTreeCreate(a, pi);

	return root;

2.二叉树销毁

// 二叉树销毁 
void BinaryTreeDestory(BTNode** root)
{
	if (*root)
	{
   // 注意这里是二级指针
		BinaryTreeDestory(&(*root)->_left);
		BinaryTreeDestory(&(*root)->_right);
		free(*root);
		*root = NULL;
	}
}

3. 二叉树节点个数 

通过递归求节点个数

/ 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	return BinaryTreeSize(root->_left)+ BinaryTreeSize(root->_right)+1;

}

4. 二叉树叶子节点的个数

一个节点没有孩子则为叶子节点

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	if (root->_left == NULL && root->_right == NULL)
	{
		return 1;
	}

	return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}

5.二叉树第k层节点个数

(根节点为第一层,第二层为其孩子节点....依次往下递增)

二叉树第k层节点 ==  左孩子的第k-1层 + 右孩子的第k-1层节点

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
  
	if (root == NULL)
	{
		return 0;
	}

 //当k == 1 时, 即为第k层的节点
	if (k == 1)
	{
		return 1;
	}

	return BinaryTreeLevelKSize(root->_left, k - 1)+ BinaryTreeLevelKSize(root->_right,k-1);
}

6.二叉树查找值为x的节点

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	BTNode* ret;
	if (root == NULL)
	{
		return NULL;
	}
	//根节点查找
	if (root->_data == x)
	{
		return root;
	}
	
   //根节点找不到,则左孩子查找
	ret = BinaryTreeFind(root->_left, x);
  // 若找到此节点,则ret不为空,直接返回该地址
	if (ret)
		return ret;

 //左海子找不到,则右孩子查找
	ret = BinaryTreeFind(root->_right, x);
	if (ret)
 // 若找到此节点,则ret不为空,直接返回该地址
		return ret;

 //都找不到返回空
	return NULL;
}

7.二叉树的前/中/后序遍历

 

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	printf("%d ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);

}

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreeInOrder(root->_left);
	printf("%d ", root->_data);
	BinaryTreeInOrder(root->_right);

}

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%d ", root->_data);
}

8.层序遍历 

层序遍历需要创建一个队列(尾进头出),插入根节点到队列中,然后打印头结点,接着插入其左孩子节点,最后删除头节点,以此循坏,直到队列为空。

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("此二叉树为空\n");
		return;
	}

 // 创造队列
	Queue qu;
	QueueInit(&qu);

 //创造一个变量记住队列中头节点
	BTNode* cur;

 // 插入根节点
	QueuePush(&qu, root);
  //若队列不为空,则循坏
	while (!QueueEmpty(&qu))
	{
     //找到队列的头节点
		cur = QueueFront(&qu);
		printf("%c ", cur->_data);
		
     //插入头节点的左孩子(左孩子不为空)
		if (cur->_left)
		{
			QueuePush(&qu, cur->_left);
		}
     //插入头节点的右孩子(右孩子不为空)
		if (cur->_right)
		{
			QueuePush(&qu, cur->_right);

		}
      //删除头节点
		QueuePop(&qu);
	}
	printf("\n");
	QueueDestroy(&qu);
}

 9.判断二叉树是否是完全二叉树

思想:创建一个队列,插入头结点之后,再出头节点,接着再插入其左右孩子节点,一直循坏该操作,知道队列中删除的元素为空时退出循坏,此时的队列并不为空,接着继续判断队列后面的元素是否都为空,若都为空则为完全二叉树,反之则不是

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
  //创造一个队列
	Queue qu;
	QueueInit(&qu);
  // 若树的根节点不为空,则插入到队列中
	if (root)
	{
		QueuePush(&qu, root);
	}
 
 //创造一个变量来记住队列中的头元素
	BTNode* front;

	//队列插入一层,出一个结点进两个孩子,若有空则退出循坏
	while (!QueueEmpty(&qu))
	{
      //  front = 队列中头元素
		front = QueueFront(&qu);
     //删除队列的头结点
		QueuePop(&qu);
    //若头元素为空则退出循坏
		if (front == NULL)
		{
			break;
		}

	//插入左右孩子
		QueuePush(&qu, front->_left);
		QueuePush(&qu, front->_right);
		

	}


	//判断空后是否继续为空
	while (!QueueEmpty(&qu))
	{
		front = QueueFront(&qu);
		QueuePop(&qu);

    //若front不为空,则不是完全二叉树
		if (front != NULL)
		{
			QueueDestroy(&qu);
			return false;
		}

	}
  
   //都为空,则返回true
	QueueDestroy(&qu);
	return true;
}


http://www.kler.cn/a/457114.html

相关文章:

  • 在线免费批量生成 Word 文档工具
  • Excel文件恢复教程:快速找回丢失数据!
  • streamlit、shiny、gradio、fastapi四个web APP平台体验
  • ASP.NET Core Web API Hangfire
  • 拓展C盘内存的方法(C盘旁边不一定是D盘)
  • vue中使用exceljs组件库导入导出json到excel
  • 力扣算法--求两数之和等于目标数
  • MySQL的TIMESTAMP类型字段非空和默认值属性的影响
  • 用科技的方法能否实现真正的智能
  • DAY3 QT简易登陆界面优化
  • blender中合并的模型,在threejs中显示多个mesh;blender多材质烘培成一个材质
  • Debian 12 安装配置 fail2ban 保护 SSH 访问
  • 数据安全中间件的好处
  • OpenCV-Python实战(6)——图相运算
  • adb无线连接手机后scrcpy连接报错ERROR: Could not find any ADB device
  • Debian-linux运维-docker安装和配置
  • HarmonyOS NEXT 实战之元服务:静态案例效果---我的订阅每日咨询
  • 打造智能化恶意软件检测桌面系统:从数据分析到一键报告生成
  • 外网访问 Docker 容器的可视化管理工具 DockerUI
  • 郴州年夜饭大数据分析:Python爬虫的美味之旅
  • 大模型的实践应用33-关于大模型中的Qwen2与Llama3具体架构的差异全解析
  • 基于 Ragflow 搭建知识库-初步实践
  • 贪心算法解决单调递增数字问题
  • Vivado常用IP例化1
  • Go语言zero项目服务恢复与迁移文档
  • 谈谈前端对链表的理解