【数据结构】二叉树链式结构(第三章)

🎆前言🎆

✨笔者也仅是大一萌新,写博客为了记录和巩固知识✨

🥰赠人玫瑰,手留余香,欢迎各位读者进行交流和建议🥰

🌹能与大家一起学习,一起进步是我的荣幸🌹

🤞如果这篇文章有帮助到您,还请留个赞支持一下哦🤞



preview


⭐目录

⭐二叉树的链式结构

🔎前情提要:

在前文中,我们学习了二叉树的顺序结构,但是顺序结构只能处理完全二叉树,如果要处理一棵普通的二叉树,那就要用到链式结构

二叉树会有两种情况:空数(一个值都没有) 非空树(由根结点,根节点的左子树、根节点的右子树组成),并且二叉树是递归式的,这也是我们遍历二叉树的重要知识点

image-20220423232845581

🔎二叉树遍历:

二叉树遍历是按照某种特定的规则,依次对二叉树的结点进行对应操作,并且每个结点只操作一次,遍历是二叉树进行其它运算的基础。

二叉树遍历具有三种方法:

  • 前序——根,左子树,右子树
  • 中序——左子树,根,右子树
  • 后序——左子树,右子树,根

以下面的图为例子,每一个数据它可以是根、左子树、右子树的任意一种

如:5可以作为根,它的左子树为NULL,右子树为NULL,6也可以作为根,它的左子树为5,右子树为3,所以一定要完全遵守方法进行遍历

image-20220424004613539

🔎前序:

前序的遍历顺序是:根,左子树,右子树

以上图数据(12 10 11 6 4 0 1 5 3 3)来看,它**前序遍历后的打印顺序为:12 10 6 5 NULL NULL 3 NULL NULL 4 NULL 3 NULL NULL 11 0 NULL NULL 1 NULL NULL(NULL是为了更好理解它的遍历过程,实际并不需要打印出来)**

image-20220424002508038

🔎中序:

前序的遍历顺序是:左子树,根,右子树

以数据(12 10 11 6 4 0 1 5 3 3)来看,它**中序遍历后的打印顺序为:NULL 5 NULL 6 NULL 3 NULL 10 NULL 4 NULL 3 NULL 12 NULL 0 NULL 11 NULL 1 NULL**

image-20220424003059389

🔎后序:

前序的遍历顺序是:左子树,右子树,根

以数据(12 10 11 6 4 0 1 5 3 3)来看,它**后序遍历后的打印顺序为:NULL NULL 5 NULL NULL 3 6 NULL NULL NULL 3 4 10 NULL NULL 0 NULL NULL 1 11 12**image-20220424003501444

遍历操作(代码环节)

🔎前期操作

这里引用了队列的头文件是方便之后进行层序遍历

#include "Queue.h"

typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left; //左孩子指针
	struct BinaryTreeNode* right; //右孩子指针
	QDataType data;
}BTNode;

BTNode* BuyBTNode(QDataType x) //扩容
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		printf("malloc fail!");
		exit(-1);
	}
	node->data = x;
	node->left = node->right = NULL;
	return node;
}

BTNode* CreatBinaryTree() //录入数据
{
	BTNode* node1 = BuyBTNode(12);
	BTNode* node2 = BuyBTNode(10);
	BTNode* node3 = BuyBTNode(11);
	BTNode* node4 = BuyBTNode(6);
	BTNode* node5 = BuyBTNode(4);
	BTNode* node6 = BuyBTNode(0);
	BTNode* node7 = BuyBTNode(1);
	BTNode* node8 = BuyBTNode(5);
	BTNode* node9 = BuyBTNode(3);
	BTNode* node10 = BuyBTNode(3);
	node1->left = node2;
	node1->right = node3;
	node2->left = node4;
	node2->right = node5;
	node3->left = node6;
	node3->right = node7;
	node4->left = node8;
	node4->right = node9;
	node5->right = node10;
	return node1;
}
🔎前序:

递归图(这玩意害得自己画,真要画出来可能除了自己别人也看不懂,笔者水平有限只能画成这样了,也只是给大家看下大概的思路,后面递归也不再画了,毕竟画了大家也看不懂😭,真有问题的话可以来问我哦💖):

image-20220427004813573

void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
🔎中序:
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
    InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
🔎后序:
void TailOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	TailOrder(root->left);
	TailOrder(root->right);
	printf("%d ", root->data);
}

⭐二叉树的大小

这里可以使用全局变量进行存储count,但是会存在线程安全问题,当在linux多线程中,别人不小心用了这个全局变量,就会出错,并且多次调用函数时,全局或者静态变量会继续上次的值进行运算

int BTreeSize(BTNode* root/*, int* pCount*/) //思路:每当遍历到了一个不为空的结点,就加一(遍历+计数)
{
	/*if (root == NULL)
	return;
	++(*pCount);
	BTreeSize(root->left, pCount);
	BTreeSize(root->right, pCount);*/
	
	//后序 最优
	return root == NULL ? 0 : BTreeSize(root->left) + 
		BTreeSize(root->right) + 1;
}

⭐二叉树的叶子大小

int BTreeLeafSize(BTNode* root) //思路:叶子大小就是度为0的结点,那么我们就判断该结点是否具有左子树和右子树
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}

二叉树的第K层大小

思路:求第K层大小,实际找到K-1层然后向下遍历一层即可,如求第4层,那么我们到第三层时开始遍历,此时第四层k等于1,如果该节点不为空,那么就会返回1回去

image-20220505223750525

int BTreeKLevelSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	else //转换成左子树k-1层节点个数 + 右子树k-1层节点个数
		return BTreeKLevelSize(root->left, k - 1) + BTreeKLevelSize(root->right, k - 1);
}

⭐二叉树的深度(高度)

int BTreeDepth(BTNode* root)//找最高的+1
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDepth = BTreeDepth(root->left);
	int rightDepth = BTreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

⭐二叉树的搜索

类似于前序递归,根–>左树–>右树的方式查找,并且返回指针,如果没有找到就返回空。

BTNode* BTreeFind(BTNode* root, QDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* ret1 = BTreeFind(root->left, x);
	if (ret1)
	{
		return ret1;
	}
	BTNode* ret2 = BTreeFind(root->right, x);
	if (ret2)
	{
		return ret2;
	}
	return NULL;
}

判断是否为完全二叉树

bool BTreeComplete(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)
		{
			QueueDestory(&q);
			return false;
		}
	}

	QueueDestory(&q);
	return true;
}

⭐层序遍历

void LevelOreder(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);
		}
	}
	printf("\n");
	QueueDestory(&q);
}

二叉树销毁

void BTreeDestory(BTNode* root) //root只是一个形参
{
	if (root == NULL)
	{
		return;
	}

	BTreeDestory(root->left);
	BTreeDestory(root->right);
	free(root); 
}

⭐主函数

	BTNode* tree = CreatBinaryTree();

	PrevOrder(tree);
	printf("\n");

	InOrder(tree);
	printf("\n");

	TailOrder(tree);
	printf("\n");

	/*int count = 0; //每次使用都要先置0一次
	BTreeSize(tree, &count);
	printf("%d\n", count);*/

	int count1 = BTreeSize(tree);
	printf("size = %d\n", count1);

	int count2 = BTreeLeafSize(tree);
	printf("leaf size = %d\n", count2);

	int count3 = BTreeKLevelSize(tree, 3);
	printf("No.2 size = %d\n", count3);

	int count4 = BTreeDepth(tree);
	printf("depth = %d\n", count4);

	for (int i = 1; i <= 10; i++)
	{
		printf("Find:%d,%p\n",i,BTreeFind(tree, i));
	}
	BTNode* ret = BTreeFind(tree, 5);

	printf("Find:%p\n", BTreeFind(tree, 50));
	if (ret)
	{
		ret->data = 50;
	}
	printf("Find:%p\n", BTreeFind(tree, 50));

	LevelOrder(tree);
	printf("完全二叉树:%d\n", BTreeComplete(tree));

	BTreeDestory(tree); //传一级没法完全置空,出来后还需要置空一次
	tree = NULL; //这里置空才起作用

	return 0;
  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

A.A呐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值