数据结构——二叉树

在这里插入图片描述

本章代码仓库:堆、二叉树链式结构

文章目录

  • 🍭1. 树
    • 🧁1.1 树的概念
    • 🧁1.2 树的结构
  • 🍬2. 二叉树
    • 🍫2.1 二叉树的概念
    • 🍫2.2 特殊的二叉树
    • 🍫2.3 二叉树的性质
    • 🍫2.4 二叉树的存储结构
  • 🍯3. 堆
    • 🍼3.1 堆的实现
      • 🥛接口声明
      • 🥛接口实现
    • 🍼3.2 堆排序
      • 🥛堆排序实现
      • 🥛堆排序时间复杂度
        • ☕向下调整时间复杂度
        • ☕向上调整时间复杂度
        • ☕调堆时间复杂度
    • 🍼3.3 Top-K
  • 🍾4. 链式二叉树结构实现
    • 🍷4.1 手搓链式
    • 🍷4.2 二叉树遍历
      • 🍻前序遍历
      • 🍻中序遍历
      • 🍻后序遍历
      • 🍻层序遍历
    • 🍷4.3 二叉树结点个数
    • 🍷4.4 树的深度
    • 🍷4.5 K层结点个数
    • 🍷4.6 查找值为x的结点
    • 🍷4.6 查找值为x的结点

🍭1. 树

🧁1.1 树的概念

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

在任意一颗非空的树中:

  • 有且具有一个特定的节点称为root节点
  • 除根节点外,其他节点被分成M个不互相交的有限集
  • 每棵子树根节点有且仅有一个前驱节点,可以有0个或者多个后继节点
  • 树是递归定义的

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:B的度为4

叶节点或终端节点:度为0的节点称为叶节点(没有孩子); 如上图:D、J、K、F、G、H、I

非终端节点或分支节点:度不为0的节点(有孩子); 如上图:B、C、E

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点

兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点

树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为4

节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

树的高度或深度:树中节点的最大层次; 如上图:树的高度为4

堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:G、H互为堂兄弟节点

节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙

森林:由m(m>0)棵互不相交的树的集合称为森林;

🧁1.2 树的结构

树的结构如果用线性结构,就会蛮复杂,假设我们知道树的度为5,那我们就可以定义一个指针数组来表示每层的节点

#define N 5
struct TreeNode
{struct TreeNode* children[N];	//指针数组
};

在一般情况下,我们都是不知道树的度,如果采用线性结构,十分不便

struct TreeNode
{SeqList sl;	//存节点指针int val;
}

image-20230803091542771

所以在实际中,一般采用孩子兄弟表示法

typedef int DateType;
struct TreeNode
{struct TreeNode* _firstChild;	//第一个孩子节点struct TreeNode* _pNextBrother;	//兄弟节点DateType _val;	//数据
};

image-20230803094458269

树在数据结构中并不常用,树在实际中的典型应用就是文件系统,一层一层的

将Code文件看作根节点,下面的cppremake-clinux等就能看作是它的孩子节点

然后这些文件里面又包含了其他文件,层层推进

image-20230803094744120

🍬2. 二叉树

🍫2.1 二叉树的概念

二叉树可以看作一个进行了“计划生育”的树

image-20230803095806081

二叉树的特点:

  • 每个节点至多有两颗子树(不存在度大于2的节点)
  • 左子树右子树有顺序,次序不可颠倒(好比人的左右手),即使某个节点只要一棵子树,也要区分是左子树还是右子树

🍫2.2 特殊的二叉树

  1. 满二叉树

    满二叉树就是所有的分支节点都有左右子树,并且所有叶子都在同一层

    假设二叉树的深度为K,则总节点数则为2k-1

    image-20230803100339434

  2. 完全二叉树

    完全二叉树从根节点开始,从左到右依次填充节点,直到最后一层,最后一层的节点可以不满,但节点都尽量靠左排列

    满二叉树定是完全二叉树(正方形也是一种特殊的长方形)

    image-20230803102737902

🍫2.3 二叉树的性质

  1. 一颗非空二叉树第i层至多有**2i-1**个结点

  2. 深度为k的二叉树至多有2k-1 个结点

  3. 对于任何一颗二叉树,如果终端叶子节点为n0,度为2的结点数为n2,则n0 = n2 + 1

  4. 有n个结点的满二叉树的深度h = log2(n+1)

    高度为h的完全二叉树,结点数量范围:[2h-1,2h-1]

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

    • 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
    • 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
    • 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

🍫2.4 二叉树的存储结构

二叉树的存储结构可分为顺序存储和链式存储:

  1. 顺序存储

    顺序存储就是用数组来存储,这一般适用于完全二叉树,因为这样不会造成空间的浪费

    这在物理上是一个数组,但在逻辑上是一颗二叉树

  2. 链式存储

    顾名思义,采用链表来表示这颗二叉树

    typedef int DateType;
    struct TreeNode
    {struct TreeNode* _lChild;	//左孩子struct TreeNode* _rChild;	//右孩子DateType _val;	//数据
    };
    

🍯3. 堆

堆是一颗完全二叉树,堆中的每个节点都满足堆序性质,即在最大堆中,每个节点的值都大于或等于其子节点的值;在最小堆中,每个节点的值都小于或等于其子节点的值。

🍼3.1 堆的实现

下面以大根堆为例:

🥛接口声明

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#define CAPACITY 4typedef int HPDateType;
typedef struct Heap
{HPDateType* val;int _size;int _capacity;
}HP;//初始化
void HeapInit(HP* php);
//插入数据
void HeapPush(HP* php, HPDateType x);
//删除堆顶元素
void HeapPop(HP* php);
//获取堆顶元素
HPDateType HeapTop(HP* php);
//是否有元素
bool HeapEmpty(HP* php);
//获取当前堆的元素数量
int HeapSize(HP* php);
//销毁
void HeapDestroy(HP* php);void AdjustUp(HPDateType* val, int child);
void AdjustDown(HPDateType* val, int sz, int parent);
void Swap(HPDateType* x1, HPDateType* x2);

🥛接口实现

#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include"Heap.h"//初始化
void HeapInit(HP* php)
{assert(php);php->val = (HPDateType*)malloc(sizeof(HPDateType) * CAPACITY);if (php->val == NULL){perror("malloc fail");exit(-1);}php->_size = 0;php->_capacity = CAPACITY;
}
//交换元素
void Swap(HPDateType* x1, HPDateType* x2)
{HPDateType tmp = *x1;*x1 = *x2;*x2 = tmp;
}
//向上调整 前提子树是堆
void AdjustUp(HPDateType* val, int child)
{int parent = (child - 1) / 2;while (child > 0){if (val[child] > val[parent]){Swap(&val[child], &val[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}
//向下调整 前提:子树都是堆
void AdjustDown(HPDateType* val, int sz, int parent)
{//默认左孩子大int child = parent * 2 + 1;//至多叶子结点结束while (child < sz){//不越界 选出更大的孩子if (child+1<sz && val[child] < val[child+1]){child++;}if (val[child] > val[parent]){Swap(&val[child], &val[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
//插入数据
void HeapPush(HP* php, HPDateType x)
{assert(php);if (php->_size == php->_capacity){//扩容HPDateType* tmp = realloc(php->val, sizeof(HPDateType) * php->_capacity * 2);if (tmp == NULL){perror("realloc fail");exit(-1);}php->val = tmp;php->_capacity *= 2;}php->val[php->_size] = x;php->_size++;AdjustUp(php->val, php->_size - 1);
}
//删除堆顶元素
void HeapPop(HP* php)
{assert(php);assert(!HeapEmpty(php));Swap(&php->val[0], &php->val[php->_size - 1]);php->_size--;AdjustDown(php->val, php->_size, 0);
}
//获取堆顶元素
HPDateType HeapTop(HP* php)
{assert(php);return php->val[0];
}
//是否有元素
bool HeapEmpty(HP* php)
{assert(php);return php->_size == 0;
}
//获取当前堆的元素数量
int HeapSize(HP* php)
{assert(php);return php->_size;
}
//销毁
void HeapDestroy(HP* php)
{free(php->val);php->val = NULL;php->_size = 0;php->_capacity = 0;
}

🍼3.2 堆排序

🥛堆排序实现

堆排序分为两个步骤:

  1. 建堆

    排升序:建大堆

    排降序:建小堆

  2. 堆删除的思想进行排序

如果排升序,堆顶元素是最大的,将其与最后一个元素交换,这就是堆的删除操作,但我们不需要将这个数据删除,交换完不管它即可,这样最后一个元素就是最大的,然后再向下调整,再找出最大的元素,以此反复,则可完成升序的排序。

使用堆排序,不需要手搓一个数据结构堆出来,我们只需要建堆和模拟删除操作即可

//排升序 建大堆
void HeapSort(int* pa, int sz)
{//向上调整 建堆 O(N*logN)//for (int i = 0; i < sz; i++)//{//	AdjustUp(pa, i);//}//向下调整 O(N)for (int i = (sz - 1 - 1) / 2; i >= 0; --i){AdjustDown(pa, sz, i);}//向下调整排序 O(N*logN)for (int i = 0; i < sz; i++){Swap(&pa[0], &pa[sz - 1 - i]);AdjustDown(pa, sz - 1 - i, 0);}}

🥛堆排序时间复杂度

建堆操作可以采用向上调整,也可以采用向下调整,但是向下调整的效率是高于向上调整的

image-20230804161542503

☕向下调整时间复杂度

向下调整是从第h-1层开始的

层数结点数向下移动层数
12^0h-1
22^1h-2
32^2h-3
h-12^(h-2)1

调整次数:

T(N) = 2h-1 * 1 + 2h-2 * 2 + 2h-3 * 3 + … + 22 * (h-3) + 21 * (h-2) + 20 * (h-1)

化简得:T(N) = 2h -1 - h

高度为h的满二叉树结点个数为:N = 2h - 1

这样即可推出时间复杂度为:N - log2(N+1)NlogN不在一个量级,则时间复杂度为O(N)

过程示例:

on

☕向上调整时间复杂度

向上调整建堆是从第二层开始调整的

层数结点数向上移动层数
22^11
32^22
h-12^(h-2)h-2
h2^(h-1)h-1

调整次数:

T(N) = 21 * 1 + 22 * 2 + … + 2h-1 * (h-2) + 2h-1 * (h-1)

化简得:T(N) = -2h + 2 + 2h * h - 2h = 2h * h - 2h * 2 + 2

高度为h的满二叉树结点个数为:N = 2h - 1

推出时间复杂度为:(N+1)*log2(N+1) - 2*(N+1) + 2,N和logN不在一个量级,则时间复杂度为O(N*logN)

过程示例:

logN

这里也很好比较:

向上调整建堆时,结点数多的地方,调整次数多;

而向下调整建堆时,结点数多的地方,调整次数少,所以采用向下调整建堆时,效率会高于向上调整

☕调堆时间复杂度

建完堆直接,我们只能保证栈顶元素是最大/最下的,要完成排序,还需要调堆

调堆采用的是删除堆顶元素的逻辑,N个元素,每次调整的时间复杂度为:O(logN),则整个堆排序时间复杂度为:N*log(N)

🍼3.3 Top-K

在现实的世界中,大部分只关注前多少多少,例如:我国排名前十的大学、一个专业学生成绩的前五等等。

这些都是排序,如果数据量较大,数据可能不会一下子就全部加载到内存当中,那我们就可以采用Top-K的思路解决:

用数据集合中的前k个来建堆,然后再用剩余的N-K个元素依次与堆顶元素比较

  • 前k个最大元素,建小堆
  • 前k个最小元素,建大堆

例如要在十万个数据当中找出5个最大/最小的数据,只需要建一个存储5个元素的堆

以前5个最大元素为例,那就是建小堆,那堆顶元素则是最小的,每次只需将堆顶元素和数据进行对比,如果大于堆顶元素,则替换掉堆顶元素,然后进堆,这样就一直保证,堆顶元素是这个堆中最小的元素

场景模拟:

一万个小于一万的随机数,找出前k个最大元素

void Print_TopK(const char* file, int k)
{int* topk = (int*)malloc(sizeof(int) * 5);if (topk == NULL){perror("malloc fail");exit(-1);}FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen fail");exit(-1);}//读取前k个数据for (int i = 0; i < k; i++){fscanf(fout, "%d", &topk[i]);}//建小堆for (int i = (k - 2) / 2; i >= 0; i--){AdjustDown(topk, k, i);}//将剩余元素与堆顶元素比较,大于堆顶元素则替换int val = 0;int ret = fscanf(fout, "%d", &val);while (ret != EOF){if (val > topk[0]){topk[0] = val;AdjustDown(topk, k, 0);}ret = fscanf(fout, "%d", &val);}for (int i = 0; i < k; i++){printf("%d ", topk[i]);}printf("\n");free(topk);topk = NULL;fclose(fout);
}
//造数据
void CreateDate()
{int n = 10000;srand((int)time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen fail");exit(-1);}for (size_t i = 0; i < n; i++){int x = rand() % 10000;fprintf(fin, "%d\n", x);}fclose(fin);
}

🍾4. 链式二叉树结构实现

🍷4.1 手搓链式

堆属于一种线性二叉树,对于链式二叉树,本次采用手搓的方式创建

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;
//申请结点
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");exit(-1);}node->data = x;node->left = NULL;node->right = NULL;return node;
}
//造树(手搓)
BTNode* CreatTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);BTNode* node8 = BuyNode(8);node1->left = node2;node1->right = node4;;node2->left = node3;node3->right = node7;node7->left = node8;node4->left = node5;node4->right = node6;return node1;
}

🍷4.2 二叉树遍历

🍻前序遍历

前序遍历也叫做先序遍历,访问顺序:根 -> 左子树 -> 右子树

//前序遍历:根 左子树 右子树
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}

🍻中序遍历

中序遍历访问顺序:左子树 -> 根 -> 右子树

//中序遍历:左子树 根 右子树
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

🍻后序遍历

后序遍历访问顺序:左子树 -> 右子树 -> 根

//后序遍历:左子树 右子树 根
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

🍻层序遍历

层序遍历与前三种不一样,层序遍历采用队列的方式实现:

首先根节点进队列,当遍历根节点之后,根节点出队列的同时把左右孩子带进去

然后再两个孩子依次出队,同时带入孩子的孩子,依次反复

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);if (front->right)QueuePush(&q, front->right);}QueueDestroy(&q);
}

🍷4.3 二叉树结点个数

统计左子树和右子树的结点,然后再加上自己的一个

//树的结点树
int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

🍷4.4 树的深度

这里每次都要记录每次统计的结点个数,不然每次每层都得重新统计(如:注释代码块)

//树的深度
int TreeHeight(BTNode* root)
{if (root == NULL){return 0; }//记录深度int left = TreeHeight(root->left)+1;int right = TreeHeight(root->right)+1;printf("%d %d\n", left, right);return left>right?left:right;//return root==NULL?0: TreeHeight(root->left) > TreeHeight(root->right) ? TreeHeight(root->left)+1 : TreeHeight(root->right)+1;
}

🍷4.5 K层结点个数

//K层结点个数
int TreeKLevel(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;int leftChild = TreeKLevel(root->left, k - 1);int rightChild = TreeKLevel(root->right, k - 1);return leftChild + rightChild;}

🍷4.6 查找值为x的结点

//查找值为x的结点
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;//记录结点BTNode* leftNode = TreeFind(root->left, x);BTNode* rightNode = TreeFind(root->right, x);if (leftNode)return leftNode;else if (rightNode)return rightNode;return NULL;
}

root->left) > TreeHeight(root->right) ? TreeHeight(root->left)+1 : TreeHeight(root->right)+1;
}


## 4.5 K层结点个数```c
//K层结点个数
int TreeKLevel(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;int leftChild = TreeKLevel(root->left, k - 1);int rightChild = TreeKLevel(root->right, k - 1);return leftChild + rightChild;}

🍷4.6 查找值为x的结点

//查找值为x的结点
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;//记录结点BTNode* leftNode = TreeFind(root->left, x);BTNode* rightNode = TreeFind(root->right, x);if (leftNode)return leftNode;else if (rightNode)return rightNode;return NULL;
}

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

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

相关文章

Julia 日期和时间

Julia 通过 Dates 模块提供了以下三个函数来处理日期和时间&#xff1a; Date&#xff1a;表示日期&#xff0c;精确到日&#xff0c;只显示日期。DateTime&#xff1a;表示日期和时间&#xff0c;精确到毫秒。DateTime&#xff1a;表示日时间&#xff0c;精确到纳秒&#xff…

【数据库】将excel数据导入mysql数据库

环境&#xff1a;Windows10 mysql8以上 将你要导入的excel表另存为txt格式 打开txt格式文件&#xff0c;删除表头行并另存为并更改编码方式&#xff08;由于与数据库的编码不同&#xff0c;会导致导入报错&#xff09; 通过命令行登录数据库 winr cmd进入 进入装mysql的目录位…

基于BIM+AI的建筑能源优化模型【神经网络】

推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景。 AEC&#xff08;建筑、工程、施工&#xff09;行业的BIM 技术&#xff0c;允许在实际施工开始之前虚拟地建造建筑物&#xff1b; 这带来了许多有形和无形的好处&#xff1a;减少成本超支、更有效的协调、增强决策权等等。…

Windows批处理基础

一、【echo】显示文本内容 echo | Microsoft Learnhttps://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/echo 显示消息或者打开或关闭命令回显功能。 如果不结合任何参数使用&#xff0c;echo 会显示当前回显设置。 1.1、echo显示文本常用命…

AIGC大模型ChatGLM2-6B:国产版chatgpt本地部署及体验

1 ChatGLM2-6B介绍 ChatGLM是清华技术成果转化的公司智谱AI研发的支持中英双语的对话机器人。ChatGLM基于GLM130B千亿基础模型训练&#xff0c;它具备多领域知识、代码能力、常识推理及运用能力&#xff1b;支持与用户通过自然语言对话进行交互&#xff0c;处理多种自然语言任务…

【SQL】-【计算两个varchar类型的timestamp的毫秒差】

背景 TRANSTAMP3、TRANSTAMP2在Oracle数据库中的类型为varchar&#xff0c;但实际保存的值是时间戳timestamp类型&#xff0c;现在要计算二者的毫秒差 Oracle或MySQL extract(second from (to_timestamp(TRANSTAMP3,yyyy-mm-dd hh24:mi:ss.ff) - to_timestamp(TRANSTAMP2,yyy…

运放电路之比较器的分析笔记

一、比较器 比较器分为同相比较器和反相比较器。 反相比较器电路如下&#xff1a; V11为固定值&#xff0c;这里设定的是2.5V&#xff0c;接到了运放的输入正&#xff08;V&#xff09;&#xff1b; V10为输入值&#xff0c;值可变&#xff0c;接到了运放的输入负&#xff08;V…

CADintosh X for mac CAD绘图软件2D CAD 程序 兼容 M1

CADintosh X for Mac是一个功能强大的2D CAD绘图程序&#xff0c;专为Mac用户设计。它由Lemke Software开发&#xff0c;提供了一套丰富的工具和功能&#xff0c;使用户能够轻松创建高质量的技术图纸&#xff0c;平面图和设计。 CADintosh X for Mac具有直观的用户界面&#x…

【雕爷学编程】MicroPython动手做(27)——物联网之掌控板小程序2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

物联网|按键实验---学习I/O的输入及中断的编程|函数说明的格式|如何使用CMSIS的延时|读取通过外部中断实现按键捕获代码的实现及分析-学习笔记(14)

文章目录 通过外部中断实现按键捕获代码的实现及分析Tip1:函数说明的格式Tip2:如何使用CMSIS的延时GetTick函数原型stm32f407_intr_handle.c解析中断处理函数&#xff1a;void EXTI4_IRQHandler 调试流程软件模拟调试 两种代码的比较课后作业: 通过外部中断实现按键捕获代码的实…

装修小程序,开启装修公司智能化服务的新时代

随着数字化时代的来临&#xff0c;装修小程序成为提升服务质量和效率的关键工具。装修小程序旨在为装修公司提供数字化赋能、提高客户满意度的智慧装修平台。通过装修小程序&#xff0c;装修公司能够与客户进行在线沟通、展示设计方案、提高服务满意度等操作。 装修小程序的好处…

8月5日上课内容 nginx的优化和防盗链

全部都是面试题 nginx的优化和防盗链 重点就是优化&#xff1a; 每一个点都是面试题&#xff0c;非常重要&#xff0c;都是面试题 1、隐藏版本号&#xff08;重点&#xff0c;一定要会&#xff09; 备份 cp nginx.conf nginx.conf.bak.2023.0805 方法一&#xff1a;修改配…

HTML 是什么?它的全称是什么?

聚沙成塔每天进步一点点 专栏简介HTML是什么&#xff1f;HTML的全称是什么&#xff1f;写在最后 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对We…

【大模型】开源且可商用的大模型通义千问-7B(Qwen-7B)来了

【大模型】开源且可商用的大模型通义千问-7B&#xff08;Qwen-7B&#xff09;来了 新闻通义千问 - 7B 介绍评测表现快速使用环境要求安装相关的依赖库推荐安装flash-attention来提高你的运行效率以及降低显存占用使用 Transformers 运行模型使用 ModelScope 运行模型 量化长文本…

2配置篇:基础功能配置

前言 在上一章节中,我们学习了 NestJS CLI 的用法,得到了一套基础的项目工程。最开始做项目对比的时候也提到过,NestJS 作为一款自定义程度较高的框架,CLI 直接提供的基础功能虽然并不完善,但同时也为开发者提供了非常多的内置或配套的功能例如高速缓存、日志拦截、过滤器…

阿里云平台WoSignSSL证书应用案例

沃通CA与阿里云达成合作并在阿里云平台上线WoSign品牌SSL证书。自上线以来&#xff0c;WoSignSSL证书成为阿里云“数字证书管理服务”热销证书产品&#xff0c;获得阿里云平台客户认可&#xff0c;助力阿里云平台政府、金融、教育、供应链、游戏等各类行业客户实现网站系统数据…

macOS下Django环境搭建

1. macOS升级pip /Library/Developer/CommandLineTools/usr/bin/python3 -m pip install --upgrade pip 2. 卸载Python3.9.5版本 $ sudo rm -rf /usr/local/bin/python3 $ sudo rm -rf /usr/local/bin/pip3 $ sudo rm -rf /Library/Frameworks/Python.framework 3. 安装P…

IO多路转接之select

IO多路转接之select 1. 初识select 系统提供select函数来实现多路复用输入/输出模型。 select系统调用是用来让我们的程序监视多个文件描述符的状态变化的&#xff1b;程序会停在select这里等待&#xff0c;直到被监视的文件描述符有一个或多个发生了状态改变&#xff1b; …

android app控制ros机器人四(调整界面布局)

半吊子改安卓&#xff0c;记录页面布局调整&#xff1a; 在ros-mobile基础上顶端增加一行&#xff0c;用于显示app名称和logo图像&#xff1b;修改标签页。 添加文字简单&#xff0c;但是替换图标长知识了&#xff0c;开始只是简单的把mipmap各个文件夹下的图片进行替换&…

XML 学习笔记 7:XSD

本文章内容参考自&#xff1a; W3school XSD 教程 Extensible Markup Language (XML) 1.0 (Second Edition) XML Schema 2001 XML Schema Part 2: Datatypes Second Edition 文章目录 1、XSD 是什么2、XSD 内置数据类型 - built-in datatypes2.1、基本数据类型 19 种2.1.1、基本…