数据结构——二叉树(C语言版)

前言

二叉树是一种非线性的数据结构。二叉搜索树、堆、红黑树等高阶数据结构都是依托于二叉树的基础实现的,所以我们有必要好好研究一下“二叉树”这种数据结构。本文只介绍二叉树的基础及中等用法,笔者能力有限,欠妥当之处欢迎批评指正。

二叉树是树的一种,在介绍二叉树之前,我们先认识一下什么是“树”

概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
有一个特殊的结点,称为根结点,根结点没有前驱结点
除根结点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i<= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
因此,树是递归定义的(这是解决很多与树相关问题的核心思想,我们也会在后文中多次强调)

树和非树

子树一定是不相交的,除了根节点没有前驱节点(也叫父节点,这些专有名词我们在后面介绍),其他节点有且只有一个前驱节点。把握以上两点,树和非数的判别我想不是什么大问题。

树的相关专有名词

这里我们也只是简单介绍常用的专有名词,其余的有兴趣的读者可以自行查询。

结点的度:一个结点含有的子树的个数称为该结点的度
叶结点或终端结点:度为0的结点称为叶结点

非终端结点或分支结点:度不为0的结点
双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点
兄弟结点:具有相同父结点的结点互称为兄弟结点
树的度:一棵树中,最大的结点的度称为树的度

树的表示

树的表示相对复杂,树是非线性的,一般树的度虽然已知,但在每个前驱中预留度个位置来存储可能存在的子节点的地址,难免造成内存的浪费。此时我们一般会考虑“左孩子右兄弟表示法”。

typedef int DataType;
struct Node
{
struct Node* firstChild1; // 第一个孩子结点
struct Node* pNextBrother; // 指向其下一个兄弟结点
DataType data; // 结点中的数据域
};

左孩子节点负责找到节点的第一个孩子,再由孩子节点的右兄弟找到所有的子节点。

树的应用

 文件系统的目录树结构。这也就可以解释为啥,同一个文件夹下不允许有同名的文件,但是在不同文件夹下允许同名。

二叉树

我们介绍完了树的相关概念,接下来我们介绍一下今天的主角——二叉树

概念

二叉树是度不超过二的一颗树。

注意:

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

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

一棵二叉树是结点的一个有限集合,该集合:为空或由一个根结点加上两棵别称为左子树和右子树的二叉树组成


特殊二叉树

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

 性质

1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2^{i-1}个结点.
2. 若规定根结点的层数为1,则深度为h的二叉树的最大结点数是2^{h}-1 .
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 n0=n2 +1
4.若规定根结点的层数为1,具有n个结点的满二叉树的深度,h=log以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. 顺序存储
顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面再展开。二叉树顺
序存储在物理上是一个数组,在逻辑上是一颗二叉树
2. 链式存储
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链。三叉链是再左右孩子的基础上添加父节点的表示形式。

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
struct BinTreeNode* left; // 指向当前结点左孩子
struct BinTreeNode* right; // 指向当前结点右孩子
BTDataType data; // 当前结点值域
}
// 三叉链
struct BinaryTreeNode
{
struct BinTreeNode* parent; // 指向当前结点的双亲
struct BinTreeNode* left; // 指向当前结点左孩子
struct BinTreeNode* right; // 指向当前结点右孩子
BTDataType data; // 当前结点值域
};


堆是一种在完全二叉树的基础上再添加约束的数据结构。堆约束堆中任意结点的值总是不大于或不小于其父结点的值。如果任意父节点大于等于左右孩子节点,我们称之为大堆;如果任意父节点小于等于左右孩子节点,我们称之为小堆。注意,堆只约束了父节点和左右孩子节点的关系,左右孩子节点之间的大小没有任何关联,堆是建立在完全二叉树之上的数据结构。

堆的实现

我们这里介绍堆在C语言上的实现

Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <stdbool.h>typedef int dataType;typedef struct Tree
{dataType* arr;int sz;int len;
}Tree;//初始化
Tree* chushihua();//销毁
void xiaohui(Tree* t);//插入元素
void push(Tree* t, dataType x);//删除元素
void pop(Tree* t);//获得根节点元素
dataType top(Tree* t);//判断是否为空堆
bool isEmpty(Tree* t);

Heap.c

#include "Heap.h"//初始化
Tree* chushihua(int x)
{Tree* ret = (Tree*)malloc(sizeof(Tree));ret->arr = NULL;ret->len = ret->sz = 0;return ret;
}//销毁
void xiaohui(Tree* t)
{assert(t);free(t->arr);free(t);
}//交换
void swap(dataType* e1, dataType* e2)
{dataType  tmp = *e1;*e1 = *e2;*e2 = tmp;
}//向上调整
void xiangshangtiaozheng(dataType* arr, int i) {while (i > 0 && arr[i] < arr[(i - 1) / 2]) {swap(&(arr[i]), &(arr[(i - 1) / 2]));i = (i - 1) / 2;}
}//插入元素
void push(Tree* t, dataType x) {assert(t);if (t->sz == t->len) {int newlen = t->arr == NULL ? 4 : t->len * 2;t->arr = (dataType*)realloc(t->arr, sizeof(dataType) * newlen);t->len = newlen;}(t->arr)[t->sz++] = x;xiangshangtiaozheng(t->arr, t->sz - 1);
}//向下调整
void xiangxiatiaozheng(dataType* arr, int i, int sz) {while (i * 2 + 1 < sz) {int chile = i * 2 + 1;if (chile + 1 < sz && arr[chile + 1] < arr[chile]) {chile++;}if (arr[i] > arr[chile]) {swap(&arr[i], &arr[chile]);i = chile;}else return;}
}//删除根元素
void pop(Tree* t)
{assert(t && t->sz > 0);swap(&t->arr[0], &t->arr[t->sz - 1]);t->sz--;xiangxiatiaozheng(t->arr, 0, t->sz);
}//获得根节点元素
dataType top(Tree* t)
{assert(t && t->sz);return t->arr[0];
}//判断是否为空堆
bool isEmpty(Tree* t)
{assert(t);return 0 == t->sz;
}

堆的实现最重要的是掌握向上调整算法和向下调整算法。这两种算法在逻辑上是相似的,只需要重点了解从哪里开始调整,往哪调整和什么时候调整结束这三点即可。

堆的应用

堆的应用我们在这里介绍两个——堆排序和TopK问题

堆排序

堆排序的实现可以归为两步

  1. 建堆。升序建大堆,降序建小堆
  2. 排序,依次删除堆元素,当堆删空就会得到有序的数组
//堆排序
void sort(int* arr, int sz);
//向下调整
void xiangxiatiaozheng(dataType* arr, int i, int sz) {while (i * 2 + 1 < sz) {int chile = i * 2 + 1;if (chile + 1 < sz && arr[chile + 1] < arr[chile]) {chile++;}if (arr[i] > arr[chile]) {swap(&arr[i], &arr[chile]);i = chile;}else return;}
}//交换
void swap(dataType* e1, dataType* e2)
{dataType  tmp = *e1;*e1 = *e2;*e2 = tmp;
}//堆排序(降序,建小堆)
void sort(int* arr, int sz)
{//向上调整建堆 时间复杂度 N*longN/*for (int i = 1; i < sz; i++) {xiangshangtiaozheng(arr, i);}*///向下调整建堆 时间复杂度 Nfor (int i = (sz - 2) / 2; i >= 0; i--) {xiangxiatiaozheng(arr, i, sz);}int end = sz - 1;while (end > 0) {swap(&arr[0], &arr[end]);xiangxiatiaozheng(arr, 0, end);end--;}
}
TopK

 TOP-K问题,即求数据集合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

此时,我们的一般思路是所有数据入堆,在pop() K 次得到前K个数据。但如果考虑到数据量很大,此时这种方法会导致内存的急速消耗,并不是最优的方法。

此时我们推荐建一个K个大小的堆。用数据集合中前K个元素来建堆,求前k个最大的元素,则建小堆;求前k个最小的元素,则建大堆。用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素。所有数据比较完之后即可得到topK个数据。

#define K 3 //定义求K个数据
#define N 10 //定义元素总个数
#include <stdio.h>
#include <time.h>
#include <stdlib.h>void xieru(); //随机写入N个数据供测试
int* topK(int k);//topK算法,从N个数据中找出topK
void jiandui(int* arr, int k); //前K个元素建堆算法
void swap(int* e1, int* e2);//交换算法
void xiangshang(int* arr, int ch);//向上调整算法
void xiangxia(int* arr, int pr, int k);//向下调整算法int main()
{xieru();int* arr = topK(K);for (int i = 0; i < K; i++) {printf("%d ", arr[i]);}free(arr);arr = NULL;
}void xieru()
{srand(time(NULL));FILE* pf = fopen("data.txt", "w");if (pf == NULL){perror("fopen error");return;}for (int i = 0; i < N; i++){fprintf(pf, "%d\n", rand() + i);}fclose(pf);pf = NULL;
}int* topK(int k) {int* ret = malloc(sizeof(int) * k);FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen error");return;}for (int i = 0; i < k; i++){fscanf(pf, "%d", ret + i);}jiandui(ret, k);int tmp;while (fscanf(pf, "%d\n", &tmp)!=EOF) {if (tmp > ret[0]) {ret[0] = tmp;xiangxia(ret, 0, k);}}fclose(pf);return ret;
}void xiangshang(int* arr, int ch) {int pr = (ch - 1) / 2;while (ch > 0 && arr[ch] < arr[pr]) {swap(arr + ch, arr + pr);ch = pr;pr = (ch - 1) / 2;}
}void xiangxia(int* arr, int pr, int k) {int ch = pr * 2 + 1;while (ch < k) {if (ch + 1 < k && arr[ch + 1] < arr[ch]) ch++;if (arr[ch] < arr[pr]) {swap(arr + ch, arr + pr);pr = ch;ch = pr * 2 + 1;}else return;}
}void jiandui(int* arr, int k)
{/*for (int i = 1; i < k; i++) {xiangshang(arr, i);}*/for (int i = (k - 2) / 2; i >= 0; i--) {xiangxia(arr, i, k);}
}void swap(int* e1, int* e2)
{int tmp = *e1;*e1 = *e2;*e2 = tmp;
}

二叉树的链式结构

前面我们介绍的堆利用的是二叉树的顺序结构,接下来我们来介绍二叉树的链式结构。

前置声明

二叉树问题的核心思想

笔者在这里完整展示C语言实现二叉树链式结构的源码。二叉树的很多算法都是递归解决的,这也是笔者一开始在前面强调的二叉树是递归定义的,这一点是很多二叉树问题的核心思想。

二叉树的遍历

二叉树的创建是比较复杂的算法,读者可以先手写一棵树研究遍历的算法。

二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次
二叉树的遍历有:前序/中序/后序的递归结构遍历:
1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

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

其他非遍历问题

结点个数以及高度,二叉树的创建和销毁,只需要把握前面介绍的核心思想和遍历的方法即可完成。

二叉树的一些问题需要引入队列这一数据结构辅助完成。

二叉树的实现

Tree.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>typedef char dataType;typedef struct TreeNode
{dataType data;struct TreeNode* left;struct TreeNode* right;
}TreeNode;//手动创建一棵树
TreeNode* CreatBinaryTree();//创建节点
TreeNode* BuyNewNode(dataType x);//前序便利
void PrevOrder(TreeNode* root);//中序便利
void InOrder(TreeNode* root);//后序便利
void HouOrder(TreeNode* root);//求节点个数
int TreeSize(TreeNode* root);//求叶子节点个数
int TreeYeZiSize(TreeNode* root);//求树的高度
int TreeHeight(TreeNode* root);//求第K层节点的个数
int TreeSizeByK(TreeNode* root, int k);// 二叉树查找值为x的节点
TreeNode* BinaryTreeFind(TreeNode* root, dataType x);// 二叉树销毁
void BinaryTreeDestory(TreeNode** root);// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(TreeNode* root);// 层序遍历
void BinaryTreeLevelOrder(TreeNode* root);// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
TreeNode* BinaryTreeCreate(dataType* a, int n, int* pi);//根据字符串创建二叉树
//TreeNode* chuangJian(char* arr, int* pi);

Tree.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Tree.h"
#include "duilie.h"TreeNode* CreatBinaryTree()
{TreeNode* node1 = BuyNewNode(1);TreeNode* node2 = BuyNewNode(2);TreeNode* node3 = BuyNewNode(3);TreeNode* node4 = BuyNewNode(4);TreeNode* node5 = BuyNewNode(5);TreeNode* node6 = BuyNewNode(6);TreeNode* node7 = BuyNewNode(7);node1->left = node2;node1->right = node3;node2->left = node4;node2->right = node5;node3->left = node6;node3->right = node7;return node1;
}TreeNode* BuyNewNode(dataType x)
{TreeNode* ret = (TreeNode*)malloc(sizeof(TreeNode));if (ret == NULL) {perror("malloc");return NULL;}ret->data = x;ret->left = ret->right = NULL;return ret;
}void PrevOrder(TreeNode* root)
{if (root == NULL) return;printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}void InOrder(TreeNode* root)
{if (root == NULL) return;InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}void HouOrder(TreeNode* root)
{if (root == NULL) return;HouOrder(root->left);HouOrder(root->right);printf("%d ", root->data);
}int TreeSize(TreeNode* root)
{if (root == NULL) return 0;return 1 + TreeSize(root->left) + TreeSize(root->right);
}int TreeYeZiSize(TreeNode* root)
{if (root == NULL) return 0;if (root->left == NULL && root->right == NULL) return 1;return TreeYeZiSize(root->left) + TreeYeZiSize(root->right);
}int TreeHeight(TreeNode* root)
{if (root == NULL) return 0;int left = TreeHeight(root->left);int right = TreeHeight(root->right);return left > right ? left + 1 : right + 1;
}int TreeSizeByK(TreeNode* root, int k)
{if (root == NULL) return 0;if (k == 1) return 1;return TreeSizeByK(root->left, k - 1) + TreeSizeByK(root->right, k - 1);
}TreeNode* BinaryTreeFind(TreeNode* root, dataType x)
{if (root == NULL) return NULL;if (root->data == x) return root;TreeNode* tmp = BinaryTreeFind(root->left, x);if (tmp != NULL)return tmp;tmp = BinaryTreeFind(root->right, x);if (tmp != NULL)return tmp;return NULL;}void BinaryTreeDestory(TreeNode** root)
{if ((*root) == NULL) return;BinaryTreeDestory(&(*root)->left);BinaryTreeDestory(&(*root)->right);free(*root);*root = NULL;
}int BinaryTreeComplete(TreeNode* root)
{if (root == NULL) return 1;Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){TreeNode* tmp = QueueFront(&q);QueuePop(&q);if (tmp == NULL)break;QueuePush(&q, tmp->left);QueuePush(&q, tmp->right);}while (!QueueEmpty(&q)) {TreeNode* tmp = QueueFront(&q);QueuePop(&q);if (tmp != NULL){QueueDestroy(&q);return 0;}			}QueueDestroy(&q);return 1;
}void BinaryTreeLevelOrder(TreeNode* root)
{if (root == NULL) return;Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){TreeNode* tmp = QueueFront(&q);QueuePop(&q);printf("%d ", tmp->data);if (tmp->left != NULL)QueuePush(&q, tmp->left);if (tmp->right != NULL)QueuePush(&q, tmp->right);}QueueDestroy(&q);
}TreeNode* BinaryTreeCreate(dataType* a, int n, int* pi)
{if (a == NULL) return NULL;if (!(*pi <= n)) return NULL;TreeNode* root = NULL;if (a[*pi] == '\0') return NULL;if (a[*pi] != '#') {root = BuyNewNode(a[(*pi)++]);}else {(*pi)++;return NULL;}root->left = BinaryTreeCreate(a, n, pi);root->right = BinaryTreeCreate(a, n, pi);return root;
}//TreeNode* chuangJian(char* arr, int* pi)
//{
//	if (arr == NULL) return NULL;
//	TreeNode* root = NULL;
//	//if (arr[*pi] == '\0') return NULL;
//	if (arr[*pi] != '#') {
//		root = BuyNewNode(arr[(*pi)++]);
//	}
//	else {
//		(*pi)++;
//		return NULL;
//	}
//	root->left = chuangJian(arr, pi);
//	root->right = chuangJian(arr, pi);
//	return root;
//}

dui.h 

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Tree.h"typedef TreeNode* QDataType;// 链式结构:表示队列 
typedef struct QListNode
{struct QListNode* _next;QDataType _data;
}QNode;// 队列的结构 
typedef struct Queue
{QNode* _head;QNode* _last;
}Queue;// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

dui.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "duilie.h"void QueueInit(Queue* q)
{assert(q);q->_head = NULL;q->_last = NULL;
}QNode* NewNode(QDataType data)
{QNode* ret = (QNode*)malloc(sizeof(QNode));ret->_data = data;ret->_next = NULL;return ret;
}void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* newNode = NewNode(data);if (q->_head == NULL) {q->_head = newNode;q->_last = newNode;}else {q->_last->_next = newNode;q->_last = newNode;}
}void QueuePop(Queue* q)
{assert(q && q->_head != NULL);QNode* rem = q->_head;q->_head = q->_head->_next;free(rem);if (q->_head == NULL) {q->_last = NULL;}
}QDataType QueueFront(Queue* q)
{assert(q && q->_head);return q->_head->_data;
}QDataType QueueBack(Queue* q)
{assert(q && q->_last);return q->_last->_data;
}int QueueSize(Queue* q)
{assert(q);int ret = 0;QNode* cut = q->_head;while (cut != NULL) {ret++;cut = cut->_next;}return ret;
}int QueueEmpty(Queue* q)
{assert(q);return q->_head == NULL;
}void QueueDestroy(Queue* q)
{assert(q);if (q->_head == NULL) return;QNode* cut = q->_head;while (cut != NULL) {QNode* rem = cut->_next;free(cut);cut = rem;}q->_head = q->_last = NULL;
}

结语

以上便是今天的全部内容。如果有帮助到你,请给我一个免费的赞。

因为这对我很重要。

编程世界的小比特,希望与大家一起无限进步。

感谢阅读!

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

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

相关文章

【RS】哨兵系列新网站无法下载的问题及解决办法(Sentinel-2)

最近有些小伙伴留言说哨兵数据无法下载&#xff0c;网站打开后会有一层蒙版&#xff0c;无法选取研究区等信息&#xff0c;今天就跟大家分享一下如何解决这个问题。还知道如何下载的小伙伴可以移步到之前的文章&#xff1a;【RS】欧空局Sentinel-2卫星数据下载(哨兵1、2、3、5P…

海外短剧看剧系统搭建部署,h5/app双端,系统页面一键翻译功能,批量上传素材等功能。

目录 前言&#xff1a; 一、海外短剧系统有是吗功能&#xff1f; 二、海外短剧项目在海外反馈怎么样&#xff1f; 总结&#xff1a; 前言&#xff1a; 海外短剧系统搭建开发&#xff0c;想进军海外短剧市场的&#xff0c;搭建这样一款海外短剧系统是必要的。海外短剧市场规…

ATA-4051C高压功率放大器应用分享:超声波测量液位系统

超声波测量液位是一种非接触式液位测量方法&#xff0c;其原理是利用超声波的传播特性来测量液位。超声波是一种高频机械波&#xff0c;其频率高于人类能够听到的频率&#xff0c;通常在100kHz以上。超声波具有较好的穿透性和反射性&#xff0c;可以在固体、液体和气体中传播&a…

FTP

文章目录 概述主动模式和被动模式的工作过程注意事项 概述 文件传输协议 FTP&#xff08;File Transfer Protocol&#xff09;在 TCP/IP 协议族中属于应用层协议&#xff0c;是文件传输标准。主要功能是向用户提供本地和远程主机之间的文件传输&#xff0c;尤其在进行版本升级…

ThinkBook 14 G6+ IMH(21LD)原厂Win11系统oem镜像下载

lenovo联想笔记本电脑原装出厂Windows11系统安装包&#xff0c; 恢复开箱状态自带预装系统&#xff0c;含恢复重置还原功能 链接&#xff1a;https://pan.baidu.com/s/1WIPNagHrC0wqYC3HIcua9A?pwdhzqg 提取码&#xff1a;hzqg 联想原装出厂系统自带所有驱动、出厂主题壁…

Zabbix安装:构建高效可靠的Zabbix监控系统

目录 引言 一、zabbix基本介绍 &#xff08;一&#xff09;什么是zabbix &#xff08;二&#xff09;zabbix结构体系 &#xff08;三&#xff09;zabbix监控对象 &#xff08;四&#xff09;zabbix进程 &#xff08;五&#xff09;zabbix监控模式 &#xff08;六&#…

【SQL边干边学系列】01介绍性问题

文章目录 前言介绍性问题1.我们有哪些承运商&#xff1f;2. 从目录表中查询特定字段3.销售代表4.在美国的销售代表5.由特定员工ID下的订单6.供应商和联系人信息 答案1.我们有哪些承运商&#xff1f;2. 从目录表中查询特定字段3.销售代表4.在美国的销售代表5.由特定员工ID下的订…

Codes 重新定义 SaaS 模式的研发项目管理平台开源版 4.5.5 发布

一&#xff1a;简介 Codes 重新定义 SaaS 模式 云端认证 程序及数据本地安装 不限功能 30 人免费 Codes 是一个 高效、简洁、轻量的一站式研发项目管理平台。包含需求管理&#xff0c;任务管理&#xff0c;测试管理&#xff0c;缺陷管理&#xff0c;自动化测试&#xff0…

海外短剧的未来展望:创新与发展的方向

随着全球化的加速和互联网技术的飞速发展&#xff0c;海外短剧作为一种新兴的娱乐形式&#xff0c;正逐渐赢得广大观众的喜爱。在这个充满变革的时代&#xff0c;海外短剧面临着前所未有的机遇与挑战。本文将探讨海外短剧未来的创新与发展方向。 一、内容创新&#xff1a;打破传…

网络ip地址冲突会出现什么情况

在现代数字化社会中&#xff0c;网络IP地址扮演着至关重要的角色&#xff0c;它是设备在网络中唯一识别的标识。然而&#xff0c;当网络中出现IP地址冲突时&#xff0c;一系列问题便会随之而来。那么&#xff0c;网络ip地址冲突会出现什么情况呢&#xff1f;下面一起来跟虎观代…

k8s-部署对象存储minio

环境信息 minio版本 :最新 k8s 版本1.22 使用nfs作为共享存储 一.单节点安装包部署 脚本部署&#xff0c;一键部署&#xff0c;单节点应用于数据量小&#xff0c;一些缓存存储&#xff0c;比如gitlab-runner的产物数据&#xff0c;maven的打包依赖数据 #!/bin/bash# 步骤…

如何进行辐射抗扰度磁场测试?

一、为什么要进行闭环磁场测试&#xff1f; 辐射抗扰度测试中进行闭环磁场测试是为了评估设备在外部磁场影响下的性能表现。外部磁场可能来自各种源头&#xff0c;例如电力线、电动机、变压器等&#xff0c;这些磁场可能干扰设备的正常工作。闭环磁场测试通过模拟设备在实际工…

虾皮Lazada流量“滑铁卢”?自养号测评补单让你轻松翻盘!

当作为虾皮&#xff08;Shopee&#xff09;或Lazada平台的卖家时&#xff0c;密切关注流量数据是至关重要的。如果观察到店铺的流量出现下滑趋势&#xff0c;首要任务便是深入探究流量减少的根本原因。在明确了导致流量下滑的关键因素后&#xff0c;卖家便能更有针对性地采取措…

Java学习20——Map接口

目录 一.Map&#xff1a; 1.基本介绍&#xff1a; 2.Map常用方法&#xff1a; 3.Map的遍历方法&#xff1a; 4.HashMap: 1.基本介绍&#xff1a; 2.HashMap底层扩容机制&#xff1a; 5.Hashtable&#xff1a; 1.基本介绍&#xff1a; 2.HashMap和Hashtable的对比&…

Image Search-这是你的图像搜索

Image Search-这是你的图像搜索 什么是图像搜索图像搜索开通图像搜索商品图片搜索图片搜索图片新增批量操作OSS-创建bucket上传文件创建increment.meta并上传元信息导出 体验感受 什么是图像搜索 在接触一个新的产品时&#xff0c;我们首先要知道这款产品是什么&#xff1f;那…

ARM IHI0069F GIC architecture specification (8)

3.2中断旁路支持 CPU interface可以支持中断信号旁路&#xff0c;使得当接口发出的中断信号被禁用时&#xff0c;传统中断信号被传递到PE上的中断请求输入&#xff0c;从而绕过GIC功能。 是否支持旁路由实际设计决定。 用于确定是否使用GICv3 FIQ和IRQ输出或旁路信号的控制取决…

英伟达在2024台北电脑展上推出NIM云原生微服务

&#x1f989; AI新闻 &#x1f680; 英伟达推出NIM云原生微服务&#xff0c;助力生成式AI发展 摘要&#xff1a;在2024台北电脑展上&#xff0c;黄仁勋介绍了生成式人工智能将推动软件全栈重塑&#xff0c;并展示了Nvidia Inference Microservices&#xff08;NIM&#xff0…

《2024快手未成年人保护报告》发布:八大功能保护未成年人隐私信息

5月31日&#xff0c;快手发布《2024快手未成年人保护报告》&#xff08;下文简称《报告》&#xff09;。《报告》显示&#xff0c;快手在2023年持续升级未成年人保护机制&#xff0c;在不断提升平台保障能力和未成年人使用体验的同时&#xff0c;针对未成年人隐私信息保护持续优…

区间预测 | Matlab实现GRU-Attention-KDE核密度估计多置信区间多变量回归区间预测

区间预测 | Matlab实现GRU-Attention-KDE核密度估计多置信区间多变量回归区间预测 目录 区间预测 | Matlab实现GRU-Attention-KDE核密度估计多置信区间多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现GRU-Attention-KDE门控循环单元注意力…

【JS实战02】轮播图

一&#xff1a;HTML页面结构 1 整体外观 2 HTML结构以及CSS样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…