《数据结构》学习系列——树(上)

系列文章目录

目录

  • 树的基本概念
  • 树的定义
  • 树的特点
  • 树的相关术语
  • 层数
  • 高度
  • 路径
  • 二叉树
  • 定义
  • 特点
  • 定理
  • 满二叉树
  • 定义
  • 特点
  • 完全二叉树
  • 定义
  • 特点
  • 二叉树的存储结构
  • 顺序存储
  • 结点结构
  • 优点缺点 
  • 链式存储 
  • 结点结构
  • 三叉链表表示法
  • 算法
  • 搜索结点的父结点
  • 搜索符合数据域条件的结点
  • 删除给定结点及其左右子树
  •  二叉树遍历
  • 先根遍历

树的基本概念

  • 树结构在客观世界中大量存在,例如家谱、行政组织机构都可用树结构形象地表示
  • 树在计算机领域中也有着广泛的应用,例如在编译程序中,用树来表示源程序的语法结构;在数据库系统中,可用树来组织信息;在分析算法的行为时,可用树来描述其执行过程

 

树的定义

  •  (递归定义)定义:一个(或树形)就是一个有限非空的结点集合T,其中:

    • 有一个特别标出的被称为该树(或树形)之root(T)的结点

    • 其余结点 (根除外)被分成m≥0个不相交的集合T1,T2,...,Tm,且T1,T2,...,Tm又都是树(或树形)。树(或树形)T1,T2,...,Tm被称作root(T)的子树(或子树形

  • (非递归定义)定义:树是包含n(n≥1)个结点且满足如下条件的有限集合

    • 存在一个唯一的结点v0,它没有前驱结点,称为树的根(或根结点)

    • 任何非根结点都有且仅有前驱节点,称为该节点的父结点

    • 任何结点都可能有多个(≤n-1)后继结点,称之为该结点的子结点;若某结点没有后继结点,则称之为叶结点

    • 任一非根结点vk都有且仅有一条从v0到该结点序列(或路径)v0 → v1 → ...→ vk,其中vi是vi-1(1≤i≤k)的子结点

  • 其他定义:t是有一个有限元素的集合,其中一个元素为根,余下的元素(如果有的话)组成t的子树(subtree)。层次中最高层的元素为根,其下一级的元素是余下元素所构成的子树的根

例:

下图为一颗由根结点A发出的树,其中

  • A有三个子结点B、C和D(换句话说A是B、C和D的父结点)
  • B有一个子结点E
  • E有一个子结点F
  • C有两个子结点G和H;D有一个子结点I;F、G、H、I是叶子结点,因为它们没有子结点

  •  若断掉一个结点与其父结点的连接,把该结点和它的子孙们单独拿出,就是一棵以该结点为根结点的树,称之为“子树”。


树的特点

  •  树中任一结点都可以有零个或多个直接后继(即子结点),但至多只能有一个直接前驱(即父结点)
  • 树中只有根结点无前驱,它是始结点;叶结点无后继,它们是终结点
  • 树中某些结点之间具有父子关系或者祖先、子孙关系,祖先、子孙关系是对父子关系的扩展,一些结点之间,如兄弟结点(同一个父亲的诸子结点被称为兄弟结点)之间就没有这种关系

  • 有一个树根
  • 没有分枝相交
  • 树有层次

树的相关术语

  • 结点的度
    • 一个结点的子结点的数目,称为该结点的或者次数。一棵树的度为maxi=1,...,nD(i),其中n为树中结点总数,i指树中的第i个结点,D(i)表示结点i的度
  • 树的度
    • 树中各结点的最大值
  • 示例:
    • B有一个子结点E,度为1;A有三个子结点B、C和D(换言之,A是B、C和D的父结
      点),度为3,这棵树的度也为3

层数

  • 结点的层数:树形T中结点的层数递归定义如下
    • root(T)层数为0
    • 其余结点的层数为其前驱结点的层数加一

高度

  • 树的高度为maxi=1,...,nNL(i),其中n为树中结点总数,i指数中第i个结点,NL(i)之值为结点i的层数

  • 树的高度是指树中结点的最大层数

路径

  • 树形中结点间的连线被称为边。若树形T中存在结点序列vm→vm+1→...→vm+k,1≤k≤T的最大层数满足vi+1是vi;(m≤i≤m+k-1)的子结点,则称此结点序列为vm到vm+k的路径,该路径所经历的边数k被称为路度径长
  • 子孙结点、祖宗结点
    • 一棵树中若存在结点vm到vn的路径,则称vn为vm的子孙结点,vm为vn的祖宗结点
    • 一个结点到它某个子孙结点有且仅有条路径

二叉树

定义

二叉树(形)是结点的有限集合,它或者是空集,或者由一个根及两个不相交的,称为这个根的左、右子树形的二叉树组成

特点

  • 二叉树每个结点最多有两个子结点
  • 二叉树的子树有左右之分

  • 树与二叉树的主要区别
    • 二叉树每个结点最多有两个子结点,树则没有限制
    • 二叉树中结点的子树分成左子树和右子树,即使某结点只有一颗子树,也要指明该子树是左子树还是右子树,就是说二叉树是有序的
  • 含有三个结点的不同二叉树


定理

  • 二叉树中层数为i的结点至多有2^i个,i≥0
    • 证明:
      • 当i=0时,仅有一个根结点,其层数为0,因此i=0时引理成立
      • 假定当i=j(j≥0)时,引理成立,即第j层上至多有2个结点
      • 对于二叉树的任意结点,其子结点个数最大为2,故第j+1层上至多有2*
        2^j=2^(j+1)个结点,因此当i=j+1时,引理成立
      • 由数学归纳法可知,对于所有的i≥0,均有“第i层上至多有2^i个结点,证毕。

  • 高度为k(k≥0)的二叉树中至少有k+1个结点,含有k(k≥1)个结点的二叉树高度至多为k-1

例:

  •  高度为k的二叉树中至多有2^(k+1)-1(k≧0)个结点
    • 证明
      • 第0层上至多有2^0个结点
      • 第1层上至多有2^1个结点
      • 第2层上至多有2^2个结点
      • ......
      • 第k层上至多有2^k个结点
      • 因此,高度为k的二叉树中至多有2^0+2^1+...+2^k=2^(k+1)-1个结点

  • 设T是由m个结点构成的二叉树,其中度为2的结点个数为n2,度为0(叶结点)的个数为n0,则n0=n2+1
    • 证明:
      • 若度为1的结点个数为n1,总结点个数为n,则n=n0+n1+n2
      • 所有度为2结点的子结点总数的结点总数为2*n2,同理度为1结点的子结点总数为1*n1,度为0结点的子结点总数为0,则n=2*n2+n1+1(加上树的根)
      • n0+n1+n2 = 2*n2+n1+1
      • n0=n2+1

满二叉树

定义

一棵非空高度为k(k≥0)的满二叉树,是有2^(k+1)-1个结点的二叉树

特点

  • 高度为k(非空)二叉树至多有2^(k+1)-1个结点
  • 满二叉树的特点是:
    • 叶结点都在第k层上
    • 每个分支结点都有两个子结点
    • 叶结点的个数等于非叶结点个数加1
    • 除叶结点外,其他结点的度均为2

完全二叉树

定义

  • 一棵有n个结点、高为k的二叉树T,一棵高为k的满二叉树T*,用正整数按层次顺序分别编号T和T*的所有结点,如果T之所有结点恰好对应于T*的前n个结点,则称T为完全二叉树
  • 层次顺序:按从上至下,即从第0至第k层,每层由左到右的次序

特点

  • 具有n个结点高度为k的完全二叉树具有如下特点

    • 树中只有最下面两层结点的度可以小于2 
    • 树中最下面一层的结点都集中在该层最左边的若干位置上(满二叉树意义上)
    • 树中叶结点只能在层数最大的两层上出现,即存在一个非负整数k使得树中每个叶结点或在第k层或第k+1层上
    • 对树中所有结点,按层次顺序,用自然数从1开始编号,仅仅编号最大的非叶结点可以没有右孩子,其余非叶结点都有两个孩子结点
  • 若将一棵具有n个结点的完全二叉树按层次次序从1开始编号,则对编号为i(1≤i≤n)的结点有
    • 若i≠1,则编号为i的结点的父节点的编号为i/2
    • 若2i≤n,则编号为i的结点的左孩子的编号为2i,否则i无左孩子
    • 若2i+1≤n,则编号为i的结点的右孩子的编号为2i+1,否则i无右孩子
  • 仅仅编号最大的非叶结点可无右孩子,但必须有左孩子,其余非叶结点都有两个孩子结点

  • 用归纳法证明
  • 若i=1,如果n≥2,则左孩子的编号显然为2
  • 假定对所有j(1≤j≤i,2i≤n),有j的左孩子编号为2j
  • 那么对于结点i+1,证明其左孩子编号为2(i+1)
  • 如果2(i+1)≤n,则由层次次序得知,i+1的左孩子之前的两个结点就是i的左孩子和右孩子,因为i的左孩子编号为2i(归纳假设),故i的右孩子编号为2i+1,从而i+1的左孩子编号为2i+2=2(i+1)
  • 证毕

  • 具有n个结点的完全二叉树的高度是\log_2n
    • 设二叉树高度为k,由定义知,完全二叉树的结点个数介于高度为k-1和高度为k的满二叉树的结点数之间,即有:2^k-1<n≤2^(k+1)-1
    • 从而有2^k≤n<2^(k+1),即k≤log2n<k+1,因为k为整数,故有k=log2n

二叉树的存储结构

要存储一棵二叉树,需存储其所有结点的数据信息,以及其左、右孩子的地址

通常有两种存储方式:

  • 顺序存储
  • 链接存储

顺序存储

指将二叉树的所有结点按照层次顺序存放在一块地址连续的存储空间中,同时要反映二叉树中的结点间的逻辑顺序

结点结构

  • 完全二叉树顺序存储方式:按照层次顺序
    • 结点编号恰好反映了结点间的逻辑关系
  • 示例:一维数组A存储二叉树
    • A[1]存储二叉树的根结点,A[i]存储二叉树中编号为i的结点,并且结点A[i]的左孩子(若存在)存放在A[2i]处,而A[i]的右孩子(若存在)存放在A[2i+1]处

优点缺点 

  • 顺序存储的完全二叉树
    • 优点:简单、节省空间
    • 只存储结点信息域、未存储其左孩子和右孩子。通过计算可找到它的左孩子、右孩子和父节点,寻找子孙结点和祖先结点也非常方便 
  • 顺序存储存储非完全二叉树
    • 编号不能与结点一一对应
    • 解决方案:先加入若干虚结点将其转化成一棵“完全二叉树”,然后再将对原来的结点和虚结点统一编号,最后完成顺序存储。但这增加了用于存储虚结点的空间


链式存储 

二叉树各结点随机存放在内存空间中,结点之间的关系用指针标识

  • 有一个指向根节点的指针,称为根指针root,二叉树通过根指针来访问,二叉树为空,即root = NULL
  • 若某结点左孩子或右孩子不存在,则对应指针为NULL
  • 包含n个结点的二叉树用链式存储表示,需要2n个指针域,其中n-1个用来表示结点的左右孩子,其余n+1个指针域为空

结点结构

二叉树结点应包含三个域:数据域data指针域left(左指针)和指针域right(右指针),其中左、右指针分别指向该结点的左、右子树的根结点

三叉链表表示法

结点包括三个指针域,parent域中的指针指向其父结点


算法

搜索结点的父结点

#include <iostream>using namespace std;class Tree
{protected:int data;Tree *left;Tree *right;public:Tree(int d)  // 构造函数,创建树的节点{data = d;left = NULL;right = NULL;}Tree* Left()  // 返回左子树{return left;}Tree* Right() // 返回右子树{return right;}int Data()   // 返回节点数据{return data;}void setLeft(Tree *l) // 设置左子树{left = l;}void setRight(Tree *r) // 设置右子树{right = r;}
};// Father 函数用于查找某个节点的父节点
void Father(Tree* t, Tree* p, Tree*& q)  // 通过引用传递 q
{if (t == NULL || t == p){q = NULL;return;}if (t->Left() == p || t->Right() == p) // 找到父节点{q = t;return;}Father(t->Left(), p, q);  // 递归搜索左子树if (q == NULL){Father(t->Right(), p, q);  // 递归搜索右子树}return; 
}int main()
{// 创建树节点Tree *t = new Tree(1);t->setLeft(new Tree(2));t->setRight(new Tree(3));t->Left()->setLeft(new Tree(4));t->Left()->setRight(new Tree(5));t->Right()->setLeft(new Tree(6));t->Right()->setRight(new Tree(7));// 查找节点 t->Left()->Left()(也就是节点 4)的父节点Tree *p = t->Left()->Left();Tree *q = NULL;Father(t, p, q);// 输出父节点的数据,如果父节点存在if (q != NULL){cout << q->Data() << endl;}else{cout << "NULL" << endl;}return 0;
}

搜索符合数据域条件的结点

// Find 函数用于查找某个节点
Tree* Find(Tree* t,int data,Tree*& q)  // 通过引用传递 q
{if(t==NULL){q=NULL;return q;}if(t->Data()==data){q=t;return q;}q=Find(t->Left(),data,q);if(q==NULL){q=Find(t->Right(),data,q);}return q;
}int main()
{// 创建树节点Tree *t = new Tree(1);t->setLeft(new Tree(2));t->setRight(new Tree(3));t->Left()->setLeft(new Tree(4));t->Left()->setRight(new Tree(5));t->Right()->setLeft(new Tree(6));t->Right()->setRight(new Tree(7));// 查找节点 t->Left()->Left()(也就是节点 4)值为4Tree *p = t->Left()->Left();Tree *q = NULL;q = Find(t,p->Data(),q);// 输出找到结点的值if (q != NULL){cout << q->Data() << endl;}else{cout << "NULL" << endl;}return 0;
}

删除给定结点及其左右子树

// 递归删除给定节点及其左右子树
void Del(Tree* root)
{if (root == NULL)return;// 递归删除左子树和右子树Del(root->Left());Del(root->Right());delete root;
}// 查找并删除树中的某个节点及其左右子树
void DeleteNode(Tree* root, Tree* target)
{if (target == NULL) return;if (target == root){Del(root);root = NULL;return;}Tree* parent = NULL;// 查找目标节点的父节点Father(root, target, parent);if (parent->Left() == target) parent->setLeft(NULL);if (parent->Right() == target) parent->setRight(NULL);Del(target);target = NULL;return;
}int main()
{// 创建二叉树Tree* t = new Tree(10);t->setLeft(new Tree(5));t->setRight(new Tree(15));t->Left()->setLeft(new Tree(3));t->Left()->setRight(new Tree(7));t->Right()->setLeft(new Tree(12));t->Right()->setRight(new Tree(18));// 目标节点为 t->Left()(节点 5),我们要删除它及其左右子树Tree* target = t->Left();DeleteNode(t, target);return 0;
}

 二叉树遍历

二叉树为空则什么都不做;否则遍历分三步进行

例子:

  •  先根遍历得到的结点序列:x+AB+x-CDEF
  • 中根遍历得到的结点序列:A+BxC-DxE+F
  • 后根遍历得到的结点序列:AB+CD-ExF+X

  • 对于给定的一棵二叉树,可给出在先根序、中根序和后根序下的唯一结点排列
  • 三种遍历序列的叶结点间的相对次序是相同的,叶结点都是按着从左到右的次序排列,区别仅在于非叶结点间的次序以及非叶结点和叶结点间的次序有所不同

先根遍历

  • 若二叉树为空,则空操作
  • 否则
    • 访问根节点
    • 先根遍历左子树
    • 先根遍历右子树

Preorder(t)

{

        if t !=NULL;

        {

                print(data(t));

                Perorder(Left(t));

                Perorder(Right(t));

        }
}

中根遍历

  • 若二叉树为空,则空操作
  • 否则
    • 中根访问左子树
    • 访问根节点
    • 中根遍历右子树

Indorder(t)

{

        if t !=NULL;

        {

                Indorder(Left(t));

                print(data(t));

                Indorder(Right(t));

        }
}

后根遍历

  • 若二叉树为空,则空操作
  • 否则
    • 后根访问左子树
    • 后根遍历右子树
    • 访问根节点

Postorder(t)

{

        if t !=NULL;

        {

                Postorder(Left(t));

                print(data(t));

                Postorder(Right(t));

        }
}

递归遍历代码 

#include <iostream>using namespace std;class Tree
{protected:int data;Tree *left;Tree *right;public:Tree(int d)  // 构造函数,创建树节点{data = d;left = NULL;right = NULL;}Tree* Left()  // 返回左子树{return left;}Tree* Right() // 返回右子树{return right;}int Data()   // 返回数据{return data;}void setLeft(Tree *l) // 设置左子树{left = l;}void setRight(Tree *r) // 设置右子树{right = r;}
};// 前序遍历(根 -> 左 -> 右)
void preorderTraversal(Tree *node)
{if (node == NULL)return;cout << node->Data() << " ";  // 输出根节点数据preorderTraversal(node->Left());  // 递归遍历左子树preorderTraversal(node->Right()); // 递归遍历右子树
}// 中序遍历(左 -> 根 -> 右)
void inorderTraversal(Tree *node)
{if (node == NULL)return;inorderTraversal(node->Left());  // 递归遍历左子树cout << node->Data() << " ";  // 输出根节点数据inorderTraversal(node->Right()); // 递归遍历右子树
}// 后序遍历(左 -> 右 -> 根)
void postorderTraversal(Tree *node)
{if (node == NULL)return;postorderTraversal(node->Left());  // 递归遍历左子树postorderTraversal(node->Right()); // 递归遍历右子树cout << node->Data() << " ";  // 输出根节点数据
}int main()
{// 创建一个简单的树//       1//      / \//     2   3//    / \//   4   5Tree *root = new Tree(1);Tree *node2 = new Tree(2);Tree *node3 = new Tree(3);Tree *node4 = new Tree(4);Tree *node5 = new Tree(5);root->setLeft(node2);root->setRight(node3);node2->setLeft(node4);node2->setRight(node5);// 递归前序遍历cout << "Preorder Traversal: ";preorderTraversal(root);cout << endl;// 递归中序遍历cout << "Inorder Traversal: ";inorderTraversal(root);cout << endl;// 递归后序遍历cout << "Postorder Traversal: ";postorderTraversal(root);cout << endl;return 0;
}

堆栈遍历代码

以中序遍历为例子

NIO1.[初始化]

        CREATE(S)

        p = t

NIO2.[入栈]

        WHILE p != NULL

                S = p

                p = Left(p)

NIO3.[栈为空?]

        IF S为空 RETURN

        ELSE p = S

NIO4.[访问p,更新p]

        PRINR(Data(p))

        p = Right(p)

NIO5.[返回]

        GOTO NIO2.

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

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

相关文章

手机IMEI号为空

1、问题描述 售后反馈&#xff0c;几台机器出现无IMEI问题&#xff0c;需要分析确认 2、分析过程 抓取开机日志&#xff0c;发现radio log中&#xff0c;RILD一直处于重启状态。 Line 1589: 12-19 14:44:42.836240 3156 3156 I IMS_RILA: getMtkRadioProxy service d…

javaweb-请求和响应

1.http协议 1.1请求 1.2.响应 常见响应状态码&#xff1a; 状态码大全&#xff1a;https://cloud.tencent.com/developer/chapter/13553 常见的响应头&#xff1a; 2.请求和响应 2.1.请求 2.1.1postman 作用&#xff1a;常用于接口测试 使用&#xff1a;官网安装-->注册…

Java 根据字符生成背景透明的图片

上代码 package com.example.demotest.controller;/*** Author shaolin* Date 2024-10-08 10:11**/import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.WritableRaster; impor…

Github 2024-10-08 Python开源项目日报Top10

根据Github Trendings的统计,今日(2024-10-08统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10JavaScript项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次关注人数…

深入了解音频剪辑在线工具的特色与优势

在数字时代&#xff0c;音频内容已成为连接人心的重要桥梁。如果你也有同样的兴趣爱好&#xff0c;那不妨看看我今天要介绍的音频剪辑在线相关的工具们吧。 1.福昕音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 福昕音频剪辑工具&#xff0c;专为音乐…

【含开题报告+文档+PPT+源码】基于SSM框架的民宿酒店预定系统的设计与实现

开题报告 随着人们旅游需求的增加&#xff0c;民宿行业呈现出快速发展的趋势。传统的住宿方式逐渐无法满足人们对个性化、舒适、便捷的需求&#xff0c;而民宿作为一种新型的住宿选择&#xff0c;逐渐受到人们的青睐。民宿的特点是具有独特的风格、便捷的地理位置、相对亲近的…

Spring Aop实现日志收集和重复属性赋值

Spring Aop实现日志收集和重复属性赋值 简介 ​ AOP(Aspect-Oriented Programming)&#xff0c;即面向切面编程&#xff0c;用人话说就是把公共的逻辑抽出来&#xff0c;让开发者可以更专注于业务逻辑开发。 ​ 和IOC一样&#xff0c;AOP也指的是一种思想。AOP思想是OOP&…

电商行业应用 WMS 的成功案例

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。一站式数智工厂解决方案服务商】 京东&#xff1a;作为国内知名的电商巨头&#xff0c;京东拥有庞大的仓储体系。通过应用先进的 WMS 系统&#xff0c;实现了高效的库存管理、精准的订单拣选和快速…

Java中HashMap和HashTable的区别

HashTable&#xff1a; HashMap&#xff1a; HashMap和Hashtable将键和值对存储在哈希表中。使用 Hashtable 或 HashMap 时&#xff0c;我们指定一个用作键的对象以及要链接到该键的值。然后对键进行哈希处理&#xff0c;并将生成的哈希码用作表中存储值的索引。现在让我们借助…

基于java SpringBoot和Vue校园求职招聘系统设计

摘要 随着信息技术的迅猛发展&#xff0c;基于Java Spring Boot和Vue的校园求职招聘系统设计成为了解决高校就业难问题的重要手段。本文旨在探讨如何利用Java Spring Boot框架构建后端服务&#xff0c;以及使用Vue.js进行前端开发&#xff0c;从而创建一个高效、易用且功能全面…

掌控板micropython编程实现OLED中bmp图像

掌控板micropython编程实现OLED中bmp图像 1.设置输出格式 打开PCtoLCD2002软件&#xff0c;点击“选项”菜单&#xff0c;设置选项如图1所示。其中&#xff0c;点阵格式&#xff1a;阴码&#xff1b;取模走向&#xff1a;顺向&#xff1b;输出数制&#xff1a;十六进制。设置…

六、索引的数据结构

文章目录 1. 为什么使用索引2. 索引及其优缺点2.1 索引概述2.2 优点2.3 缺点3. InnoDB中索引的推演3.1 索引之前的查找3.1.1 在一个页中的查找3.1.2 在很多页中查找3.2 设计索引3.2.1 一个简单的索引设计方案3.2.2 InnoDB中的索引方案3.3 常见索引概念3.3.1 聚簇索引3.3.2 二级…

【Linux】线程与线程安全知识总结

向外张望的人在做梦&#xff0c; 向内审视的人才是清醒的。 --- 荣格 --- 我最近复习了线程安全这部分知识&#xff0c;将不明白的问题总结出来&#xff0c;并通过AI进行问答帮助我进行学习巩固。本人能力有限 &#xff0c;可能有些内容不准确&#xff0c;望各位大佬海涵&am…

_c++11

嗨喽大家好呀&#xff0c;今天阿鑫给大家带来的是c进阶——c11的内容&#xff0c;好久不见啦&#xff0c;下面让我们进入本节博客的内容吧&#xff01; _c11 统一的列表初始化右值引用可变模板参数(了解&#xff0c;不常接触)lambda表达式function和bind包装器 1. 统一的列表…

气膜体育馆:解决场地困境的新选择—轻空间

北京市近日出台了关于规范和加强新建充气膜体育建筑的指导意见&#xff0c;旨在有效解决区域体育配套不足的问题。这一政策的出台&#xff0c;不仅为全民健身打造了新的载体&#xff0c;也为校园体育设施建设指明了方向。 满足日益增长的健身需求 随着人们健康意识的提升&#…

Skyeye 云智能制造 v3.14.8 发布,ERP 商城 + AI

Skyeye 云智能制造&#xff0c;采用 Springboot winUI 的低代码平台、移动端采用 UNI-APP。包含 30 多个应用模块、50 多种电子流程&#xff0c;CRM、PM、ERP、MES、ADM、EHR、笔记、知识库、项目、门店、商城、财务、多班次考勤、薪资、招聘、云售后、论坛、公告、问卷、报表…

openmmlab使用系列(二):图像超分辨率重构

文章目录 前言一、图像超分辨率重构简介二、mmmagic实现图像超分 前言 超分辨率重构技术&#xff0c;作为计算机视觉领域的一项重要研究课题&#xff0c;近年来受到了广泛关注。随着科技的飞速发展&#xff0c;人们对图像质量的要求越来越高&#xff0c;尤其是在智能手机、监控…

SpringBoot3实战:实现接口签名验证

有时候我们要把自己的服务暴露给第三方去调用&#xff0c;为了防止接口不被授权访问&#xff0c;我们一般采用接口签名的方式去保护接口。 接下来松哥和大家聊一聊这个话题。 一 场景分析 什么时候需要接口签名&#xff1f; 接口签名是一种重要的安全机制&#xff0c;用于确…

JAVA基础: synchronized 和 lock的区别、synchronized锁机制与升级

1 synchronized 和 lock的区别 synchronized是一个关键字&#xff0c; lock是一个接口&#xff0c;实际使用的是实现类 synchronized通过触发的是系统级别的锁机制&#xff0c; lock是API级别的锁机制 synchronized自动获得锁&#xff0c;自动释放锁。 lock需要通过方法获得锁…