前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据结构(二叉树的链式结构)

数据结构(二叉树的链式结构)

作者头像
用户11289931
发布2024-09-24 16:35:32
590
发布2024-09-24 16:35:32
举报
文章被收录于专栏:学习

链式结构的二叉树

⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。

通常的⽅法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩⼦所在的链结点的存储地址, 其结构如下:

代码语言:javascript
复制
typedef int BTDataType;
// ⼆叉链
typedef struct BinaryTreeNode
{
 struct BinTreeNode* left; // 指向当前结点左孩⼦ 
 struct BinTreeNode* right; // 指向当前结点右孩⼦ 
 BTDataType val; // 当前结点值域 
}BTNode;

⼆叉树的创建⽅式

⼆叉树的创建⽅式⽐较复杂,其运用了大量的递归知识。为了更好的步⼊到⼆叉树内容中,我们先⼿动创建⼀棵链式⼆叉树:

代码语言:javascript
复制
BTNode* buyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->left = newnode->right = NULL;

	return newnode;
}

BTNode* CreateTree()
{
 BTNode* n1 = BuyBTNode(1);
 BTNode* n2 = BuyBTNode(2);
 BTNode* n3 = BuyBTNode(3);
 BTNode* n4 = BuyBTNode(4);
 BTNode* n5 = BuyBTNode(5);
 BTNode* n6 = BuyBTNode(6);
 BTNode* n7 = BuyBTNode(7);
 n1->left = n2;
 n1->right = n4;
 n2->left = n3;
 n4->left = n5;
 n4->right = n6;
 n5->left = n7;
 return n1;
}

我们再来回顾一下⼆叉树的概念:

⼆叉树分为空树和⾮空⼆叉树,⾮空⼆叉树由根结点、根结点的左⼦树、根结点 的右⼦树组成的

根结点的左⼦树和右⼦树分别⼜是由⼦树结点、⼦树结点的左⼦树、⼦树结点的右⼦树组成的,因此,⼆叉树定义是递归式的,后序链式⼆叉树的操作中基本都是按照该概念实现的。


前中后序遍历

⼆叉树的操作离不开树的遍历,下面我们先来看看⼆叉树的遍历有哪些⽅式:

遍历规则:

按照规则,⼆叉树的遍历有:前序/中序/后序的递归结构遍历: 1)前序遍历(PreorderTraversal亦称先序遍历):访问根结点的操作发⽣在遍历其左右⼦树之前 访问顺序为:根结点、左⼦树、右⼦树 2)中序遍历(InorderTraversal):访问根结点的操作发⽣在遍历其左右⼦树之中(间) 访问顺序为:左⼦树、根结点、右⼦树 3)后序遍历(PostorderTraversal):访问根结点的操作发⽣在遍历其左右⼦树之后  访问顺序为:左⼦树、右⼦树、根结点

前序遍历

代码语言:javascript
复制
void PreOrder(BTNode* root)
{
 if (root == NULL)
 {
 printf("N ");
 return;
 }
 printf("%d ", root->val);
 PreOrder(root->left);
 PreOrder(root->right);
}

中序遍历

代码语言:javascript
复制
void InOrder(BTNode* root)
{
 if (root == NULL)
 {
 printf("N ");
 return;
 }
 InOrder(root->left);
 printf("%d ", root->val);
 InOrder(root->right);
}

后序遍历

代码语言:javascript
复制
void PostOrder(BTNode* root)
{
 if (root == NULL)
 {
 printf("N ");
 return;
 }
 InOrder(root->left);
 InOrder(root->right);
 printf("%d ", root->val);
}
图解遍历:

以前序遍历为例子:

函数递归的栈帧图:

前序遍历结果:1 2 3 4 5 6 中序遍历结果:3 2 1 5 4 6 后序遍历结果:3 1 5 6 4 1

结点的个数及其高度

代码语言:javascript
复制
// ⼆叉树结点个数 
int BinaryTreeSize(BTNode* root); 
// ⼆叉树叶⼦结点个数 
int BinaryTreeLeafSize(BTNode* root); 
// ⼆叉树第k层结点个数 
int BinaryTreeLevelKSize(BTNode* root, int k); 
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);
// ⼆叉树查找值为x的结点 
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root);

以下是其的实现方式:

代码语言:javascript
复制
// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
// ⼆叉树叶⼦结点个数
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);
}

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

	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) 
		+ BinaryTreeLevelKSize(root->right, k - 1);
}
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDep = BinaryTreeDepth(root->left);
	int rightDep = BinaryTreeDepth(root->right);

	return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}

	BTNode* leftFind =  BinaryTreeFind(root->left, x);
	if (leftFind)
	{
		return leftFind;
	}
	BTNode* rightFind =  BinaryTreeFind(root->right, x);
	if (rightFind)
	{
		return rightFind;
	}
	return NULL;
}

// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));

	free(*root);
	*root = NULL;
}

层序遍历

设⼆叉树的根结点所在层数为1,层序遍历就是从所在⼆叉树的根结点出发,⾸先访问第⼀层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,⾃上⽽下,⾃左⾄右逐层访问树的结点的过程就是层序遍历

实现层序遍历需要额外借助数据结构:队列

下图为其实现的代码:

代码语言:javascript
复制
//层序遍历
//借助数据结构---队列
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	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);
	}
	//队列为空
	QueueDestroy(&q);
}

判断是否为完全二叉树

代码语言:javascript
复制
//判断二叉树是否为完全二叉树
//---队列
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	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 != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

结尾

以上便是本期的全部内容,感谢各位的观看与支持!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 链式结构的二叉树
    • ⼆叉树的创建⽅式
    • 前中后序遍历
      • 遍历规则:
        • 前序遍历
          • 中序遍历
            • 后序遍历
              • 图解遍历:
          • 结点的个数及其高度
          • 层序遍历
            • 判断是否为完全二叉树
            • 结尾
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档