数据结构:二叉树的递归实现(C实现)

news2024/11/23 8:09:57

在这里插入图片描述

个人主页 : 个人主页
个人专栏 : 《数据结构》 《C语言》

文章目录

  • 前言
  • 一、树的概念
  • 二、二叉树
    • 二叉树的概念
    • 二叉树的性质
  • 三、二叉树链式结构实现
    • 二叉树节点定义
    • 创建二叉树节点
    • 遍历二叉树
      • 先序遍历二叉树(BinaryTreePrevOrder)
      • 中序遍历二叉树(BinaryTreeInOrder)
      • 后序遍历二叉树(BinaryTreePostOrder)
      • 层序遍历二叉树(BinaryTreeLevelOrder)
    • 二叉树节点个数(BinaryTreeSize)
    • 二叉树第K层节点个数(BinaryTreeLevelKSize)
    • 二叉树叶子节点个数(BinaryTreeLeafSize)
    • 二叉树查找值为X的节点(BinaryTreeFind)
    • 判断二叉树是否是完全二叉树(BinaryTreeComplete)
    • 通过前序遍历的数组构建二叉树
  • 四、代码展示
    • 二叉树代码展示
    • 队列代码展示
  • 总结


前言

本篇博客主要讲解二叉树的相关操作如下:

//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

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

//二叉树节点个数
int BinaryTreeSize(BTNode* root);

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

//二叉树第K层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

//二叉树查找值为X的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);

//二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

//二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

//层序遍历
void BinaryTreeLevelOrder(BTNode* root);

//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x);

一、树的概念

树是一种非线性结构,它是由n个有限节点组成的一个有层次关系的集合。

在这里插入图片描述

  • 图中A节点没有前驱节点,被称为根节点
  • 除根节点外,其余节点被分成两个无不相交的集合T1(B,D,E,F…),T2(C,G,H,L…)。其中每个集合T又是一颗结构与树类似的子树。每一颗子树的根节点有且只有一个根节点,可以有0个或多个后继节点
  • 因此,树是递归定义的。
  • 树的子树不能有交集,否则就为图。

  • 节点的度:一个节点含有的子树的个数称为该节点的度;如上图A节点的度是2
  • 叶节点或终端节点:度为0的节点被称为叶节点;如上图:K,J,F,L,O,P为叶节点
  • 非终端节点或分支节点:度不为0的节点;如上图:A,B,C,D,E…等节点为分支节点
  • 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点。如上图A节点是B,C的父节点
  • 孩子节点或子节点:若一个节点含有子树,则子树的根节点就是该节点的子节点。如上图B,C是A的子节点
  • 兄弟节点:具有相同的父节点的节点互为兄弟节点。如上图B,C互为兄弟节点
  • 树的度:一颗树中,最大节点的度就是该数的度。如上图数的度为3
  • 节点的层次:从根开始定义起,根为第一层,根的子节点为第二层,依次类推。如上图G节点的层次为3
  • 树的高度或深度:树中节点的最大层次。如上图树的深度为5
  • 堂兄弟节点:父节点在同一层的节点互为堂兄弟节点。如上图D,G互为堂兄弟节点
  • 节点的祖先:从根到该节点所经分支上的所以节点。如上图A是所以节点的祖先
  • 子孙节点 :以某节点为根的子树中任一节点都称为该节点的子孙。如上图所以节点是A的子孙
  • 森林:由m棵互不相交的树的集合称为森林

二、二叉树

二叉树的概念

由一个根节点加上两颗子树构成 。

在这里插入图片描述

  • 二叉树的度最大为2
  • 二叉树是有序树,二叉树的子树有左右之分,次序不能颠倒

二叉树的性质

若规定根节点的层数是1,则一个非空二叉树的第K层最多有2^(k - 1)个节点

若规定根节点的层数是1,则深度为h的二叉树的最大节点数是2^h - 1

对于任何一颗二叉树,如果度为0的节点为N0,度为2的节点为N2,那么N0 = N2 + 1 (数学归纳)

若规定根节点的层数是1,具有N个节点的满二叉树的深度为log(n + 1)[以2为底]

对于具有n个节点的完全二叉树,如果按照从上至下从左到右的数组顺序对所以节点从0开始编号(也就是堆的结构),则对序号为K的节点有:
若k>0,k节点的父节点的序号:(k - 1) / 2;
如果k是0(根节点),则无父节点
若2k+1<n,左孩子序号 2k+1,右孩子序号2k+2 如果2k+1> n则无左孩子 2*k+2>n则无右孩子

三、二叉树链式结构实现

二叉树节点定义

节点需要一个数据域,一个指向左孩子节点的指针,一个指向右孩子节点的指针。
在这里插入图片描述

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

创建二叉树节点

我们只需要传递二叉树节点的数据即可,动态开辟出的节点空间用返回值的方式接受。
malloc出一块节点空间,将函数参数给data,使left 和 right 指向NULL,返回该空间的地址

在这里插入图片描述

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x)
{
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
		perror("malloc:");
		exit(-1);
	}
	root->data = x;
	root->left = root->right = NULL;

	return root;
}

为了方便我们理解,这里我们先手动创建一个二叉树来进行讲解相关操作,最后在来讲解先序创建二叉树。

void test()
{
	BTNode* a = BuyBinaryTreeNode('A');
	BTNode* b = BuyBinaryTreeNode('B');
	BTNode* c = BuyBinaryTreeNode('C');
	BTNode* d = BuyBinaryTreeNode('D');
	BTNode* e = BuyBinaryTreeNode('E');
	BTNode* f = BuyBinaryTreeNode('F');
	BTNode* g = BuyBinaryTreeNode('G');
	BTNode* h = BuyBinaryTreeNode('H');

	a->left = b;
	b->left = d;
	b->right = e;
	e->right = h;
	a->right = c;
	c->left = f;
	c->right = g;
}

创建的二叉树就是下图所示:
在这里插入图片描述

遍历二叉树

遍历二叉树有多种方式:

  • 先序遍历 :根节点 -> 左子树 -> 右子树
  • 中序遍历 :左子树-> 根节点 -> 右子树
  • 后序遍历 :左子树 -> 右子树 -> 根节点
  • 层序遍历 : 从左到右从上到下,依次遍历二叉树节点

先序遍历二叉树(BinaryTreePrevOrder)

对于下图中的二叉树,其先序遍历结果为:ABD##E#H##CF##G##( ’ # ’ 表示NULL )
在这里插入图片描述
那么是如何遍历的?我们需要按照根,左,右的顺序递归二叉树即可。
在这里插入图片描述

//二叉树前序遍历   根节点 左子树  右子树
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	//根节点
	printf("%c ", root->data);
	//左子树
	BinaryTreePrevOrder(root->left);
	//右子树
	BinaryTreePrevOrder(root->right);
}

这份代码是如何展开的?
在这里插入图片描述

中序遍历二叉树(BinaryTreeInOrder)

中序遍历与先序遍历类似,只有将根节点的访问与左子树递归交换执行顺序即可
对于下图中的二叉树,其中序遍历结果为:#D#B#E#H#A#F#C#G# ( ’ # ’ 表示NULL )
在这里插入图片描述
在这里插入图片描述

//二叉树中序遍历		左子树  根  右子树
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	//左子树
	BinaryTreeInOrder(root->left);
	//根
	printf("%c ", root->data);
	//右子树
	BinaryTreeInOrder(root->right);
}

后序遍历二叉树(BinaryTreePostOrder)

后序遍历,就是再次调整根节点的访问顺序,将根节点的访问顺序调整到左子树递归与右子树递归后即可。

对于下图中的二叉树,其中序遍历结果为:##D###HEB##F##GCA ( ’ # ’ 表示NULL )
在这里插入图片描述
在这里插入图片描述

//二叉树后序遍历  左子树 右子树 根
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	//左子树
	BinaryTreePostOrder(root->left);
	//右子树
	BinaryTreePostOrder(root->right);
	//根
	printf("%c ", root->data);
}

层序遍历二叉树(BinaryTreeLevelOrder)

要实现二叉树的层序遍历,我们需要借助队列。
我们将根节点先入队列,之后我们每次出队头数据时,将该队头数据指向的左子节点 与 右子节点分别入队列,如果左子节点 或 右子节点 为NULL就不入队列,重复上述过程直到队列为空

在这里插入图片描述

//层序遍历  借助队列  出队头数据时,将其左子节点 与 右子节点依次入队列
void BinaryTreeLevelOrder(BTNode* root)
{
	Quene q;
	QueneInit(&q);

	//入根节点
	QuenePush(&q, root);

	//队列为空,代表二叉树中元素也遍历完成
	while (!QueneEmpty(&q))
	{
		QDataType val = QueneFront(&q);
			printf("%c ", val->data);

		//入数据  该节点的左节点 与 右节点
		if (val->left != NULL)
			QuenePush(&q, val->left);

		if (val->right != NULL)
			QuenePush(&q, val->right);

		//出队头数据
		QuenePop(&q);
	}
		QueneDestrory(&q);
}

二叉树节点个数(BinaryTreeSize)

我们使用递归的思路来看待二叉树节点个数的接口。
子问题:根节点的左子树的节点个数 与 根节点的右子树的节点个数
结束条件:空节点返回
所以求二叉树节点个数的问题可以转换为求根节点左子树节点数 + 根节点右子树节点数 +根节点的节点总数

//二叉树节点个数   根节点的左子树与右子树的节点个数和  
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	//        左子树节点数                 右子树节点数               根节点
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

对于下面二叉树的递归展开图:
在这里插入图片描述
在这里插入图片描述

二叉树第K层节点个数(BinaryTreeLevelKSize)

函数声明:

int BinaryTreeLevelKSize(BTNode* root, int k);

子问题:根节点左子树第K-1层节点个数 与 根节点右子树第K-1层节点个数
结束条件:访问到空节点 或 找到所求层数(k == 1)

也就是说,求二叉树第K层节点数的问题转换为求根节点左子树第K-1层节点数 与 根节点右子树第K-1层节点数之和。

//二叉树第K层节点个数       左子树的第k-1层节点数 + 右子树的第k-1层节点数     不同栈帧的k互不影响
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	//如果 k 超过数的深度
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

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

对于下面二叉树,求第3层节点数的递归展开图。
在这里插入图片描述
在这里插入图片描述

二叉树叶子节点个数(BinaryTreeLeafSize)

函数声明:

int BinaryTreeLeafSize(BTNode* root);

子问题:根节点左子树叶子结点 与 根节点右子树叶子结点
结束条件:访问到空节点 或 访问到叶子结点

原问题转换成根节点左子树叶子结点个数 + 根节点右子树叶子结点个数。


//二叉树叶子节点个数   左子树的叶子节点 + 右子树的叶子结点
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);
}

对于下面二叉树,求其叶子结点的个树的递归展开图
在这里插入图片描述
在这里插入图片描述

二叉树查找值为X的节点(BinaryTreeFind)

先序遍历查找节点,如果是该节点,直接返回该节点地址。如果不是该节点,继续查找该节点的左子树,如果左子树也没找到,查找右子树。

//二叉树查找值为X的节点   前序遍历查找  
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

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

	//左子树
	BTNode* leftNode = BinaryTreeFind(root->left, x);
	if (leftNode != NULL)
		return leftNode;

	//右子树
	BTNode* rightNode = BinaryTreeFind(root->right, x);
	if (rightNode != NULL)
		return rightNode;

	return NULL;
}

对于下面二叉树,查找 ’ C '的递归展开图
在这里插入图片描述
在这里插入图片描述

判断二叉树是否是完全二叉树(BinaryTreeComplete)

完全二叉树也就是堆,当其层序遍历时,其中有效数据(不包含NULL)是连续的。
只需要借助队列,来层序遍历二叉树(如果某个节点左子节点或右子节点是NULL也入队列)。当队列首数据是NULL时,判断其后数据是否全是NULL,如果其后数据全是NULL,返回true,如果其后元素有一个不是NULL,返回false。


//完全二叉树的节点是连续的,层序遍历二叉树,如果遇到NULL,检查栈中后续元素是否都为NULL
bool BinaryTreeComplete(BTNode* root)
{
	Quene q;
	QueneInit(&q);

	QuenePush(&q, root);
	while (!QueneEmpty(&q))
	{
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
			QuenePush(&q, node->left);
			QuenePush(&q, node->right);
		}
		else
		{
			break;
		}
	}

	while (!QueneEmpty(&q))
	{
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
			QueneDestrory(&q);
			return false;
		}
	}

	QueneDestrory(&q);
	return true;
}

通过前序遍历的数组构建二叉树

在先序遍历的数组中,我们以’ # '代表NULL。
函数声明:其中a是先序遍历的数组,n是节点数,pi是现在节点的个数

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

子问题:构建左子树与右子树
结束条件:遇到先序遍历数组的’ # '或节点数大于n
创建根节点,再遍历左子树和右子树,使根节点指向左子树与右子树。

//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (*pi >= n  || a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}

	BTNode* newnode = BuyBinaryTreeNode(a[*pi]);
	(*pi)++;

	//左子节点
	BTNode* leftnode = BinaryTreeCreate(a, n, pi);
	newnode->left = leftnode;

	//右子节点
	BTNode* rightnode = BinaryTreeCreate(a, n, pi);
	newnode->right = rightnode;

	return newnode;
}

四、代码展示

二叉树代码展示

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;



//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

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

//二叉树节点个数
int BinaryTreeSize(BTNode* root);

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

//二叉树第K层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

//二叉树查找值为X的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);

//二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

//二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

//层序遍历
void BinaryTreeLevelOrder(BTNode* root);

//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x);

#include "BinaryTree.h"
#include "quene.h"

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x)
{
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
		perror("malloc:");
		exit(-1);
	}
	root->data = x;
	root->left = root->right = NULL;

	return root;
}

//二叉树前序遍历   根节点 左子树  右子树
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	//根节点
	printf("%c ", root->data);
	//左子树
	BinaryTreePrevOrder(root->left);
	//右子树
	BinaryTreePrevOrder(root->right);
}

//二叉树中序遍历		左子树  根  右子树
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	//左子树
	BinaryTreeInOrder(root->left);
	//根
	printf("%c ", root->data);
	//右子树
	BinaryTreeInOrder(root->right);
}

//二叉树后序遍历  左子树 右子树 根
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	//左子树
	BinaryTreePostOrder(root->left);
	//右子树
	BinaryTreePostOrder(root->right);
	//根
	printf("%c ", root->data);
}



//二叉树的销毁  后序遍历二叉树 
void BinaryTreeDestroy(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	//左子树
	BinaryTreeDestroy(root->left);
	//右子树
	BinaryTreeDestroy(root->right);
	//根
	free(root);
}



//二叉树节点个数   根节点的左子树与右子树的节点个数和  
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	//        左子树节点数                 右子树节点数               根节点
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}



//二叉树叶子节点个数   左子树的叶子节点 + 右子树的叶子结点
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层节点个数       左子树的第k层节点数 + 右子树的第k层节点数     不同栈帧的k互不影响
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	//如果 k 超过数的深度
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

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




//二叉树查找值为X的节点   前序遍历查找  
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

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

	//左子树
	BTNode* leftNode = BinaryTreeFind(root->left, x);
	if (leftNode != NULL)
		return leftNode;

	//右子树
	BTNode* rightNode = BinaryTreeFind(root->right, x);
	if (rightNode != NULL)
		return rightNode;

	return NULL;
}



//层序遍历  借助队列  出队头数据时,将其左子节点 与 右子节点依次入队列
void BinaryTreeLevelOrder(BTNode* root)
{
	Quene q;
	QueneInit(&q);

	//入根节点
	QuenePush(&q, root);

	//队列为空,代表二叉树中元素也遍历完成
	while (!QueneEmpty(&q))
	{
		QDataType val = QueneFront(&q);
			printf("%c ", val->data);

		//入数据  该节点的左节点 与 右节点
		if (val->left != NULL)
			QuenePush(&q, val->left);

		if (val->right != NULL)
			QuenePush(&q, val->right);

		//出队头数据
		QuenePop(&q);
	}
		QueneDestrory(&q);
}



//判断二叉树是否是完全二叉树    层序遍历二叉树

//bool BinaryTreeComplete(BTNode* root)
//{
//	Quene q;
//	QueneInit(&q);
//
//	//如果某个节点的右节点为空,那么之后遍历的节点的左/右节点也应该为空
//	bool flag = false;
//
//	QuenePush(&q, root);
//	while (!QueneEmpty(&q))
//	{
//		QDataType val = QueneFront(&q);
//
//		if (val->left == NULL && val->right != NULL)
//			return false;
//
//		if (flag == true && (val->left != NULL || val->right != NULL))
//			return false;
//
//		if (val->left != NULL)
//			QuenePush(&q, val->left);
//
//		if (val->right != NULL)
//			QuenePush(&q, val->right);
//		else
//			flag = true;
//
//		QuenePop(&q);
//	}
//
//	return true;
//}

//完全二叉树的节点是连续的,层序遍历二叉树,如果遇到NULL,检查栈中后续元素是否都为NULL
bool BinaryTreeComplete(BTNode* root)
{
	Quene q;
	QueneInit(&q);

	QuenePush(&q, root);
	while (!QueneEmpty(&q))
	{
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
			QuenePush(&q, node->left);
			QuenePush(&q, node->right);
		}
		else
		{
			break;
		}
	}

	while (!QueneEmpty(&q))
	{
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
			QueneDestrory(&q);
			return false;
		}
	}

	QueneDestrory(&q);
	return true;
}



//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (*pi >= n  || a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}

	BTNode* newnode = BuyBinaryTreeNode(a[*pi]);
	(*pi)++;

	//左子节点
	BTNode* leftnode = BinaryTreeCreate(a, n, pi);
	newnode->left = leftnode;

	//右子节点
	BTNode* rightnode = BinaryTreeCreate(a, n, pi);
	newnode->right = rightnode;

	return newnode;
}

队列代码展示

#include "BinaryTree.h"
#include <assert.h>

//队列 节点结构--树节点
typedef struct QueneNode
{
	struct BinaryTreeNode* data;
	struct QueneNode* next;
}QueneNode;

typedef struct BinaryTreeNode* QDataType;

//队列 结构
typedef struct Quene
{
	QueneNode* head;
	QueneNode* tail;
	int size;
}Quene;


//初始化队列
void QueneInit(Quene* q);

//队尾入队列
void QuenePush(Quene* q, QDataType x);

//队头出数据
void QuenePop(Quene* q);

//获取队列头部元素
QDataType QueneFront(Quene* q);

//获取队列队尾元素
QDataType QueneBack(Quene* q);

//获取队列中有效元素个数
int QueneSize(Quene* q);

//检查队列是否为空,如果为空返回ture,如果非空返回false
bool QueneEmpty(Quene* q);

//销毁队列
void QueneDestrory(Quene* q);

#include "quene.h"

//初始化队列
void QueneInit(Quene* q)
{
	assert(q);

	q->head = q->tail = NULL;
	q->size = 0;
}

//队尾入队列
void QuenePush(Quene* q, QDataType x)
{
	assert(q);

	QueneNode* newnode = (QueneNode*)malloc(sizeof(QueneNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->data = x;

	//队列为空
	if (QueneEmpty(q) == true)
	{
		q->head = q->tail = newnode;
	}
	else//队列不为空
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}

	q->size++;
}



//队头出数据
void QuenePop(Quene* q)
{
	assert(q);
	//队列为空
	assert(QueneEmpty(q) != true);

	//队列只有一个元素
	if (q->head->next == NULL)
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	else//队列中有多个元素
	{
		QueneNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}

	q->size--;
}


//获取队列头部元素
QDataType QueneFront(Quene* q)
{
	assert(q);

	return q->head->data;
}


//获取队列队尾元素
QDataType QueneBack(Quene* q)
{
	assert(q);

	return q->tail->data;
}


//获取队列中有效元素个数
int QueneSize(Quene* q)
{
	assert(q);

	return q->size;
}


//检查队列是否为空,如果为空返回ture,如果非空返回false
bool QueneEmpty(Quene* q)
{
	assert(q);

	return q->size == 0;
}


//销毁队列
void QueneDestrory(Quene* q)
{
	assert(q);

	QueneNode* cur = q->head;
	while (cur)
	{
		QueneNode* next = cur->next;
		free(cur);
		cur = next;
	}

}

总结

以上就是我对于二叉树的理解!!!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/893892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文阅读——Imperceptible Adversarial Attack via Invertible Neural Networks

Imperceptible Adversarial Attack via Invertible Neural Networks 作者&#xff1a;Zihan Chen, Ziyue Wang, Junjie Huang*, Wentao Zhao, Xiao Liu, Dejian Guan 解决的问题&#xff1a;虽然视觉不可感知性是对抗性示例的理想特性&#xff0c;但传统的对抗性攻击仍然会产…

java面试基础 -- 普通类 抽象类 接口

目录 抽象类语法 抽象类特性 普通类 & 抽象类 抽象类 & 接口 什么是接口 语法 接口方法 变量 接口特性 抽象类&接口的区别 抽象类语法 在Java中&#xff0c;一个类如果被 abstract 修饰称为抽象类&#xff0c;抽象类中被 abstract 修饰的方法称为抽象…

python-03(入门基础篇3——字符串 的 基本常见语法 以及 format的用法)

python-03&#xff08;入门基础篇3——字符串 的 基本常见语法 以及 format的用法&#xff09; 1. 前言1.1 体验python入门1.2 官网参考 2. 字符串简单入门2.1 简单介绍2.2 拼接字符串&#xff08;&#xff09;和 重复字符串&#xff08;*&#xff09;2.3 相邻字符串自动拼接2.…

凭空销毁千万,揭秘nd4.eth大佬背后的故事

文/章鱼哥 出品/陀螺财经 在加密社区&#xff0c;千万资产的销毁&#xff0c;就在弹指之间&#xff0c;好似一场行为艺术。 上周&#xff0c;nd4.eth域名的不明持有者在没有任何公开解释的前提下销毁了价值约800余万美元的加密货币和高价值蓝筹NFT&#xff0c;引起了看客们的关…

区块链中slot、epoch、以及在slot和epoch中的出块机制,分叉原理(自己备用)

以太坊2.0中有两个时间概念&#xff1a;时隙槽slot 和 时段&#xff08;周期&#xff09;epoch。其中一个slot为12秒&#xff0c;而每个 epoch 由 32 个 slots 组成&#xff0c;所以每个epoch共384秒&#xff0c;也就是 6.4 分钟。 对于每个epoch&#xff0c;使用RANDAO伪随机…

时序预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测

时序预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测 目录 时序预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测 程序设计 完整…

windows上的docker自动化部署到服务器脚本

1、mvn install后&#xff0c;双击这个bat&#xff0c;实现docker build后上传到124服务器&#xff0c;并且重启124服务器 **echo offsetlocal:: 定义镜像名称和版本变量 set IMAGE_NAMEweb set IMAGE_VERSION1.3.1:: 清理本地文件 echo Cleaning up... del service-%IMAGE_N…

产品管理:理解、掌握要点

产品管理是什么&#xff1f; 产品管理是指通过使用各种方法和技术&#xff0c;有效地规划、组织、控制和监督整个产品生命周期的过程。它涉及到从产品的概念阶段开始一直到产品的上市和销售阶段的各个环节。在当今竞争激烈的市场中&#xff0c;一个成功的产品管理过程对企业的…

Vue学习笔记--004

Vue学习 一、scoped解决样式冲突 写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。 全局样式: 默认组件中的样式会作用到全局&#xff0c;任何一个组件中都会受到此样式的影响 局部样式: 可以给组件加上scoped 属性,可以 让样式只作用于当前组件 …

简单的洗牌算法

目录 前言 问题 代码展现及分析 poker类 game类 Text类 前言 洗牌算法为ArrayList具体使用的典例&#xff0c;可以很好的让我们快速熟系ArrayList的用法。如果你对ArrayList还不太了解除&#xff0c;推荐先看本博主的ArrayList的详解。 ArrayList的详解_WHabcwu的博客-CSD…

nn.embedding会被反向传播更新吗?

https://developer.aliyun.com/article/1191215 这样是不可更新&#xff0c;但被我注释掉了。

【C++ 学习 ⑭】- 详解 stack、queue 和 priority_queue 容器适配器

目录 一、详解 C STL 容器适配器 1.1 - 什么是容器适配器&#xff1f; 1.2 - 容器适配器的种类 二、详解 C STL deque 容器 2.1 - deque 的原理介绍 2.2 - deque 的优缺点 三、详解 stack 容器适配器 3.1 - stack 的基本介绍 3.2 - stack 的成员函数 3.3 - stack 的模…

live555在Windows WSL2中编译、运行,搭建RTSP流服务器

文章目录 1. 背景2. 实施步骤2.1 下载live555安装包2.2 解压压缩包2.3 编译源码2.3 安装ffmpeg2.4 安装opencv-python2.5 视频文件格式转换2.6 启动推流2.6 安装VLC&#xff0c;验证 3. 用opencv-python接口接收视频流参考 1. 背景 想要通过RTSP往opencv的接口中推流&#xff…

富文本中的参数如何设置大小?

富文本里如果直接显示的数据可以随意调节大小,颜色等格式. 但是如果数据是动态的参数 就无法随意设置参数的格式了.当字数过多时就会出现显示不全,有没有大佬知道如何解决? wangEditor set HTML

Flink 数据集成服务在小红书的降本增效实践

摘要&#xff1a;本文整理自实时引擎研发工程师袁奎&#xff0c;在 Flink Forward Asia 2022 数据集成专场的分享。本篇内容主要分为四个部分&#xff1a; 小红书实时服务降本增效背景Flink 与在离线混部实践实践过程中遇到的问题及解决方案未来展望 点击查看原文视频 & 演…

【学习笔记之vue】These dependencies were not found:

These dependencies were not found:方案一 全部安装一遍 我们先浅试一个axios >> npm install axios 安装完报错就没有axios了&#xff0c;验证咱们的想法没有问题&#xff0c;实行&#xff01; ok

chapter 3 Free electrons in solid - 3.2 量子自由电子理论对一些现象的解释

3.2 自由电子气的热容 Heat capacity of free electron gas 3.2.1 计算自由电子的热容 Calculation of Heat Capacity of free Electrons T>0K, total energy of free electrons: E ∫ E d N 3 5 N e E F 0 [ 1 5 12 π 2 ( k B T E F 0 ) 2 ] E \int EdN \frac{3}{5}…

Unable to find resource t64.exe in package pip._vendor.distlib报错问题解决

Unable to find resource t64.exe in package pip._vendor.distlib报错问题解决 问题报错具体内容具体解决方案解决方法一解决方法二 问题报错具体内容 想要对python的版本进行一个升级,使用如下语句 python -m pip install --upgrade pip出现如下报错 Unable to find reso…

四维轻云场景更新之后,如何快速搭建场景?

「四维轻云」是一款轻量化的地理空间数据管理云平台&#xff0c;支持地理空间数据的在线管理、编辑以及分享。平台提供了项目管理、数据上传、场景搭建、发布分享、素材库等功能模块&#xff0c;支持团队多用户在线协作管理。 四维轻云平台是以项目的形式进行数据管理&#xf…

vue2中常用的组件封装技巧

文章目录 vue组件封装技巧1.props参数2.$attrs3.$emit4.$listeners5.插槽 vue组件封装技巧 1.props参数 最简单父传子的技巧&#xff0c;在父组件传入值&#xff0c;子组件声明props接收就可以了 如下&#xff1a; 父组件&#xff1a; <template><div id"ap…