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

目录

二叉树的遍历

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;
}
相关推荐
老大白菜23 分钟前
python 选择排序(Selection Sort)
python·算法·排序算法
酒鬼猿24 分钟前
基础算法--滑动窗口
算法
叶子20242235 分钟前
labelme下载
java·jvm·算法
计算机萍萍学姐1 小时前
ArrayList和LinkedList的区别是什么?
java·数据结构·算法
程序员南飞2 小时前
算法-excel表头位置转成对应数字 26进制转10进制
java·javascript·算法
老大白菜3 小时前
python 插入排序(Insertion Sort)
python·算法·排序算法
苍墨穹天3 小时前
大模型算法题(2)
人工智能·算法
打不了嗝 ᥬ᭄3 小时前
位运算与操作符应用
数据结构·算法·leetcode·蓝桥杯
风染yeye3 小时前
区块链期末复习3:跨链原子交换&其他加密货币
算法·区块链·密码学·分布式账本