数据结构从入门到精通——二叉树的实现

二叉树的实现

  • 前言
  • 一、二叉树链式结构的实现
    • 1.1前置说明
    • 1.2二叉树的手动创建
  • 二、二叉树的遍历
    • 2.1 前序、中序以及后序遍历
    • 二叉树前序遍历
    • 二叉树中序遍历
    • 二叉树后序遍历
    • 2.2 层序遍历
    • 练习
  • 三、二叉树的具体代码实现
    • 二叉树的节点个数
    • 二叉树叶子节点个数
    • 二叉树第k层节点个数
    • 二叉树查找值为x的节点
    • 二叉树的销毁
    • 二叉树的创建
    • 判断二叉树是否是完全二叉树
  • 四、二叉树的选择练习题
    • 答案
  • 五、二叉树基础oj练习
  • 六、二叉树的完整代码
    • Tree.h
    • Tree.c
    • Test.c


前言

二叉树是一种常见的数据结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。实现二叉树通常涉及定义节点类(包含数据和指向子节点的指针)以及相应的插入、删除和查找操作。遍历二叉树则是访问其所有节点的过程,常见的遍历方式有前序遍历(根-左-右)、中序遍历(左-根-右)和后序遍历(左-右-根)。这些遍历方法可以递归或迭代实现,对于理解二叉树结构和操作非常重要。


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

1.1前置说明

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

1.2二叉树的手动创建

typedef int BTDataType;
typedef struct BinaryTreeNode
{
 	BTDataType _data;
 	struct BinaryTreeNode* _left;
 	struct BinaryTreeNode* _right;
}BTNode;
 
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;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式见下文

再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是:

  1. 空树
  2. 非空:根节点,根节点的左子树、根节点的右子树组成的。

在这里插入图片描述

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

二、二叉树的遍历

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

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

在这里插入图片描述

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

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

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

// 二叉树前序遍历 
void PreOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);

二叉树前序遍历

// 二叉树前序遍历 
void PreOrder(BTNode* root);
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL->");
		return;
	}
	printf("%d->", root->val);
	PreOrder(root->left);
	PreOrder(root->right);
}

二叉树中序遍历

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

二叉树后序遍历

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

下面主要分析前序递归遍历,中序与后序图解类似。

前序遍历递归图解:

在这里插入图片描述

在这里插入图片描述

前序遍历结果:1 2 3 4 5 6
中序遍历结果:3 2 1 5 4 6
后序遍历结果:3 2 5 6 4 1

2.2 层序遍历

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

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

使用队列的形式来实现层序遍历——队列

void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if(root)QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			printf("%c ", front->val);
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
		else
		{
			printf(" N ");
		}
	}
	printf("\n");
	QueueDestroy(&q);
}

层序遍历(也称为广度优先遍历)是一种树的遍历方法,它按照树的层次顺序访问节点。具体来说,从根节点开始,先访问所有相邻的子节点,然后逐层向下遍历,每访问一层的节点,就转向下一层,直到遍历完所有节点。这种遍历方法常用于二叉树、多叉树和图等数据结构。在二叉树中,通常使用队列来实现层序遍历,首先将根节点入队,然后不断从队列中出队节点并访问,同时将该节点的子节点入队,直到队列为空。层序遍历的时间复杂度通常为O(n),其中n为节点数,空间复杂度取决于队列的大小,最坏情况下为O(n)。

练习

请写出下面的前序/中序/后序/层序遍历
在这里插入图片描述

三、二叉树的具体代码实现

二叉树的节点个数

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

该段代码定义了一个名为BinaryTreeSize的函数,用于计算二叉树中节点的总数。函数接受一个指向二叉树根节点的指针root作为参数。如果root为空,则返回0;否则,递归计算左子树和右子树的节点数,并将它们相加,再加上根节点本身,最终返回整个二叉树的节点总数。

二叉树是每个节点最多有两个子节点的树结构,通常子节点被称为“左子节点”和“右子节点”。二叉树的节点个数是指树中所有节点的总数,包括根节点、内部节点(非叶子节点)和叶子节点。计算二叉树的节点个数可以通过遍历树的所有节点来实现,例如使用前序遍历、中序遍历或后序遍历等方法。在遍历过程中,每访问一个节点,就将计数器加1,最终计数器的值就是二叉树的节点个数。此外,对于完全二叉树和满二叉树等特殊类型的二叉树,其节点个数可以通过特定的公式直接计算得出。

二叉树叶子节点个数

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

该函数BinaryTreeLeafSize计算二叉树的叶子节点数量。如果根节点为空,返回0;如果根节点是叶子节点(即没有左右子节点),返回1;否则,递归计算左子树和右子树的叶子节点数量并返回它们的和。

二叉树的叶子节点是指没有子节点的节点。要计算二叉树的叶子节点个数,可以采用递归或迭代的方法。递归方法的基本思路是,对于每个节点,如果它是叶子节点,则计数加1;否则,递归计算其左右子树的叶子节点个数并相加。迭代方法则可以利用队列或栈等数据结构,层次遍历或深度优先遍历二叉树,统计叶子节点的个数。无论采用哪种方法,最终得到的叶子节点个数即为二叉树的叶子节点总数。

二叉树第k层节点个数

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

该函数BinaryTreeLevelKSize计算了二叉树中第k层的节点数量。首先,它检查k是否大于0并确认根节点root是否存在。如果root为空,则返回0。如果k等于1,表示要求的是第一层的节点数,直接返回1。否则,它递归地对左子树和右子树调用自身,计算第k-1层的节点数,然后将这两个结果相加得到第k层的节点数。

二叉树第k层的节点个数可以通过递归或迭代方法计算。在递归方法中,对于给定的二叉树,我们首先检查根节点是否为空。如果为空,则树为空,返回0。否则,我们递归地计算左子树和右子树的第k-1层节点数,并将它们相加得到第k层的节点数。在迭代方法中,我们使用队列进行层序遍历,记录每一层的节点数,直到找到第k层或遍历完整个树。最终,返回第k层的节点数。这两种方法的时间复杂度均为O(n),其中n为二叉树中节点的总数。

二叉树查找值为x的节点

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)return NULL;
	if (root->val == x)return root;
	BTNode* left = BinaryTreeFind(root->left, x);
	if (left)
		return left;
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right)
		return right;
	return NULL;
}

该函数是一个在二叉树中查找指定值的函数。它接受一个二叉树的根节点和一个要查找的值x作为参数。如果根节点为空,则返回NULL。如果根节点的值与x相等,则返回根节点。否则,它递归地在左子树和右子树中查找x。如果在左子树或右子树中找到x,则返回对应的节点。如果在整棵树中都没有找到x,则返回NULL

二叉树的销毁

二叉树的构建及遍历

//二叉树销毁 
 void Binary Tree Destory (BTNode** root) ; 
void BinaryTreeDestroy(BTNode** root)
{
	if ((*root) == NULL)return;
	BinaryTreeDestroy(&(*root)->left);
	BinaryTreeDestroy(&(*root)->right);
	free(*root);
	*root = NULL;
}

该函数BinaryTreeDestroy是一个用于销毁二叉树的递归函数。它接受一个指向二叉树根节点指针的指针root。首先,它检查根节点是否为空,如果为空则直接返回。否则,它递归地销毁左子树和右子树,然后释放根节点的内存,并将根节点指针设置为NULL,从而完成整个二叉树的销毁。

二叉树的创建

// 通过前序遍历的数组" A B D # # E # H # # C F # # G # # " 构建二叉树
 BTNode* Binary TreeCreate(BTDataType* a,int n,int* pi) ; 
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (a == NULL || n <= 0)return NULL;
	if (a[*pi] == ' ')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->val = a[(*pi)++];
	root->left = BinaryTreeCreate(a, n, pi);
	root->right = BinaryTreeCreate(a, n, pi);
	return root;
}

该段代码实现了一个二叉树的创建函数。它接收三个参数:一个数据类型数组a,一个整数n表示数组长度,以及一个整数指针pi指向数组中当前要处理的元素索引。函数首先检查输入是否有效,若数组为空或n小于等于0,则返回NULL。若当前元素为空格,则递增索引并返回NULL。否则,创建一个新的二叉树节点,将当前元素赋值给节点的值,并递归地创建左右子树。最后返回新创建的根节点。

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

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			printf("%c ", front->val);
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
		while (!QueueEmpty(&q))
		{
			BTNode* front = QueueFront(&q);
			if (front)
			{
				QueueDestroy(&q);
				return false;
			}
		}
	}
	QueueDestroy(&q);
	return true;
}

此函数BinaryTreeComplete检查给定的二叉树root是否是完全二叉树。它使用一个队列q进行层序遍历。首先,如果根节点存在,则将其入队。然后在队列不为空的情况下,反复取出队首节点并打印其值,然后将它的左右子节点入队。如果在遍历过程中发现队列中出现了空节点,则立即销毁队列并返回false,因为完全二叉树在层序遍历中不应出现空节点。如果遍历结束,即队列为空,且没有发现空节点,则销毁队列并返回true,说明是完全二叉树。

四、二叉树的选择练习题

  1. 某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为( )
    A、 ABDHECFG
    B、 ABCDEFGH
    C、 HDBEAFCG
    D、 HDEBFGCA
  2. 二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为( )
    A 、E
    B、 F
    C、 G
    D、 H
  3. 设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列____。
    A、 adbce
    B 、decab
    C、 debac
    D、 abcde
  4. 某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为( )
    A 、FEDCBA
    B、 CBAFED
    C、 DEFCBA
    D、 ABCDEF

答案

1.A
2.A
3.D
4.A

五、二叉树基础oj练习

  1. 单值二叉树
  2. 检查两颗树是否相同
  3. 对称二叉树
  4. 二叉树的前序遍历
  5. 二叉树中序遍历
  6. 二叉树的后序遍历
  7. 另一颗树的子树

六、二叉树的完整代码

Tree.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType val;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;

}BTNode;
typedef BTNode* QDatatype;
typedef struct QueueNode
{
	QDatatype val;
	struct QueueNode* next;
}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);

//创建二叉树
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);

Tree.c

#include "Tree.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 = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}
void QueuePush(Queue* pq, QDatatype x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("newnode malloc :");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
	if (pq->ptail)
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->phead = pq->ptail = newnode;
	}
	pq->size++;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}
void QueuePop(Queue* pq)
{
	assert(pq);
	//assert(!QueueEmpty(pq));
	assert(pq->phead != 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 != NULL);
	return pq->phead->val;
}
QDatatype QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail != NULL);
	return pq->ptail->val;
}
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (a == NULL || n <= 0)return NULL;
	if (a[*pi] == ' ')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->val = a[(*pi)++];
	root->left = BinaryTreeCreate(a, n, pi);
	root->right = BinaryTreeCreate(a, n, pi);
	return root;
}
void BinaryTreeDestroy(BTNode** root)
{
	if ((*root) == NULL)return;
	BinaryTreeDestroy(&(*root)->left);
	BinaryTreeDestroy(&(*root)->right);
	free(*root);
	*root = NULL;
}
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);
}
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)return 0;
	if (k == 1)return 1;
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)return NULL;
	if (root->val == x)return root;
	BTNode* left = BinaryTreeFind(root->left, x);
	if (left)
		return left;
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right)
		return right;
	return NULL;
}
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%c ", root->val);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%c ", root->val);
	BinaryTreeInOrder(root->right);
}
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%c ", root->val);
}

bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			printf("%c ", front->val);
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
		while (!QueueEmpty(&q))
		{
			BTNode* front = QueueFront(&q);
			if (front)
			{
				QueueDestroy(&q);
				return false;
			}
		}
	}
	QueueDestroy(&q);
	return true;
}

Test.c

#include "Tree.h"
int main()
{
	char a[] = { 'a','b','c',' ',' ','d','e',' ','g',' ',' ','f',' ',' ',' ' };
	int pi = 0;
	BTNode* root = BinaryTreeCreate(a, sizeof(a) / sizeof(a[0]), &pi);
	BinaryTreePrevOrder(root);
	printf("\n");

	BinaryTreeInOrder(root);
	printf("\n");

	BinaryTreePostOrder(root);
	printf("\n");

	printf("TreeSize : %d\n", BinaryTreeSize(root));
	printf("TreeKLevel : %d\n", BinaryTreeLevelKSize(root, 3));

	BTNode* ret = BinaryTreeFind(root, 3);
	printf("TreeFind : %p\n", ret);
	

	BinaryTreeLevelOrder(root);
	printf("\n");
	printf("BinaryTreeComplete %d\n ", BinaryTreeComplete(root));
	BinaryTreeDestroy(&root);
	root = NULL;

	return 0;
}

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1bgxnv3eldfha


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

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

相关文章

【数字图像处理系列】读取图像

【数字图像处理系列】读取图像 使用函数 imread 可以将图像读人 MATLAB 环境&#xff0c;imread 的语法为 imread(filename)其中&#xff0c;filename是一个含有图像文件全名的字符串(包括任何可用的扩展名)。例如&#xff0c;命令行 >>f imread(pout.tif)将tif图像po…

MATLAB环境下基于振动信号的轴承状态监测和故障诊断

故障预测与健康管理PHM分为故障预测和健康管理与维修两部分&#xff0c;PHM首先借助传感器采集关键零部件的运行状态数据&#xff0c;如振动信号、温度图像、电流电压信号、声音信号及油液分析等&#xff0c;提取设备的运行监测指标&#xff0c;进而实现对设备关键零部件运行状…

精确率(召回率)的权衡(Machine Learning研习十六)

精确率&#xff08;召回率&#xff09;的权衡 为了理解这种权衡&#xff0c;让我们看看 SGDClassifier如何做出分类决策。 对于每个实例&#xff0c;它根据决策函数计算分数。 如果该分数大于阈值&#xff0c;则将该实例分配给正类&#xff1b; 否则它会将其分配给负类。 图 3…

基于SpringBoot+Vue保密信息学科平台系统设计与实现(源码+部署说明+演示视频+源码介绍+lw)

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

filezilla客户端的应用以及ftplftpwget的用法

filezilla的应用 用户的配置查看上一篇文章FTP3种用户的配置 进入filezilla软件测试 用yy用户登录发现可以上传下载创建删除 再用cc用户登录发现不能上传不能删除不能创建只能下载 ftp&lftp&wget客户端的应用 以命令行的方式连接ftp&#xff0c;一般只会用到上…

【HTTP完全注解】范围请求

范围请求 范围请求是HTTP的一种内容协商机制&#xff0c;该机制允许客户端只请求资源的部分内容。范围请求在传送大的媒体文件&#xff0c;或者与文件下载的断点续传功能搭配使用时非常有用。 范围请求的工作流程 范围请求通过在HTTP请求标头Range中表明需要请求的部分资源的…

Windows东方通下载及使用

把安装包都拖到桌面来&#xff0c;可以拖一个解压包进去 下载东方通可以不用配环境变量 双击安装包 下一步 点击接受 选择版本&#xff0c;都可以 选择安装路径 下一步 点击安装 改端口号 移到桌面 把安装包里面的文件拖进去 过期了&#xff0c;记得改时间 点击时间面板&…

【回顾练习】静态路由配置综合实验报告

一、分析要求 为R6设备配置公有IP地址&#xff0c;并确保只能进行IP地址配置&#xff0c;无法进行其他配置。为R1-R5设备分配私有IP地址。为R1、R2、R4配置两个环回地址&#xff0c;为R5、R6配置一个环回地址。在R3上配置DHCP服务&#xff0c;以供两台PC自动获取IP地址。使用动…

Vuex状态、数据持久化(vue2、vue3状态数据持久化)

简介&#xff1a;Vuex是一个仓库&#xff0c;是vue的状态管理工具&#xff0c;存放公共数据&#xff0c;任何组件都可以使用vuex里的公共数据。Vuex提供了插件系统&#xff0c;允许我们使用 vuex-persistedstate插件&#xff0c;将Vuex的状态持久化到本地存储中&#xff0c;解决…

如何安装配置Goland并使用固定公网地址SSH远程连接本地服务器

文章目录 1. 安装配置GoLand2. 服务器开启SSH服务3. GoLand本地服务器远程连接测试4. 安装cpolar内网穿透远程访问服务器端4.1 服务器端安装cpolar4.2 创建远程连接公网地址 5. 使用固定TCP地址远程开发 本文主要介绍使用GoLand通过SSH远程连接服务器&#xff0c;并结合cpolar内…

蓝桥杯--高精度加法--基础

import java.util.*; import java.math.*; public class BASIC30 {public static void main(String[] args) {//阶乘的运算&#xff0c;因为计算出来的数据会足够的大&#xff0c;所以这个地方使用阶乘Scanner scanner new Scanner(System.in);//只能将对应的字符串转化为BigI…

STL —— string(1)

目录 1. 模板 1.1 泛型编程 1.2 函数模板 1.2.1 函数模板概念 1.2.2 函数模板格式 1.2.3 函数模板的原理 1.2.4 显式实例化 1.2.5 模板参数的匹配原则 1.3 类模板 1.3.1 类模板定义格式 1.3.2 类模板的实例化 2. STL —— string类 2.1 STL 简介 2.2 标准库中的s…

Gold Effects

HDRP、URP、LWRP和标准支持 完全可定制的金币效果。几乎每个属性都是可调整的,您可以更改这些效果的颜色、渐变、噪波纹理和整体形状。支持HDRP、URP和LWRP,当然也支持标准渲染器。易于拖放设置,带有定制示例的演示场景。使用标准Unity Animator为箱子制作动画,因此您可以轻…

#鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行

3 月 19 日&#xff0c;#鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行。 现场&#xff0c;深圳市南山区人民政府副区长李志娜发布《2024 年南山区支持鸿蒙原生应用发展首批政策措施清单》&#xff0c;从加强鸿蒙原生应用供给能力、推动鸿蒙原生应用产业集聚、完善鸿蒙原生…

windows管理github代码

资料 windows SSH下载github

Windows抓取密码的四种方式其他各类密码抓取

对于Windows&#xff08;不是域环境&#xff09;我们有四种方法去抓取它的密码 在线读取SAM文件离线读取SAM文件在线读取Lsass进程离线读取Lsass进程 在这次的blog&#xff0c;我们还是用的mimkatz 目录 1.在线读取SAM文件 2.离线读取sam文件 3.在线读取lsass进程 4.离线…

如何与手机共享笔记本电脑的互联网?这里提供详细步骤

这篇文章介绍了如何通过将手机变成Wi-Fi热点来与手机共享笔记本电脑的互联网连接。 如何共享笔记本电脑的互联网连接 你可以通过Wi-Fi或有线共享笔记本电脑的数据连接,具体取决于你的设置。 Windows Windows允许你通过ICS共享你的互联网连接。ICS,或称互联网连接共享,是W…

如何使用 PDF 转换器完成 PDF 转 Word

如果您正在寻找能够轻松将 PDF 转换为 Word 的软件&#xff0c;那么奇客PDF转换器是一个不错的选择。下面这篇文章将指导您如何使用奇客PDF转换器将PDF文件转换为Word。 奇客PDF转换器也称为奇客PDF&#xff0c;是将 PDF 文件内容转换为 Word 文本格式的优秀工具。通过使用 PD…

eNSP实验一(静态)

目录 命名更改 子网划分 配置IP DHCP配置 配置静态路由 NET设置 Telnet及端口映射 命名更改 <Huawei>system-view Enter system view, return user view with CtrlZ. [Huawei]sysname R1 [R1] 1、R6为ISP&#xff0c;接口IP地址均为公有地址(12.0.0.0/24)&#…

运动想象 (MI) 迁移学习系列 (14) : EEGNet-Fine tuning

运动想象迁移学习系列:EEGNet-Fine tuning 0. 引言1. 主要贡献2. 提出的方法2.1 EEGNet框架2.2 微调 3. 实验结果3.1 各模型整体分类结果3.2 算法复杂度比较3.3 不同微调方法比较 4. 总结欢迎来稿 论文地址&#xff1a;https://www.nature.com/articles/s41598-021-99114-1#cit…