< 数据结构 > w字拿捏链式二叉树

这篇具有很好参考价值的文章主要介绍了< 数据结构 > w字拿捏链式二叉树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、为何使用链式二叉树

2、何为链式二叉树

3、基本接口

        创建二叉链结构

        手动构建一颗树

4、二叉树的遍历

        前序遍历

        中序遍历

        后续遍历

        层序遍历

5、经典问题

        结点个数

        叶结点个数

        第K层结点个数

        二叉树的深度

        二叉树查找值为x的节点

        二叉树的销毁

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

6、总代码


1、为何使用链式二叉树

在前几篇博文中,我们学习的都是完全二叉树或满二叉树,而这两个都是可以用数组来实现的,但是如果不是完全二叉树呢?回顾下曾经学过的知识点:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

 由上图得知,普通二叉树也可以使用数组来存储,但是会存在大量的空间浪费,而完全二叉树就不会这样,因为其空间利用率是%100的。既然这样,那普通二叉树该如何进行存储呢?答案是使用链式结构进行存储。

2、何为链式二叉树

  •  链式结构分为两种:二叉链三叉链

先看下代码结构:

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
	struct BinTreeNode* _pLeft; // 指向当前节点左孩子
	struct BinTreeNode* _pRight; // 指向当前节点右孩子
	BTDataType _data; // 当前节点值域
};
// 三叉链
struct BinaryTreeNode
{
	struct BinTreeNode* _pParent; // 指向当前节点的双亲
	struct BinTreeNode* _pLeft; // 指向当前节点左孩子
	struct BinTreeNode* _pRight; // 指向当前节点右孩子
	BTDataType _data; // 当前节点值域
};
  • 画图演示:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  • 注意:

链式二叉树和我们之前的学习略有差别。以前我们学习的数据结构无非就是增删查改这些东西,而链式二叉树不太关注这块的增删查改。因为普通二叉树的增删查改没有意义。如下的二叉树:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

链式二叉树是要比之前链表啥的更加复杂的,如果只是单纯的让链式二叉树存储数据的话,价值就不大了,不如使用线性表。接下来,我将通过其遍历方式,结点个数……为大家展开讨论。此节内容是为了后续学习更复杂的搜索二叉树打基础,具体是啥后面再谈。

  • 在具体讲解之前,再回顾下二叉树,二叉树是:
  1. 空树
  2. 非空:根节点,根节点的左子树、根节点的右子树组成的。

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。

3、基本接口

        创建二叉链结构

创建二叉链结构其实就很easy了,也就是创建一个结构体罢了,这种在先前已经写过很多,咱就是说直接上代码:

//创建二叉链结构
typedef int BTDataType; //本文以int整型为例
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	int data;
}BTNode;

        手动构建一颗树

  • 思路:

其实构建一棵树的思想还是挺简单的,按照图示创建6个节点,并根据图中的样子将节点顺次链接起来

  • 代码演示:
//创建二叉链结构
typedef int BTDataType; //本文以int整型为例
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	int data;
}BTNode;
//创建结点
BTNode* BuyBTNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	node->data = x;
	node->left = node->right = NULL;
	return node;
}
//构建树
BTNode* CreatBinaryTree()
{
	//创建6个结点
	BTNode* node1 = BuyBTNode(1);
	BTNode* node2 = BuyBTNode(2);
	BTNode* node3 = BuyBTNode(3);
	BTNode* node4 = BuyBTNode(4);
	BTNode* node5 = BuyBTNode(5);
	BTNode* node6 = BuyBTNode(6);
	//将结点连接起来,构成自己想要的树
	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	//返回根结点
	return node1;
}
int main()
{
	BTNode* tree = CreatBinaryTree();
	return 0;
}

4、二叉树的遍历

  •  以一颗二叉树为例:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

后续的遍历均是建立在次二叉树基础上展开。 

        前序遍历

  •  遍历规则:

前序遍历,也叫先根遍历

遍历顺序: -> 左子树 -> 右子树

  • 思路:

既然先从根走,根就是1,接下来访问1的左子树,此时又要先访问其左子树的根为2,接着再访问2的左子树->根:3,接着访问其左子树和右子树,不过均为空,递归返回,此时3作为2的左子树访问完毕,访问2的右子树为NULL,再递归返回此时1的左子树就访问完毕了,访问其右子树,同理访问左树4,再访问左树5,接着左右子树NULL,递归返回访问4的右树,……类似的

  • 图示:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  •  代码演示:

前序遍历的代码非常简洁,短短几行即可操作,先看代码:

//前序遍历
void PrevOrder(BTNode*root)
{
	if (root == NULL)
	{
		printf("NULL  "); //如果为空,就打印空
		return;
	}
	printf("%d  ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

跟我们先前画的图一模一样,让我们通过一副递归图来深刻理解其原理:

  • 递归图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        中序遍历

  •  遍历规则:

中序遍历,也叫中根遍历

遍历顺序:左子树 -> 根结点 -> 右子树

  • 思路:

根据遍历顺序,我们得知,如若想访问1,得先访问其左子树2,访问2还得先访问其左子树3,类似的,再访问其左子树为NULL,递归返回访问根结点3,再访问右子树NULL,递归返回访问根结点2,再访问右子树NULL,递归返回访问根结点1,再访问其右子树,1的右子树访问规律同1的左子树,这里不过多赘述。

  • 画图演示:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  •  代码演示:

中序遍历的代码和前序遍历一样,看起来都非常简洁:

//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL  "); //如果为空,就打印空
		return;
	}
	InOrder(root->left);
	printf("%d  ", root->data);
	InOrder(root->right);
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

单纯看代码看不出啥头绪,还得是画递归图。

  • 递归图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        后续遍历

  •  遍历规则:

后续遍历,也叫后根遍历

遍历顺序:左子树 -> 右子树 -> 根结点

  • 思路:

要访问1得先访问1的左子树2,继而得先访问2的左子树3,再先访问3的左子树NULL,右子树NULL,根3,递归返回访问2的右子树NULL,根2,再递归返回访问1的右子树……类似的

  • 画图演示:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  • 代码演示:

后续的代码也非常简单,有了前文前序遍历和中序遍历的基础,后续遍历只需要把打印放后面即可,代码如下:

//后序遍历
void PosOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL  "); //如果为空,就打印空
		return;
	}
	PosOrder(root->left);
	PosOrder(root->right);
	printf("%d  ", root->data);
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  • 画图演示递归过程:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        层序遍历

  •  遍历规则:

层序遍历听名字就很直白,直接一层一层按顺序遍历呗。

我这里直接给出答案:1、2、4、3、5、6

  • 思路:

细心的童鞋可能已经发现,先前的遍历思想都是通过递归来完成的,而层序的遍历则是通过队列来实现的。

首先,把根节点1的结点指针先入队列,队列此时不为空,出队头的数据,把队头数据的孩子2的结点指针和4的结点指针入进去,队列不为空,出2,入孩子3,队列不为空,再出4,把孩子5和6入进去,然后再出,没有孩子继续出,出到最后队列为空。总结如下两句话:

  1. 先把根入队列,借助队列性质:先进先出
  2. 上一层的节点出的时候,带下一层的节点进去
  • 图示:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  • 代码演示:
//层序遍历
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->data); //打印队头数据
		if (front->left)
		{
			QueuePush(&q, front->left); //front左孩子不为空,就入
		}
		if (front->right)
		{
			QueuePush(&q, front->right);//front右孩子不为空,就入
		}
	}
	printf("\n");
	QueueDestory(&q);
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

5、经典问题

        结点个数

  •  思想:

求结点个数,这里我将提供如下几种方法,但不都是可行的,要对比着看,本质都是递归的思想:

  • 法一:遍历

在前文中,我们已经学习了如何遍历链式二叉树,现在想求结点的个数,那么只需要随便采用一种遍历方式,并把打印换成计数++来求个数即可,听起来非常容易,先看代码:

//节点个数
void BTreeSize(BTNode* root)
{
	int count = 0; //局部变量
	if (root == NULL) //如果为空
		return;
	++count;
	BTreeSize(root->left);
	BTreeSize(root->right);
}

难道上述代码能够准确求出结点个数吗?其实不然,根本求不出来。

具体解释起来需要借用栈帧的思想,因为这里用的是递归,而递归是每递归一次在栈帧里头都会开辟一块空间,每一块栈帧都会有一个count,而我希望的是只需要有一个count,然后所有的count均加在一起,可是现在每递归一次,重新开辟一个count,count即局部变量。递归完就销毁,同形参的改变不会影响实参一样,一个道理。所有此法根本就行不通,得换。

  • 法二:定义局部静态变量count

在法一中,我们定义的是局部变量count,会导致每递归一次就开辟栈帧,并创建count,每次递归结束返回就销毁栈帧。那如果可以把count放在静态区里头,不久可以保留住count吗

//节点个数
int BTreeSize(BTNode* root)
{
	static int count = 0; //局部静态变量
	if (root == NULL) //如果为空
		return count;
	++count;
	BTreeSize(root->left);
	BTreeSize(root->right);
	return count;
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

看似好像是成功了,确实结点个数为6,但真的就是成功了吗?当然不是,如果我们现在想多打印几次呢?

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

什么鬼?怎么size还呈现等差数列递增呢?就是因为这里运用了static关键字,将count扣在静态区,导致多次调用没办法初始化为0,使其每次递归调用累计加加,但是当你再重新调用自己时,count不会重新置为0,会依旧保留为曾经++的结果。局部的静态变量有一个好处,它的生命周期在全局,但是只能在局部去访问。它的初始化为0只有第一次调用会访问,其余均不会。由此可见,局部的静态也是不行的,还得再优化。

  • 法三:定义全局变量count

法二的局部静态变量行不通,那就把count设定为全局变量要知道全局变量是存在静态区的。虽然也在静态区,但是其初始化为0是可以重复访问的。

//节点个数
int count = 0;
void BTreeSize(BTNode* root)
{
	if (root == NULL) //如果为空
		return;
	++count;
	BTreeSize(root->left);
	BTreeSize(root->right);
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

确实可以求出结点个数,并且也不会出现像法二一样的问题。但是其实定义全局变量也会存在一个小问题:线程安全的问题,这个等以后学到Linux再来讨论,我们这边考虑再换一种更优解。

  • 法四:最优解

我们这里可以考虑多套一层,可以考虑把变量的地址传过去。这样操作不会存在任何问题,上代码:

//节点个数
void BTreeSize(BTNode* root, int* pCount)
{
	if (root == NULL) //如果为空
		return;
	++(*pCount);
	BTreeSize(root->left, pCount);
	BTreeSize(root->right, pCount);
}
  • 法五:新思路

直接利用子问题的思想来写,返回当root为空为0,不是就递归左树+右树+1。

  1. 空树,最小规模子问题,结点个数返回0
  2. 非空,左子树结点个数+右子树结点个数 + 1(自己)
int BTreeSize(BTNode* root)
{
	return root == NULL ? 0 : 
    BTreeSize(root->left) + 
    BTreeSize(root->right) + 1;
}

此法非常巧妙,很灵活的运用了递归的思想,我们通过递归图来深刻理解下:

  • 递归图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  •  总结:

上述算法思想其实就是分治思想

把复杂的问题分成更小规模的子问题,子问题再分成更小规模的子问题……直到子问题不可再分割,直接能出结果。

此思想纯纯是在套娃。接下来的多个问题都将会用到分治思想。

        叶结点个数

  •  思路1:遍历+计数

在遍历的基础上如果结点的左右子树均为空则count++。但是此题我们依旧采用分治思想。

  • 思路2:分治思想

首先,如果为空,直接返回0,如若结点的左子树和右子树均为空,则为叶节点,此时返回1,其它的继续分治递归。

  • 代码演示:
//叶结点个数
int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0; //为空,返回0
	if (root->left == NULL && root->right == NULL)
		return 1; //如果左右子树均为空,则为叶结点,返回1
	return BTreeLeafSize(root->left) + BTreeLeafSize(root->right); //继续分治递归
}
  • 递归图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        第K层结点个数

  •  思路:

假设K=3

  1. 空树,返回0
  2. 非空,且K == 1,返回1
  3. 非空,且K>1,转换成左子树K-1层节点个数 + 右子树K-1层节点个数
  • 代码演示:
//第K层节点个数,K>=1
int BTreeKLevelSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BTreeKLevelSize(root->left, k - 1) + BTreeKLevelSize(root->right, k - 1);
}
  • 递归图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        二叉树的深度

  •  思路:

此题同样是运用分治的思想来解决,要比较左子树的高度和右子树的高度,大的那个就+1,因为还有根结点也算1个高度。

  • 代码演示:
//求树的深度
int BTreeDepth(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftDepth = BTreeDepth(root->left); //左子树高度
	int rightDepth = BTreeDepth(root->right);//右子树高度
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
  • 递归图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        二叉树查找值为x的节点

  •  思路:

还是利用分治的思想,将其递归化成子问题去解决

  1. 先去根结点寻找,是就返回此节点
  2. 此时去左子树查找有无节点x
  3. 最后再去右子数去查找有无节点x
  4. 若左右子树均找不到节点x,直接返回空
  • 代码演示:
//二叉树查找值为x的节点
BTNode* BTreeFind(BTNode* root, BTDataType 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;
}

int main()
{
	BTNode* tree = CreatBinaryTree();
	for (int i = 0; i <= 7; i++)
	{
		printf("Find:%d,%p\n", i, BTreeFind(tree, i));
	}
	return 0;
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  • 递归图:

假设我们寻找的是数字5

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

        二叉树的销毁

  •  思路:

销毁的思想和遍历类似,如若我挨个遍历的同时,没遍历一次就销毁一次,岂不能达到效果,但是又会存在一个问题,那就是你要采用什么样的遍历方式?倘若你采用前序遍历,刚开始就把根销毁了,那么后面的子树还怎么销毁呢?因为此时根没了,子树找不到了就,所以要采用倒着销毁的规则,也就是后续的思想

  • 代码演示:
//二叉树的销毁
void BTreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BTreeDestory(root->left);
	BTreeDestory(root->right);
	free(root);
	root = NULL;
}

思想和后续遍历类似,不做递归图演示。

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

 在做提前,再来回顾下完全二叉树的概念:前k-1层是满的,最后一层是连续的。

  • 来看一幅图:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

在这三幅图中,很明显肉眼得知第二幅和第三幅图是完全二叉树,只有第一幅不是,现在如何用代码的方式表明出来呢?

  • 思路:层序遍历+变形 

通过上图,不难发现,如果是完全二叉树的话,在层序遍历的时候是不会出现间隔的NULL。例如第一幅图就不是完全二叉树,因为层序遍历到第三层的时候会出现间隔NULL,因为3 -> NULL -> 5 -> 6,而剩余两幅图均不会出现这样的问题,接下来,我将利用类似的思想解决这道题。

层序遍历明确指出,当其中一个结点pop出来时,要把它的孩子给push进队列里,但前提是把不为空的孩子给push进去,现在规矩变了,不管你是否为空,都给push进去,也就是说出一个结点,push两个孩子结点,使其停止的条件是当我pop出来的结点为NULL时,此时停止push,一直pop到队列为空,如果全是空,就是完全二叉树,如果有非空,就不是。

  • 画图演示:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树

  • 代码演示:
//判断一颗二叉树是否是完全二叉树
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) //如果取队头为空,停止,接下来进入下一个while循环判断是否为完全二叉树
			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; //全是空,此时返回true,为完全二叉树
}
  • 效果如下:

w数据结构建立一棵树,数据结构,c语言,数据结构,链式二叉树文章来源地址https://www.toymoban.com/news/detail-663240.html

6、总代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include"Queue.h"
//创建二叉链结构
typedef int BTDataType; //本文以int整型为例
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	int data;
}BTNode;
//创建结点
BTNode* BuyBTNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	node->data = x;
	node->left = node->right = NULL;
	return node;
}
//构建树
BTNode* CreatBinaryTree()
{
	//创建6个结点
	BTNode* node1 = BuyBTNode(1);
	BTNode* node2 = BuyBTNode(2);
	BTNode* node3 = BuyBTNode(3);
	BTNode* node4 = BuyBTNode(4);
	BTNode* node5 = BuyBTNode(5);
	BTNode* node6 = BuyBTNode(6);
	//将结点连接起来,构成自己想要的树
	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	//返回根结点
	return node1;
}

//前序遍历
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 PosOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL  "); //如果为空,就打印空
		return;
	}
	PosOrder(root->left);
	PosOrder(root->right);
	printf("%d  ", root->data);
}

/* 全局变量
节点个数
int count = 0;
void BTreeSize(BTNode* root)
{
	if (root == NULL) //如果为空
		return;
	++count;
	BTreeSize(root->left);
	BTreeSize(root->right);
}*/

/*节点个数
多套一层
void BTreeSize(BTNode* root, int* pCount)
{
	if (root == NULL) //如果为空
		return;
	++(*pCount);
	BTreeSize(root->left, pCount);
	BTreeSize(root->right, pCount);
}
*/
//结点个数 -- > 子问题法
int BTreeSize(BTNode* root)
{
	return root == NULL ? 0 : BTreeSize(root->left) + BTreeSize(root->right) + 1;
}

//叶结点个数
int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0; //为空,返回0
	if (root->left == NULL && root->right == NULL)
		return 1; //如果左右子树均为空,则为叶结点,返回1
	return BTreeLeafSize(root->left) + BTreeLeafSize(root->right); //继续分治递归
}

//第K层节点个数,K>=1
int BTreeKLevelSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BTreeKLevelSize(root->left, k - 1) + BTreeKLevelSize(root->right, k - 1);
}

//求树的深度
int BTreeDepth(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftDepth = BTreeDepth(root->left);
	int rightDepth = BTreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

//二叉树查找值为x的节点
BTNode* BTreeFind(BTNode* root, BTDataType 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;
}

//二叉树的销毁
void BTreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BTreeDestory(root->left);
	BTreeDestory(root->right);
	free(root);
	root = NULL;
}

//层序遍历
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->data); //打印队头数据
		if (front->left)
		{
			QueuePush(&q, front->left); //front左孩子不为空,就入
		}
		if (front->right)
		{
			QueuePush(&q, front->right);//front右孩子不为空,就入
		}
	}
	printf("\n");
	QueueDestory(&q);
}

//判断一颗二叉树是否是完全二叉树
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) //如果取队头为空,停止,接下来进入下一个while循环判断是否为完全二叉树
			break;
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q); 
		//如果空出到非空,那么说明不是完全二叉树
		if (front)
			return false;
	}
	return true; //全是空,此时返回true,为完全二叉树
}


int main()
{
	BTNode* tree = CreatBinaryTree();
	//PrevOrder(tree);
	//printf("\n");
	//InOrder(tree);
	//printf("\n");
	//PosOrder(tree);
	//printf("\n");
	//printf("size: %d", BTreeSize(tree));

	for (int i = 0; i <= 7; i++)
	{
		printf("Find:%d,%p\n", i, BTreeFind(tree, i));
	}
	LevelOrder(tree);
	printf("完全二叉树:%d\n", BTreeComplete(tree));
	BTreeDestory(tree);
	tree = NULL;
	return 0;
}

到了这里,关于< 数据结构 > w字拿捏链式二叉树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】二叉树之链式结构

    🔥 博客主页 : 小羊失眠啦. 🎥 系列专栏 : 《C语言》 《数据结构》 《Linux》 《Cpolar》 ❤️ 感谢大家点赞👍收藏⭐评论✍️ 在学习二叉树各种各样的操作前,我们先来回顾一下二叉树的概念: 二叉树是度不超过2的树,由根结点和左右2个子树组成,每个子树也可以看作

    2024年02月04日
    浏览(46)
  • 数据结构——二叉树的链式结构

      个人主页 : 日刷百题 系列专栏 : 〖C语言小游戏〗〖Linux〗〖数据结构〗  〖C语言〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ 这里我们使用先序遍历的思想来创建二叉树,这里的内容对于刚接触二叉树的朋友可能有些难理解,不妨先看完下面的二叉树各种遍历

    2024年02月05日
    浏览(48)
  • 【数据结构】二叉树的链式结构

    学习链式二叉树要知道三种遍历方式,便于对二叉树的节点以及左子树和右子树进行操作。 前序遍历:根、左子树、右子树 中序遍历:左子树、根、右子树 后序遍历:左子树、右子树、根 以下图为例: 得到的结果: 前序遍历:1 2 3 4 5 6 中序遍历:3 2 1 5 4 6 后序遍历:3 2

    2024年02月08日
    浏览(57)
  • 数据结构:二叉树的链式结构

    朋友们、伙计们,我们又见面了,本期来给大家解读一下链式二叉树的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! 数据结构与算法专栏 :数据结构与算法 个  人  主  页 :stackY、 C 语 言 专 栏 :C语言:从入门到精通 目录 前言

    2024年02月07日
    浏览(59)
  • 【数据结构和算法】--- 二叉树(3)--二叉树链式结构的实现(1)

    在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,且为了方便后面的介绍,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研

    2024年01月25日
    浏览(63)
  • 【数据结构】二叉树 链式结构的相关问题

     本篇文章来详细介绍一下二叉树链式结构经常使用的相关函数,以及相关的的OJ题。 目录 1.前置说明 2.二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层次遍历 3.节点个数相关函数实现 3.1 二叉树节点个数 3.2 二叉树叶子节点个数 3.3 二叉树第k层节点个数 3.4 在二叉树中查找值

    2024年02月14日
    浏览(59)
  • 【数据结构—二叉树的链式结构实现】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、二叉树的存储结构 二、二叉树链式结构的实现 2.1手动构建一课树 2.2二叉树的遍历 三、二叉树链式结构的实现 3.1前序遍历(递归) 3.2中序遍历(递归) 3.3后序遍历(递归) 3.4层序遍历(非递

    2024年02月03日
    浏览(59)
  • 【数据结构 —— 二叉树的链式结构实现】

    树是一种非线性的数据结构,它是由n(n=0)个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 1.有一个 特殊的结点,称为根结点 ,根节点没有前驱结点 2.除根节点外, 其余结点被分成M(M0)个互不相交

    2024年02月05日
    浏览(57)
  • 【数据结构】二叉树的链式存储结构

    前序遍历,又叫先根遍历。 遍历顺序:根 - 左子树 - 右子树 代码: 中序遍历,又叫中根遍历。 遍历顺序:左子树 - 根 - 右子树 代码 : 后序遍历,又叫后根遍历。 遍历顺序:左子树 - 右子树 - 根 代码 : 除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍

    2024年02月09日
    浏览(46)
  • 【数据结构】二叉树链式结构的实现(三)

    目录 一,二叉树的链式结构 二,二叉链的接口实现         1,二叉链的创建         2,接口函数         3,动态创立新结点         4,创建二叉树         5,前序遍历         6,中序遍历         7,后序遍历 三,结点个数以及高度等      

    2024年02月08日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包