★ 数据结构 ★ 二叉树(下)

Ciallo~(∠・ω< )⌒☆ ~ 今天,我将继续和大家一起学习数据结构中的二叉树~

目录

[一 二叉树链式结构的实现](#一 二叉树链式结构的实现)

[二 二叉树的遍历](#二 二叉树的遍历)

[2.1 前序、中序以及后序遍历](#2.1 前序、中序以及后序遍历)

[2.2 层序遍历](#2.2 层序遍历)

[三 二叉树实现的一些函数](#三 二叉树实现的一些函数)

[3.1 二叉树结点个数](#3.1 二叉树结点个数)

[3.2 二叉树叶子结点个数](#3.2 二叉树叶子结点个数)

[3.3 二叉树层数](#3.3 二叉树层数)

[3.4 二叉树第k层结点个数](#3.4 二叉树第k层结点个数)

[3.5 二叉树查找值为x的结点](#3.5 二叉树查找值为x的结点)

3.6二叉树的销毁

[3.7 判断二叉树是否是完全二叉树](#3.7 判断二叉树是否是完全二叉树)

[四 二叉树的一些选择题](#四 二叉树的一些选择题)


一 二叉树链式结构的实现

二叉树的基本结构:

cpp 复制代码
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType a;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

手动快速创建一棵简单的二叉树的方式~

cpp 复制代码
BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	return node1;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序讲解。

二 二叉树的遍历

2.1 前序、中序以及后序遍历

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

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

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

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

以上树为例,

  • 前序遍历的访问顺序应为:1 2 3 N N N 4 5 N N 6 N N
  • 中序遍历的访问顺序应为:N 3 N 2 N 1 N 5 N 4 N 6 N
  • 后序遍历的访问顺序应为:N N 3 N 2 N N 5 N N 6 4 1
cpp 复制代码
// 二叉树前序遍历
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->a);
	PreOrder(root->left);
	PreOrder(root->right);
} // 1 2 3 N N N 4 5 N N 6 N N

同理:~

cpp 复制代码
// 二叉树中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->a);
	InOrder(root->right);
} // N 3 N 2 N 1 N 5 N 4 N 6 N

// 二叉树后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->a);
} // N N 3 N 2 N N 5 N N 6 4 1

2.2 层序遍历

**层序遍历:**除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

核心为节点出栈时把子节点入栈。

cpp 复制代码
typedef struct BinaryTreeNode* QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;
cpp 复制代码
// 层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->a);

		if (front->left)
			QueuePush(&q, front->left);
		if (front->right)
			QueuePush(&q, front->right);
	}
	QueueDestory(&q);
}

三 二叉树实现的一些函数

3.1 二叉树结点个数

按遍历的方法我们可以得到以下程序:

cpp 复制代码
// 二叉树结点个数
int size = 0; // 放在全局
int BinaryTreeSize(BTNode* root)
{
	static int size = 0;
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		++size;
	}
	BinaryTreeSize(root->left);
	BinaryTreeSize(root->right);
	return size;
}

然而此程序的全局变量size每次使用都要置为0, 若放在函数内定义为static int 则多次调用就会报错,解决方法为再传一个指针变量 ,或者写如下更好的写法

因为节点个数只有两种情况,为空--0,不为空--左子树+右子树+1

3.2 二叉树叶子结点个数

cpp 复制代码
// 二叉树叶子结点个数
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);
}

3.3 二叉树层数

cpp 复制代码
// 二叉树层数
int BinaryTreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	// 直接写return效率很差~ 会重复调用很多次~
	//return BinaryTreeHeight(root->left) > BinaryTreeHeight(root->right) ?
		//BinaryTreeHeight(root->left) + 1 : BinaryTreeHeight(root->right);
	int left = BinaryTreeHeight(root->left);
	int right = BinaryTreeHeight(root->right);
	return left > right ? left + 1 : right + 1;
}

3.4 二叉树第k层结点个数

cpp 复制代码
// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1) // 每次到底返回1
	{
		return 1;

	}
	return BinaryTreeLevelKSize(root->left, k - 1)
		+ BinaryTreeLevelKSize(root->right, k - 1);
}

3.5 二叉树查找值为x的结点

cpp 复制代码
// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->a == x)
	{
		return root;
	}
	BTNode* ret1 = BinaryTreeFind(root->left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = BinaryTreeFind(root->right, x);
	if (ret2)
		return ret2;
	return NULL;
}

要接收找到后的返回值~ 前序遍历~

3.6二叉树的销毁

cpp 复制代码
void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);
}

利用后序销毁

3.7 判断二叉树是否是完全二叉树

  • 层序遍历走,空也进队列
  • 遇到第一个空节点时,开始判断,后面空就是完全二叉树,后面有非空就不是完全二叉树。

不可能出现遇到空时后面还有非空没进队列,后面的非空一定时前面非空的孩子,层序出到空时,前面非空都出完了,那他的孩子一定进堆列了。

cpp 复制代码
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(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;
}

四 二叉树的一些选择题

**1.**某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( B )

A . 不存在这样的二叉树 B. 200 C. 198 D. 199

对任何一棵二叉树, 如果度为0其叶结点个数为n1, 度为2的分支结点个数为n2 ,则有 n1= n2+1,199+1 = 200

**2.**下列数据结构中,不适合采用顺序存储结构的是( A )

A .非完全二叉树 B. 堆 C .队列 D. 栈

**3.**在具有 2n 个结点的完全二叉树中,叶子结点个数为( A )

A .n B. n+1 C .n-1 D. n/2

**4.**一个具有767个结点的完全二叉树,其叶子结点个数为( B )

A .383 B .384 C .385 D .386

**5.**一棵完全二叉树的结点数位为531个,那么这棵树的高度为( B )

A. 11 B. 10 C. 8 D. 12

2 ^( h - 1) ~ 2 ^ h - 1

**6.**给前序和中序确定二叉树的方法

~完~

相关推荐
喵叔哟15 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生21 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
hopetomorrow35 分钟前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
小牛itbull1 小时前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
闲暇部落1 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
chnming19871 小时前
STL关联式容器之set
开发语言·c++
带多刺的玫瑰1 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
爱敲代码的憨仔1 小时前
《线性代数的本质》
线性代数·算法·决策树