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

目录

二叉树的遍历

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

2.二叉树销毁

[3. 二叉树节点个数](#3. 二叉树节点个数)

[4. 二叉树叶子节点的个数](#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;
}
相关推荐
杨连江4 分钟前
原子级平面限域协同晶核诱导定向生长单层鳞片石墨的研究
算法
MATLAB代码顾问10 分钟前
混合粒子群-模拟退火算法(HPSO-SA)求解作业车间调度问题——附MATLAB代码
算法·matlab·模拟退火算法
Felven14 分钟前
C. Prefix Min and Suffix Max
算法
加农炮手Jinx14 分钟前
LeetCode 26. Remove Duplicates from Sorted Array 题解
算法·leetcode·力扣
加农炮手Jinx15 分钟前
LeetCode 88. Merge Sorted Array 题解
算法·leetcode·力扣
Hhy_110715 分钟前
【从零开始学习数据结构 ④】:栈 ——后进先出的艺术
c语言·数据结构·学习·visual studio
格林威15 分钟前
线阵工业相机:如何计算线阵相机的行频(Line Rate)?公式+实例
开发语言·人工智能·数码相机·算法·计算机视觉·工业相机·线阵相机
yueyue54318 分钟前
透过现象看本质:以fast_lio架构的整套算法的局部避障改为TEB算法为例深度探讨——如何成为一个合格的算法架构师?
算法·架构
梨花爱跨境18 分钟前
红人视频×A10算法:亚马逊转化率与流量闭环实战
算法
海清河晏11120 分钟前
数据结构 | 链式队列
开发语言·数据结构·链表