二叉树的实现(初阶数据结构)

1.二叉树的概念及结构

1.1 概念

一棵二叉树是结点的一个有限集合,该集合:

    1.或者为空

    2.由一个根结点加上两棵别称为左子树和右子树的二叉树组成

 从上图可以看出:

    1.二叉树不存在度大于2的结点

    2.二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

1.2 特殊二叉树

    1.满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树,也就是说没如果一个二叉树的层数为K,且结点总数是2^k-1,则它就是满二叉树。

    2.完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当每一个结点都与深度为K的满二叉树中编号从1至n的结点——对应时称之为完全二叉树,要注意的是满二叉树是一中特殊的完全二叉树。

 

1.3二叉树的性质

    1.若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。

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

    3.对任何一棵二叉树,如果度为0其叶子结点个数为a,度为2的分支个数为b,则有a=b+1。

    4.若规定根结点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1).(ps:以2为底,n+1为对数)

    5.对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点有:

    1.若i>0,i的位置结点的双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点

    2.2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子

    3.2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

1.4二叉树的存储结构

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。

1.顺序存储

顺序结构村塾就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费,而现实中使用只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一棵二叉树。

2.链式存储

二叉树的链式存储结构是指用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。链式结构又分为二叉链和三叉链。

2.二叉树的实现

#pragma once


#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.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 BinaryTreeDestory(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);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);
//二叉树的高度
int TreeHigh(BTNode* root);

2.1创建新的结点

调用函数BuyNode来创建新的结点

BTNode* BuyNode(BTDataType 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;
}

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

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
//a为我们所要遍历的数组
//n是最大数组的长度
//pi是我们用来遍历数组的指针
//当遍历是遇到‘#’或者指针超出了数组的范围就返回NULL
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{

	
	if (a[*pi] == '#' || *pi >= n)
	{
		printf("NULL ");
		(*pi)++;
		return NULL;
	}

	//创建一个新的二叉树的节点
	BTNode* dst = BuyNode(a[*pi]); 
	printf("%c ", dst->_data);
	(*pi)++;

	dst->_left = BinaryTreeCreate(a, n, pi);
	dst->_right = BinaryTreeCreate(a, n, pi);

	return dst;
}

构建出来的二叉树如下:

 2.3二叉树的销毁

实现二叉树的销毁时,我们要正确选择以哪种遍历的方式,这里使用后序遍历,从底层叶子层开始,先释放左子树和右子树的空间,再释放根结点的空间,如果先对根结点释放,就找不到它所对应的左子树和右子树了。

//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&((*root)->_left));
	BinaryTreeDestory(&((*root)->_right));
	free(*root);
	*root = NULL;
	return;

}

2.4计算二叉树的结点个数

这里我罗列了两种方法:

一种是用一个静态变量通过size++的形式来计算结点的个数(局部的静态变量只能初始化一次)

另一种是递归遍历二叉树通过放回:  左子树+右子树+1

int BinaryTreeSize(BTNode* root)
{
    //方法一:

	//用静态变量(在堆上,不在栈上)改变局部变量 -> 使得递归的size可以累加起来,但是局部的静态只能初始化一次
	/*static int size = 0;
	if (root == NULL)
	{
		return 0;
	}
	else
		++size;
	BinaryTreeSize(root->_left);
	BinaryTreeSize(root->_right);*/

    //方法二:

	//如果我们当前的节点为空,也就是说我们已经到了叶子节点的左右节点,也就是没有节点
	//所以我们需要返回0
	if (root == NULL)
	{
		return 0;
	}

	//如果我们当前的节点的左指针和右指针都是空的话,也就是说这是我们的叶子节点
	//就返回1,也就是只有一个节点
	if (root->_left == NULL && root->_right == NULL)
	{
		return 1;
	}

	//使用递归遍历我们的二叉树,即分别统计我们左子树的节点个数再加上右子树中的节点个数再加上1
	//因为我们需要将我们当前所指的节点算上
	return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;

}

2.5计算二叉树叶子结点的个数

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);
}

2.6二叉树第k层的结点个数

二叉树第一层结点个数为1,第k层结点是第一层结点往下找k-1层,第二层的结点往下找k-2层,当k为1的时候返回的结果就是找的k层的结点的个数的总和。

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)
	{
		return 1;
	}

	//分别遍历我们的左右子树,并且将我们的k的参数--,当我们的k为1时,就到达了我们所想要查找对应的层
	return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

2.7查找值为x的结点

查找第一个指定值为x的结点,同过前序遍历的方法来寻找第一个值为x的结点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}

	if (root->_data == 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;*/
	return BinaryTreeFind(root->_right, x);
}

 2.8二叉树前序遍历

前序遍历的顺序是根 - 左子树 - 右子树

void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);

}

2.9二叉树中序遍历

中序遍历的顺序是左子树 - 根 - 右子树

void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreeInOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreeInOrder(root->_right);

}

2.10二叉树后序遍历

后序遍历的顺序是左子树 - 右子树 - 根

void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ", root->_data);

}

2.11二叉树层序遍历

需要使用一个队列实现层序遍历,先将指向根结点的指针入队,当根结点出队列的时候,将它的左右子树的结点的指针入队,就达到了层层遍历的效果

void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", front->_data);
		if (front->_left)
			QueuePush(&q, front->_left);
		if (front->_right)
			QueuePush(&q, front->_right);

	}
	QueueDestroy(&q);
}

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

思路是通过层序遍历的方法,二叉树的叶子结点的下一层节点全部都是NULL,那么在根出队列,左右子树进队列的情况下:

当出队列出到空的时候,判断队列里面的结点是否有非空结点,如果有则证明不是完全二叉树,

反之队列里面都是空结点,则是完全二叉树。

// 判断二叉树是否是完全二叉树
int 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)
		{
			QueueDestroy(&q);
			printf("不是完全二叉树\n");
			return 0;
		}
	}
	QueueDestroy(&q);
	printf("是完全二叉树\n");
	return 1;
}

2.13求二叉树的高度

int TreeHigh(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int lefthigh = TreeHigh(root->_left);
	int righthigh = TreeHigh(root->_right);
	return lefthigh > righthigh ? lefthigh + 1 : righthigh + 1;
	//return TreeHigh(root->_left) > TreeHigh(root->_right) ? TreeHigh(root->_left) + 1 : TreeHigh(root->_right) + 1;
}

3.二叉树总代码

3.1 Tree.h

#pragma once


#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.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 BinaryTreeDestory(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);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);
//二叉树的高度
int TreeHigh(BTNode* root);

3.2 Tree.c

#define _CRT_SECURE_NO_WARNINGS 1


#include"Tree.h"
#include"Queue.h"



BTNode* BuyNode(BTDataType 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;
}

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

	//这里我们的a为我们的数组
	//n为我们数组的最大长度
	//pi为我们遍历数组的指针
	//这里我们使用'#'来表示NULL
	//当我们所指向的位置的元素为#或者我们的指针已经超过了数组的范围的时候,我们就需要返回NULL
	//并且将我们的指针后移
	if (a[*pi] == '#' || *pi >= n)
	{
		printf("NULL ");
		(*pi)++;
		return NULL;
	}

	//创建一个新的二叉树的节点
	BTNode* dst = BuyNode(a[*pi]); 
	printf("%c ", dst->_data);
	(*pi)++;

	//将我们之前开创的节点的左右指针指向数组中所对应的节点
	//如果我们的对应数组中的数据不为空的话,我们的左右指针都会指向新的对应的节点
	//如果我们的节点为空的话,我们会得到的返回值为NULL
	dst->_left = BinaryTreeCreate(a, n, pi);
	dst->_right = BinaryTreeCreate(a, n, pi);

	return dst;
}


//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&((*root)->_left));
	BinaryTreeDestory(&((*root)->_right));
	free(*root);
	*root = NULL;
	return;

}


//计算二叉树的节点个数

int BinaryTreeSize(BTNode* root)
{

	//用静态变量(在堆上,不在栈上)改变局部变量 -> 使得递归的size可以累加起来,但是局部的静态只能初始化一次
	/*static int size = 0;
	if (root == NULL)
	{
		return 0;
	}
	else
		++size;
	BinaryTreeSize(root->_left);
	BinaryTreeSize(root->_right);*/


	//如果我们当前的节点为空,也就是说我们已经到了叶子节点的左右节点,也就是没有节点
	//所以我们需要返回0
	if (root == NULL)
	{
		return 0;
	}

	//如果我们当前的节点的左指针和右指针都是空的话,也就是说这是我们的叶子节点
	//就返回1,也就是只有一个节点
	if (root->_left == NULL && root->_right == NULL)
	{
		return 1;
	}

	//使用递归遍历我们的二叉树,即分别统计我们左子树的节点个数再加上右子树中的节点个数再加上1
	//因为我们需要将我们当前所指的节点算上
	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层节点个数

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)
	{
		return 1;
	}

	//分别遍历我们的左右子树,并且将我们的k的参数--,当我们的k为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* ret1 = BinaryTreeFind(root->_left, x);
	if (ret1)
	{
		return ret1;
	}
	/*BTNode* ret2 = BinaryTreeFind(root->_right, x);
	if (ret2)
	{
		return ret2;
	}
	return NULL;*/
	return BinaryTreeFind(root->_right, x);
}



// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);

}


// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreeInOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreeInOrder(root->_right);

}


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

	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ", root->_data);

}


// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", front->_data);
		if (front->_left)
			QueuePush(&q, front->_left);
		if (front->_right)
			QueuePush(&q, front->_right);

	}
	QueueDestroy(&q);
}



// 判断二叉树是否是完全二叉树
int 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)
		{
			QueueDestroy(&q);
			printf("不是完全二叉树\n");
			return 0;
		}
	}
	QueueDestroy(&q);
	printf("是完全二叉树\n");
	return 1;
}

int TreeHigh(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int lefthigh = TreeHigh(root->_left);
	int righthigh = TreeHigh(root->_right);
	return lefthigh > righthigh ? lefthigh + 1 : righthigh + 1;
	//return TreeHigh(root->_left) > TreeHigh(root->_right) ? TreeHigh(root->_left) + 1 : TreeHigh(root->_right) + 1;
}

3.3 Queue.h

#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);

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

3.4 Queue.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++;
}

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

	return pq->size;
}

//队头删除
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(QueueSize(pq) != 0);
	//一个节点
	if (pq->phead == pq->ptail)
	{
		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;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

3.5 Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Tree.h"

int main()
{
	char a[] = { 'A','B','D','#','#','E','#','H','#','#','C','F','#','#','G','#','#' };
	int b = 0;
	int* pi = &b;
	BTNode* Btree = BinaryTreeCreate(a, 16, pi);
	printf("\n");

	//前序遍历
	BinaryTreePrevOrder(Btree);
	printf("\n");
	//中序遍历
	BinaryTreeInOrder(Btree);
	printf("\n");
	//后序遍历
	BinaryTreePostOrder(Btree);
	printf("\n");
	//层次遍历
	BinaryTreeLevelOrder(Btree);
	printf("\n");

	int number = BinaryTreeSize(Btree);
	printf("%d", number);
	printf("\n");

	//查找为x的节点
	BTNode* find = BinaryTreeFind(Btree, 'A');
	printf("%c", find->_data);
	printf("\n");
	//查询第K层的节点个数
	int W = BinaryTreeLevelKSize(Btree, 3);
	printf("%d\n", W);

	//查询叶子节点的个数
	int count = BinaryTreeLeafSize(Btree);
	printf("%d\n", count);

	//判断当前是否为一颗完全二叉树
	int ret = BinaryTreeComplete(Btree);

	int x = TreeHigh(Btree);
	printf("%d\n", x);
	BinaryTreeDestory(&Btree);

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年全国大学生数据统计与分析竞赛B题论文和代码:电信银行卡诈骗检测数据分析和机器学习模型构建

2024年全国大学生数据统计与分析竞赛B题论文和代码已完成&#xff0c;代码为B题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求解&#x…

SpringBoot Elasticsearch06-以黑马商场为例-黑马程序员学习笔记

黑马商城作为一个电商项目&#xff0c;商品的搜索肯定是访问频率最高的页面之一。目前搜索功能是基于数据库的模糊搜索来实现的&#xff0c;存在很多问题。 首先&#xff0c;查询效率较低。 由于数据库模糊查询不走索引&#xff0c;在数据量较大的时候&#xff0c;查询性能很…

统计信号处理基础 习题解答10-8

题目 一个随机变量具有PDF 。希望在没有任何可用数据的情况下估计的一个现实。为此提出了使最小的MMSE估计量&#xff0c;其中期望仅是对求的。证明MMSE估计量为。将你的结果应用到例10.1&#xff0c;当把数据考虑进去时&#xff0c;证明最小贝叶斯MSE是减少的。 解答 在贝叶…

2024年如何通过完善的工程化,从0到1手把手建立个人 react 组件库

本文聚焦于快速创建并部署个人的组件库&#xff0c;方便平时开发中将通用的组件抽出&#xff0c;也可用于简历上展示个人的组件成果~ 组件库体验地址&#xff1a;components-library 关于以上内容&#xff0c;你是否好奇如何实现的&#xff0c;对于大多数项目&#xff0c;诸如…

计算机网络基础-VRRP原理与配置

目录 一、了解VRRP 1、VRRP的基本概述 2、VRRP的作用 二、VRRP的基本原理 1、VRRP的基本结构图 2、设备类型&#xff08;Master&#xff0c;Backup&#xff09; 3、VRRP抢占功能 3.1&#xff1a;抢占模式 3.2、非抢占模式 4、VRRP设备的优先级 5、VRRP工作原理 三…

素颜个人引导页源码

源码介绍 素颜个人引导页源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 效果预览 源码下载 素颜个人引导页源码

Hadoop3:MapReduce源码解读之Map阶段的数据输入过程整体概览(0)

一、MapReduce中数据流向 二、MapTask并行度 1、原理概览 数据块&#xff1a;Block是HDFS物理上把数据分成一块一块。数据块是HDFS存储数据单位。 数据切片&#xff1a;数据切片只是在逻辑上对输入进行分片&#xff0c;并不会在磁盘上将其切分成片进行存储。数据切片是MapRed…

视频去水印电脑版,视频去水印软件

视频去水印怎么去&#xff0c;一直是视频编辑者们的热门话题。那么&#xff0c;如何去除频水印呢&#xff1f;接下来&#xff0c;我们将为您详细介绍视频去水印方法。 第一种方法&#xff1a; 首先通过浏览器打开 “ 51视频处理官网” 的网站。打开网站后&#xff0c;我们上传…

Linux--标准IO库

一、标准IO简介 所谓标准 I/O 库则是标准 C 库中用于文件 I/O 操作&#xff08;譬如读文件、写文件等&#xff09;相关的一系列库函数的集合&#xff0c;通常标准 I/O 库函数相关的函数定义都在头文件 <stdio.h> 中&#xff0c;所以我们需要在程序源码中包含 <s…

Windows 11中删除分区的几种方法,总有一种适合你

序言 想从Windows 11 PC中删除一个分区,以便将空间重新分配给现有分区或创建一个新分区吗?我们将为你介绍删除Windows 11分区的多种方法。 删除Windows上的分区时会发生什么 删除分区时,Windows会擦除该分区的内容,并将该分区从电脑上的任何位置删除。你将丢失保存在该分…

【启程Golang之旅】协程和管道操作

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

美国演员工会SAG-AFTRA 要求人工智能在广告中使用演员声音需征得同意并付费

SAG-AFTRA 的新豁免允许在人工智能生成的广告中使用演员的声音&#xff0c;但需要同意、补偿和安全措施 美国演员工会&#xff08;SAG-AFTRA&#xff09;推出了一项新的豁免&#xff0c;以保护会员免受未经授权的人工智能在广告中使用其声音的影响。动态人工智能音频广告豁免定…

C语言----字符串、字符数组

一、定义 C语言中的字符串是以字符数组的形态存在的 在C语言中&#xff0c;没有字符串类型&#xff0c;字符串实际上是使用空字符\0结尾的一维字符数组。因此&#xff0c;\0是用于标记字符串的结束。 二 、如何创建字符串&#xff1f; 1.通过字符数组来创建字符串&#xff0…

哈尔滨三级等保测评需要测哪些设备?

哈尔滨三级等保测评需要测的设备&#xff0c;主要包括物理安全设备、网络安全设备和应用安全设备三大类别。这些设备在保障哈尔滨地区信息系统安全方面发挥着至关重要的作用。 首先&#xff0c;物理安全设备是确保信息系统实体安全的基础。在哈尔滨三级等保测评中&#xff0c;物…

[Vue3:Vite构建项目]:安装router实现登录页面路由跳转

文章目录 一&#xff1a;前置依赖查看依赖安装vite npm create vitelatest sys-instruction-0607 --template vue-ts安装路由&#xff1a;npm install vue-router4安装elementUI&#xff1a;npm install element-plus --save 二&#xff1a;配置文件&#xff1a;views&#xff…

大学国学搜题软件?分享7个软件和公众号,来对比看看吧 #经验分享#微信#媒体

在大学里&#xff0c;高效的学习工具可以帮助我们更好地管理时间和资源&#xff0c;提高学习效果。 1.彩虹搜题 这是个老公众号了 多语言查询支持&#xff0c;满足国际用户需求。全球通用&#xff0c;无障碍搜题。 下方附上一些测试的试题及答案 1、某酸碱指示剂的&#xf…

crossover软件安装程序怎么安装 Crossover for Mac切换Windows系统 crossover软件怎么样

CrossOver Mac版是专为苹果电脑用户打造的一款实用工具&#xff0c;这款工具主要方便用户在Mac上运行windows系列的应用程序&#xff0c;用户不需要安装虚拟机就可以实现各种应用程序的直接应用&#xff0c;并且可以实现无缝集成&#xff0c;实现跨平台的复制粘贴和文件互通等&…

Vue2工程化

本节目标 工程化开发项目运行流程组件化组件注册自定义创建项目 工程化开发 基于构建工具的环境开发Vue Webpack的缺点 webpack的配置并不简单基础的配置雷同各公司缺乏统一标准 Vue CLI Vue CLI是Vue官方提供的一个全局命令工具帮助我们快速创建标准化的开发环境( 集成了w…

力扣 74.搜索二维矩阵

题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&am…

Linux RS232

一、确认硬件信息 RS232&#xff1a; 引脚信息&#xff1a; 二、软件配置 1、pinctrl信息&#xff1a; 2、设备树节点&#xff1a; 3、修改串口支持的模式 三、驱动 bsp/drivers/uart/sunxi-uart.c 四、烧录测试 查看串口参数&#xff1a; stty -F /dev/ttyAS3 -a stty -F…