数据结构二叉树之链式结构(3)(下)

文章目录

个人主页:星轨初途

个人专栏:C语言数据结构

前言

嗨٩(๑❛ᴗ❛๑)۶,我们又见面啦,上一篇我们了解到二叉树链式结构的概念及二叉树遍历方式,数据结构二叉树之链式结构(3)(上),今天我们就来继续了解二叉树的的相关功能以及实现,让我们一起来了解它吧!

本篇相关的知识点,需要的自取

传送门:
栈与队列核心篇(下):从基础到进阶,玩转队列设计
栈与队列核心篇(上):从原理到代码,吃透栈结构
数据结构之初识二叉树(1)------核心概念入门
数据结构二叉树之链式结构(3)(上)

一、二叉树链式结构的实现

我们上一篇已经手动构造了一个链式二叉树,这里就不再讲啦

c 复制代码
#include<stdio.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	node->data = x;
	node->left = NULL;
	node->right = NULL;
	return node;
}
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;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	return 0;
}

图相

1、统计二叉树结点个数

我们想统计二叉树的节点个数,我们第一时间就想到定义一个变量size来遍历进行查找

(1)、用局部变量进行统计

c 复制代码
int TreeSize(BTNode* root)
{
	int size = 0;
	if (root == NULL)
		return 0;
	else
		++size;

	TreeSize(root->left);
	TreeSize(root->right);

	return size;
}

我们不用看结果就知道size为0,因为每次调用都会被初始化,那我们可以尝试把它变成全局变量

(2)、用全局变量进行统计

c 复制代码
int size = 0;
int TreeSize(BTNode* root)
{
	
	if (root == NULL)
		return 0;
	else
		++size;

	TreeSize(root->left);
	TreeSize(root->right);

	return size;
}

或者

c 复制代码
int TreeSize(BTNode* root)
{
	static int size = 0;
	if (root == NULL)
		return 0;
	else
		++size;

	TreeSize(root->left);
	TreeSize(root->right);

	return size;
}

这两个效果一样,我们来验证一下

c 复制代码
int main()
{
	BTNode* root = CreatBinaryTree();
	printf("%d\n", TreeSize(root));
	return 0;
}

结果,好像也对,但是我们再调用一次呢

c 复制代码
int main()
{
	BTNode* root = CreatBinaryTree();
	printf("%d\n", TreeSize(root));
	printf("%d\n", TreeSize(root));
	return 0;
}

我们发现因为全局变量,导致第二次重复加了,我们该怎么解决呢

(3)、给结构体加一个变量

c 复制代码
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	int size;
}BTNode;

这样会大大扩大二叉树所占的空间,并不划算,那有没有更好的方法呢?

给函数添加一个新的变量size进行统计

c 复制代码
void TreeSize(BTNode* root, int* psize)
{
	if (root == NULL)
		return 0;
	else
		++(psize);

	TreeSize(root->left, psize);
	TreeSize(root->right, psize);
}
int main()
{
	int size = 0;
	TreeSize(root, size);
	printf("TreeSize:%d\n",size);
	return 0;
}	

为什么是0呢?

哦~,原来要传地址才能改变size的值

所以我们进行改正

c 复制代码
void TreeSize(BTNode* root, int* psize)
{
	if (root == NULL)
		return 0;
	else
		++(*psize);

	TreeSize(root->left, psize);
	TreeSize(root->right, psize);
}
int main()
{
	int size = 0;
	TreeSize(root, &size);
	printf("TreeSize:%d\n",size);
	return 0;
}	

正确

调用两回,需要重新初始化

c 复制代码
int main()
{
	int size = 0;
	TreeSize(root, &size);
	printf("TreeSize:%d\n",size);
	size = 0;
TreeSize(root, &size);
printf("TreeSize:%d\n", size);
	return 0;
}	

每次初始化很麻烦,我们还有没有其他简单的方法?有的

(4)递归实现(最优)

如果不创建新的变量,用递归实现,遍历二叉树,若为空返回0,非空返回1(自己)+左右两个子树的节点个数

代码如下:

c 复制代码
//二叉树结点个数 = 1 + 左子树结点个数 + 右子树结点个数 
int TreeSize(BTNode* root)
{
	if (root == 0)
	{
		return 0;
	}
	return 1 + TreeSize(root->left) + TreeSize(root->right);
}
int main()
{
	BTNode* root = CreatBinaryTree();
	
	printf("%d\n", TreeSize(root));
	printf("%d\n", TreeSize(root));
	return 0;
}
	

结果

正确

2、二叉树叶子结点个数

思路

这里我们还是用递归来写

如果左右子节点都为NULL,就证明是叶子节点,返回1

如果该节点为NULL空节点,返回0,

除此就是不是叶子了,返回左子树+右子树的节点数之和
代码

c 复制代码
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return TreeLeafSize(root->left)
		+ TreeLeafSize(root->right);
}
int main()
{
	BTNode* root = CreatBinaryTree();
	printf("%d\n", TreeLeafSize(root));
	return 0;
}

结果,结合图形我们知道正确

3、二叉树第K层节点个数

我们还递归遍历,但我们怎么知道遍历到了第K层了呢,我们只需要再把k-1传到函数中,当k减到1时就是我们需要的那一层

如当k=3时

代码

c 复制代码
// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	// 子问题
	return TreeLevelKSize(root->left, k - 1)
		+ TreeLevelKSize(root->right, k - 1);
}
int main()
{
	BTNode* root = CreatBinaryTree();
	int k;
	scanf("%d",&k);
	printf("%d\n", TreeLevelKSize(root,k));
	return 0;
}

结果

4、二叉树的高度

求二叉树的高度,就是看最高的一条,也就是本身节点加上左右树中高度高的那个

用代码实现

c 复制代码
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	return TreeHeight(root->left) > TreeHeight(root->right) ?
		TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}

而这个代码最后返回时先比较再决定返回哪个,但是因为没有保存数值,还要再算一次,递归到子树子树也会再算一次,会导致多次运算,超时,所以我们把数值进行保存

c 复制代码
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ?
		leftHeight + 1 : rightHeight + 1;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	
	printf("%d\n", TreeHeight(root));
	return 0;
}

结果与我们构造的二叉树高度一致,功能正常实现

5、二叉树查找值为x的结点

我们要找值为x的节点,我们分别进行左树右树进行查找,左树找到返回该节点,没有进行右树查找从根节点开始。按 "当前节点→左子树→右子树" 的顺序搜索值为x的节点,找到则返回该节点的指针,遍历完整棵树仍未找到则返回NULL。

代码如下

c 复制代码
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

	if (root->data == x)
		return root;

	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
		return ret1;

	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;

	return NULL;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	BTNode* find = TreeFind(root, 6);
	if (find)
	{
		printf("找到了\n");
	}
	else
		printf("没找到\n");
	BTNode* fin = TreeFind(root, 7);
	if (fin)
	{
		printf("找到了\n");
	}
	else
		printf("没找到\n");
	
	return 0;
}

代码实现正确

6、二叉树的销毁

c 复制代码
// 二叉树销毁
void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);
}
int main()
{
	BTNode* root = CreatBinaryTree();
	TreeDestory(root);
	root = NULL;
	
	return 0;
}

最后主函数再让root=NULL就行啦,在调用函数无法置空,要想置空修改原指针的值,得传地址,需要改为二级指针

c 复制代码
// 二叉树销毁
void TreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	TreeDestory(&((*root)->left));
	TreeDestory(&((*root)->right));
	free(*root);
	*root = NULL;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	TreeDestory(&root);
	
	return 0;
}

两个都可以只不过

第一个需要手动置空,但比较简洁

第二个需要额外置空,传地址,但是更彻底

7、总代码

头文件

Tree.h

c 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
//前序遍历
void PerOrder(BTNode* root);

//中序遍历
void InOrder(BTNode* root);

//后序遍历
void PostOrder(BTNode* root);

//二叉树结点个数 
int TreeSize(BTNode* root);
//void TreeSize(BTNode* root, int* psize);

//二叉树叶子结点个数 
int TreeLeafSize(BTNode* root);

//二叉树第k层结点个数 
int TreeLevelKSize(BTNode* root, int k);

//二叉树的高度
int TreeHeight(BTNode* root);

//二叉树查找值为x的结点 
BTNode* TreeFind(BTNode* root, BTDataType x);

// 二叉树销毁
void TreeDestory(BTNode** root);

功能实现

Tree.c

c 复制代码
#include"Tree.h"
//前序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}
//二叉树结点个数 
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}
//二叉树叶子结点个数 
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return TreeLeafSize(root->left)
		+ TreeLeafSize(root->right);
}
// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	// 子问题
	return TreeLevelKSize(root->left, k - 1)
		+ TreeLevelKSize(root->right, k - 1);
}
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

	if (root->data == x)
		return root;

	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
		return ret1;

	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;

	return NULL;
}
//二叉树的高度
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ?
		leftHeight + 1 : rightHeight + 1;
}
// 二叉树销毁
void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);
}
//// 二叉树销毁
//void TreeDestory(BTNode** root)
//{
//	if (*root == NULL)
//	{
//		return;
//	}
//	TreeDestory(&((*root)->left));
//	TreeDestory(&((*root)->right));
//	free(*root);
//	*root = NULL;
//}

测试

test.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Tree.h"
BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

	node->data = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}

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);
	//BTNode* node7 = BuyNode(7);


	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	//node5->right = node7;

	return node1;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	/*printf("%d\n", TreeSize(root));
	printf("%d\n", TreeSize(root));*/
	/*printf("%d\n", TreeLeafSize(root));
	int k;
	scanf("%d", &k);
	printf("%d\n", TreeLevelKSize(root, k));
	printf("%d\n", TreeHeight(root));
	BTNode* find = TreeFind(root, 6);
	if (find)
	{
		printf("找到了\n");
	}
	else
		printf("没找到\n");
	BTNode* fin = TreeFind(root, 7);
	if (fin)
	{
		printf("找到了\n");
	}
	else
		printf("没找到\n");*/
	TreeDestory(root);


	return 0;
}

二、二叉树层序遍历的实现

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

如图

而这肯定不能用递归实现,那我们怎么实现呢?

这时我们想到可以用队列呀!我们前面讲了队列的实现,我们可以用队列的功能来实现,怎么实现呢?

如下图,头节点进去,出队列时让子节点入队列,反复操作就完成了

这时我们需要用到队列的代码,我们再讲队列时已经把队列的代码放在文章中啦,所以这里我们直接 添加-->现有项

找到对应文件添加

或者直接建新建项把代码Ctrl+v过来

传送门:栈与队列核心篇(下):从基础到进阶,玩转队列设计(可以在这篇文章最后找)

就把文件过来了,在实现前

好啦,我们现在来实现二叉树的层序遍历

c 复制代码
void TreeLevelOrder(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);
	}
	QueueDestroy(&q);
}
int main()
{
	BTNode* root = CreatBinaryTree();
		TreeLevelOrder(root);
	TreeDestory(root);


	return 0;
}

结果,正确实现

三、深度优先遍历(DFS)和广度优先遍历(BFS)

前面前中后序都是深度优先遍历,层序遍历就是广度优先遍历

1、深度优先遍历(DFS, Depth-First Search)

核心概念

深度优先遍历是沿着二叉树的深度方向 探索,优先走到某一分支的最深处 ,遇到叶子节点(无法再深入)后再回溯 ,继续探索其他未走完的分支。简单说就是"一条路走到黑,回头再走其他路"。

工作原理与分类

在二叉树中,DFS根据"访问根节点"的时机不同,分为三种具体形式(以根节点N、左子树L、右子树R表示):

  1. 前序遍历(N→L→R):先访问根节点 → 递归遍历左子树 → 递归遍历右子树;
  2. 中序遍历(L→N→R):先递归遍历左子树 → 访问根节点 → 递归遍历右子树;
  3. 后序遍历(L→R→N):先递归遍历左子树 → 递归遍历右子树 → 访问根节点。

示例(二叉树结构)

复制代码
    1
   / \
  2   3
 / \
4   5
  • 前序遍历结果:1 → 2 → 4 → 5 → 3;
  • 中序遍历结果:4 → 2 → 5 → 1 → 3;
  • 后序遍历结果:4 → 5 → 2 → 3 → 1。

实现方式

通常用递归 (代码简洁)或 (模拟递归过程,避免栈溢出)实现。比如你之前看到的二叉树查找代码,本质就是前序遍历的DFS。

2、广度优先遍历(BFS, Breadth-First Search)

核心概念

广度优先遍历(也叫层序遍历 )是按二叉树的层次顺序 遍历:先访问根节点所在的第一层,再访问第二层的所有节点,接着第三层......依此类推,同一层内按"左→右"顺序访问。简单说就是"一层一层往下扫"。

工作原理

依赖队列(先进先出)实现:

  1. 根节点入队;
  2. 队首节点出队并访问;
  3. 将出队节点的左孩子、右孩子依次入队(若存在);
  4. 重复步骤2-3,直到队列为空。

示例(同上二叉树结构)

层序遍历结果:1 → 2 → 3 → 4 → 5(第一层→第二层→第三层)。

实现方式

必须用队列(或数组模拟队列)实现,无法用简单递归(递归天然偏向深度)。

总结:DFS与BFS的关键区别

特性 深度优先遍历(DFS) 广度优先遍历(BFS)
遍历顺序 深度优先,先探分支尽头 广度优先,先扫完一层
数据结构 递归(隐式栈)或显式栈 队列
适用场景 找路径、计算深度、前/中/后序操作 层序操作、找最短路径(如二叉树最小深度)
空间复杂度(最坏) 取决于树的深度(如链状树O(n)) 取决于树的最宽层节点数(如满二叉树O(n))

简单记:DFS是"钻洞",BFS是"扫面"------前者深入,后者铺开。

四、判断是否为完全二叉树

判断是否为完全二叉树,我们怎么判断呢?

有人会想到用层数和节点个数来判断,但是它是完全二叉树吗?

我们可以想回顾一下,

传送门:数据结构之初识二叉树(1)------核心概念入门

复制代码
  1
 / \
2   4
 \   \
  3   5

例如这个就不是
所以我们可以还用队列实现,层序遍历,只要取到空,就跳出循环,看此时队列中剩下什么,如果只剩下空节点和非空节点,就是非完全二叉树,如果队列中剩下了空节点,就是完全二叉树。

代码实现:

c 复制代码
// 判断二叉树是否是完全二叉树
bool TreeComplete(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);
	}
	int main()
{
	BTNode* root = CreatBinaryTree();
		if (TreeComplete(root))
	{
		printf("是完全二叉树\n");
	}
	else
	{
		printf("不是完全二叉树\n");
	}
	TreeDestory(root);


	return 0;
}

结果为非完全二叉树

因为我们构造时没有构造成完全二叉树

现在我们来构造成完全二叉树

只需要5,6节点删去或者再给2加个右节点(也就变成了满二叉树)就行啦

我们这里把5,6删去

结果

正确实现

五、总代码(包括队列的代码)

队列相关代码

Queue.h

c 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef struct BinaryTreeNode* QDataType;

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

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);

// 队尾插入
void QueuePush(Queue* pq, QDataType x);
// 队头删除
void QueuePop(Queue* pq);

// 取队头和队尾的数据
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);

int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

//// 队尾插入
//void QueuePush(QNode** pphead, QNode** pptail, QDataType x);
//// 队头删除
//void QueuePop(QNode** pphead, QNode** pptail);

Queue.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"

void QueueInit(Queue* pq)
{
    assert(pq);
    pq->phead = NULL;
    pq->ptail = NULL;
    pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
    assert(pq);

    QNode* cur = pq->phead;
    while (cur)
    {
        QNode* next = cur->next;
        free(cur);

        cur = next;
    }

    pq->phead = pq->ptail = NULL;
    pq->size = 0;
}

// 队尾插入
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);

    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }

    newnode->next = NULL;
    newnode->val = x;

    if (pq->ptail == NULL)
    {
        pq->phead = pq->ptail = newnode;
    }
    else
    {
        pq->ptail->next = newnode;
        pq->ptail = newnode;
    }

    pq->size++;
}

// 队头删除
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->size != 0);

    /*QNode* next = pq->phead->next;
    free(pq->phead);
    pq->phead = next;

    if (pq->phead == NULL)
        pq->ptail = NULL;*/

        // 一个节点
    if (pq->phead->next == NULL)
    {
        free(pq->phead);
        pq->phead = pq->ptail = NULL;
    }
    else // 多个节点
    {
        QNode* next = pq->phead->next;
        free(pq->phead);
        pq->phead = next;
    }

    pq->size--;
}

QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(pq->phead);

    return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(pq->ptail);

    return pq->ptail->val;
}


int QueueSize(Queue* pq)
{
    assert(pq);

    return pq->size;
}

bool QueueEmpty(Queue* pq)
{
    assert(pq);

    return pq->size == 0;
}

二叉树

Tree.h

c 复制代码
#pragma once
#include"Queue.h"
#include<stdio.h>
#include<stdlib.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
//前序遍历
void PerOrder(BTNode* root);

//中序遍历
void InOrder(BTNode* root);

//后序遍历
void PostOrder(BTNode* root);

//二叉树结点个数 
int TreeSize(BTNode* root);
//void TreeSize(BTNode* root, int* psize);

//二叉树叶子结点个数 
int TreeLeafSize(BTNode* root);

//二叉树第k层结点个数 
int TreeLevelKSize(BTNode* root, int k);

//二叉树的高度
int TreeHeight(BTNode* root);

//二叉树查找值为x的结点 
BTNode* TreeFind(BTNode* root, BTDataType x);

// 二叉树销毁
void TreeDestory(BTNode** root);
//层序遍历
void TreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
bool TreeComplete(BTNode* root);

Tree.c

c 复制代码
#include"Tree.h"
//前序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}
//二叉树结点个数 
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}
//二叉树叶子结点个数 
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return TreeLeafSize(root->left)
		+ TreeLeafSize(root->right);
}
// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	// 子问题
	return TreeLevelKSize(root->left, k - 1)
		+ TreeLevelKSize(root->right, k - 1);
}
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

	if (root->data == x)
		return root;

	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
		return ret1;

	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;

	return NULL;
}
//二叉树的高度
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ?
		leftHeight + 1 : rightHeight + 1;
}
// 二叉树销毁
void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);
}
//// 二叉树销毁
//void TreeDestory(BTNode** root)
//{
//	if (*root == NULL)
//	{
//		return;
//	}
//	TreeDestory(&((*root)->left));
//	TreeDestory(&((*root)->right));
//	free(*root);
//	*root = NULL;
//}
#include"Queue.h"
//层序遍历
void TreeLevelOrder(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);
	}

	QueueDestroy(&q);
}

// 判断二叉树是否是完全二叉树
bool TreeComplete(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)
		{
			QueueDestroy(&q);
			return false;
		}
	}

	QueueDestroy(&q);
	return true;
}

test.c

c 复制代码
#include"Tree.h"
BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

	node->data = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}

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);*/
	/*BTNode* node7 = BuyNode(7);*/


	node1->left = node2;
	node1->right = node4;
	node2->left = node3;/*
	node4->left = node5;
	node4->right = node6;*/
	/*node5->right = node7;*/

	return node1;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	/*printf("%d\n", TreeSize(root));
	printf("%d\n", TreeSize(root));*/
	/*printf("%d\n", TreeLeafSize(root));
	int k;
	scanf("%d", &k);
	printf("%d\n", TreeLevelKSize(root, k));
	printf("%d\n", TreeHeight(root));
	BTNode* find = TreeFind(root, 6);
	if (find)
	{
		printf("找到了\n");
	}
	else
		printf("没找到\n");
	BTNode* fin = TreeFind(root, 7);
	if (fin)
	{
		printf("找到了\n");
	}
	else
		printf("没找到\n");*/
	/*TreeLevelOrder(root);*/
	if (TreeComplete(root))
	{
		printf("是完全二叉树\n");
	}
	else
	{
		printf("不是完全二叉树\n");
	}
	TreeDestory(root);


	return 0;
}

六、结束语

嗨ヾ(✿゚▽゚)ノ,本篇到这里就结束啦,相关知识传送门已经放在开头啦,主要讲了二叉树链式结构功能的实现,以及深度优先遍历(DFS)和广度优先遍历(BFS),我们对树的讲解到这里就完美结束啦,但是我下一篇为大家准备了一些题目进行检验和巩固,(*❦ω❦)期待下一篇与大家相见,欢迎大家在评论区进行建议和讨论,我们下一篇再见啦!

相关推荐
R-G-B15 分钟前
哈希表(hashtable),哈希理论,数组实现哈希结构 (C语言),散列理论 (拉链发、链接发),散列实现哈希结构,c++ 实现哈希
c语言·哈希算法·散列表·哈希表·数组实现哈希结构·散列实现哈希结构·c++ 实现哈希
li星野18 分钟前
打工人日报#20251213
笔记
历程里程碑19 分钟前
C++ 6 :string类:高效处理字符串的秘密
c语言·开发语言·数据结构·c++·笔记·算法·排序算法
捷米研发三部20 分钟前
Profinet转ModbusTCP网关:实现西门子1200PLC与打标卡稳定通讯
网络
xu_yule21 分钟前
算法基础-(数据结构)
数据结构
玩转数据库管理工具FOR DBLENS23 分钟前
DBLens:开启数据库管理新纪元——永久免费,智能高效的国产化开发利器
数据结构·数据库·测试工具·数据库开发
十月南城26 分钟前
多级缓存设计思路——本地 + 远程的一致性策略、失效风暴与旁路缓存的取舍
后端
未来之窗软件服务27 分钟前
幽冥大陆(四十八)P50酒店门锁SDK 苹果object c语言仙盟插件——东方仙盟筑基期
c语言·开发语言·酒店门锁·仙盟创梦ide·东方仙盟·东方仙盟sdk
YJlio32 分钟前
桌面工具学习笔记(11.1):BgInfo——给服务器桌面“刻”上关键信息
服务器·笔记·学习
float_六七32 分钟前
Spring AOP连接点实战解析
java·后端·spring