当前位置: 首页 > news >正文

C++:STL - set map

C++:STL - set & map

    • 关联式容器
    • pair
    • set
      • 模板参数
      • typedef的类型
      • 构造函数
      • 迭代器
      • 常规接口
      • 特殊接口
    • multiset
    • map
      • 模板参数
      • typedef的类型
      • 常规接口
      • 特殊接口
    • multimap


关联式容器

关联式容器是C++标准库提供的一种数据结构,用于存储操作键值对(key-value)。每个键值对都包含一个键和一个关联的值。关联式容器提供了通过键快速查找和访问值的功能。

C++98标准库提供了四种树形结构的关联式容器setmultisetmapmultimap

  1. setset是一个无序集合,存储唯一的元素。内部实现使用红黑树,因此元素是按照特定的顺序进行存储。查找和插入操作的平均时间复杂度为O(log n)。

  2. multisetmultisetset类似,不同之处在于它可以存储重复的元素。

  3. mapmap是一个键值对的集合,其中的键是唯一的。内部实现也是使用红黑树。查找和插入操作的平均时间复杂度为O(log n)。

  4. multimapmultimapmap类似,不同之处在于它可以存储重复的键。

后续C++11又提供了哈希结构的关联式容器,此博客不做讲解。

关联式容器与序列式容器的区别在于元素的顺序。关联式容器内部使用二叉搜索树(如红黑树)实现,因此元素是按照特定的顺序进行存储。而序列式容器内部使用动态数组或链表实现,元素按照插入的顺序进行存储。


pair

在讲解mapset之前,我们要先了解一个类:pair

pair是一个模板类,封装了两个成员变量firstsecond,用于存储两个不同类型的值。它被定义在头文件<utility>中。

pair类的定义如下:

template <class T1, class T2>
struct pair
{T1 first;T2 second;
};

pair类有两个模板参数T1T2,分别表示两个值的类型。

pair类有两个成员变量firstsecond,分别表示两个值。

pair类的构造函数有多个重载形式,可以根据需要来创建pair对象。其中,最常用的是以下几种:

  • pair():默认构造函数,创建一个pair对象,默认初始化firstsecond
  • pair(const T1& x, const T2& y):构造函数,初始化firstxsecondy

pair类还支持拷贝构造函数、移动构造函数和赋值运算符重载,以及比较运算符重载。

使用pair类可以方便地将两个不同类型的值组合在一起,便于传递和操作。例如:

pair<int, string> p1(1, "hello");
cout << p1.first << " " << p1.second << endl;pair<double, char> p2;
p2.first = 3.14;
p2.second = 'a';
cout << p2.first << " " << p2.second << endl;

输出结果为:

1 hello
3.14 a

另外的,C++还提供了一个函数make_pair用于创建pair对象,需要时直接传入两个参数,分别对应firstsecondmake_pair内部会自动推演参数类型,返回一个pair对象。

auto p = make_pair("hello world", 10);

此时make_pair就会推演对象的类型为pair<const char*, int>

因为pair可以存储任意两个不同类型的数据,所以任何需要封装两个变量的地方,都可以使用pair。而我们的key - value结构,就是需要封装两个变量keyvalue,所以mapset的底层都是使用pair来完成的。


set

set是一种集合容器。它是基于红黑树实现的,它可以存储不重复的元素,并且会自动按照元素的大小进行排序。

下面是一些set的概念和特点:

  1. 不重复的元素:set中的元素是不重复的,每个元素只能出现一次。
  2. 自动排序:set中的元素会根据元素的大小进行自动排序。默认情况下,set按照升序排列。你也可以通过传入自定义的比较函数来进行降序排序。
  3. 红黑树实现:set内部使用红黑树(一种自平衡二叉搜索树)来存储元素。这个数据结构保证了素的快速插入、查找和删除,时间复杂度为O(logn)。
  4. 迭代器支持:set提供了迭代器,可以用于遍历集合中的元素。
  5. 查找和插入的效率高:由于set是基于红黑树实现,查找和插入操作的平均时间复杂度为O(logn),效率比较高。
  6. 元素的值是不可修改的:在set中,元素的值是不可修改的。如果需要修改元素的值,需要先删除旧的元素,然后插入新的元素。

接下来我们讲解set的接口使用以及注意事项。


模板参数

set的模板如下:

template < class T, class Compare = less<T>> class set;

其有两个模板参数:

T:代表value值的类型
Compare:代表了比较规则的仿函数

也就是说,我们在定义set的时候,可以在模板参数中传入仿函数,用于制定规则:

template <class T>
struct comp
{bool operator()(const T& t1, const T& t2) const{return T1 > T2;}
};int main()
{set<int, comp<int>> s1;return 0;
}

其中,s1通过仿函数comp完成了逆序排列,而set的模板参数有缺省值Compare = less<T>,所以set的默认情况是升序排列。


typedef的类型

类型含义缺省值
key_type第一个模板参数T的类型,即value的类型
value_type第一个模板参数T的类型,即value的类型
key_compare第二个模板参数的类型,即用于比较的仿函数的类型less<key_type>
value_compare第二个模板参数的类型,即用于比较的仿函数的类型less<value_type>

由于在set中,keyvalue是一致的,所以以上表格中,key_typevalue_type是一致的,key_comparevalue_compare是一致的。

key_comparevalue_compare的缺省值是 less<key_type>,即升序排序的仿函数。


构造函数

默认构造:

explicit set (const key_compare& comp = key_compare());

迭代器区间构造:

template <class InputIterator>
set (InputIterator first, InputIterator last,const key_compare& comp = key_compare());

通过一个迭代器区间来构造set,由于是模板,所以可以是其它容器的迭代器


迭代器

set的迭代器用法与其它容器一致,就是通过beginend来进行遍历,或者说使用反向迭代器。值得注意的是容器set的迭代器走中序遍历,得到的是有序的数据


常规接口

empty:

bool empty() const;

即返回这个set是否为空,如果为空返回true,不为空返回false


size:

size_type size() const;

返回当前set存储的节点个数。


swap:

void swap (set& x);

交换两个set的根节点指针。


clear:

void clear();

清空当前set


key_comp 与 value_comp:

key_compare key_comp() const;
value_compare value_comp() const;

可以看到,两者的返回类型分别是key_compare value_compare ,也就是比较keyvalue的仿函数,这两个函数的功能就是返回当前比较set的仿函数


find:

iterator find (const value_type& val) const;

find函数用于查找val值的节点,如果找到了,返回指向val的迭代器;如果没找到,则返回end()处的迭代器


count:

size_type count (const value_type& val) const;

count函数用于检测set中存在几个val值的节点,但是由于set不可以存在重复的元素,所以这个函数的返回值只有可能是1或0。返回类型为size_typesize_t无符号整型。


特殊接口

lower_bound 与 upper_bound:

iterator lower_bound (const value_type& val) const;
iterator upper_bound (const value_type& val) const;

两者都传入一个val值,返回值一个iterator迭代器,它们的功能如下:

lower_bound :返回第一个 >=val节点的迭代器
upper_bound :返回第一个 >val节点的迭代器

在STL设计中,都是利用左闭右开的区间特性,而迭代器也利用了此特性,我们可以使用lower_bound upper_bound配合得到一个一开一闭的迭代器区间,从而进行遍历,删除等等操作。

比如现在我们想遍历一个set[3, 20]的闭区间,你会如何查找迭代器?
假设我们有一个名为s1set,看一段代码:

auto it1 = s1.find(3);
auto it2 = s2.find(21);while(it1 != it2)
{cout << *it1 << endl;++it1;
}

请问这个代码正确吗?

以上代码存在两个问题:

  1. s1中可能不存在值为3或者21的节点,find有可能是失败的,此时我们就无法遍历到[3, 20]了。
  2. 由于我们要遍历[3, 20],迭代器遵循左闭右开的特性,所以我们找了一个比20大的迭代器21来遍历。但是如果我们的set存储的是float类型的数据,2021之间可能还会存在其它节点,此时我们可能就会多遍历到其它节点。

因此我们可以利用lower_bound upper_bound配合来得到迭代器:

auto it1 = s1.lower_bound(3);
auto it2 = s2.upper_bound(21);while(it1 != it2)
{cout << *it1 << endl;++it1;
}

以上代码中lower_bound(3)可以得到第一个>=3节点的迭代器,这样就不怕3节点不存在的情况了,如果3存在,此函数得到3,如果不存在,就得到大于3的下一个节点。
upper_bound(21)则是得到第一个>21节点的迭代器,如果我们存储了float类型的数据,而刚好存储了一个21.0001的数据,那么此时upper_bound(21)就刚刚好返回这个只大21一点点的节点。
通过两者配合,我们就可以得到一个等效的左闭右开迭代器区间,后续方便操作。


erase:
seterase存在三个重载:

void erase (iterator position);

这个erase用于删除迭代器指向的节点,迭代器必须有效

void erase (iterator first, iterator last);

这个erase用于删除整个迭代器区间[first, last)迭代器必须有效

size_type erase (const value_type& val);

这个erase用于删除val值的节点,val值可以不存在,删除后返回删除节点的个数。在set中,由于不存在重复节点,所以返回值只可能是0或1。


insert:
setinsert也存在三个重载:

iterator insert (iterator position, const value_type& val);

这个重载用于提高插入效率,如果迭代器position位于插入val值的节点之前,那么此次插入val的效率会提高,但是如果迭代器position与插入val节点无关,那么与一般的插入一致。

template <class InputIterator>
void insert (InputIterator first, InputIterator last);

这个重载用于插入一整个迭代器区间[first, last)

pair<iterator,bool> insert (const value_type& val);

这是最常用的插入,其用于直接插入一个val值的节点,但是其返回值比较特别:pair<iterator,bool>

如果原先val存在,此时iterator指向原先的val节点,bool值返回false表示插入失败
如果原先val不存在,此时iterator指向新插入的val节点,bool值返回true表示插入失败

但是函数不能一次性返回两个值,于是iteratorbool两个值封装进pair中返回。这样我们就既可以得到迭代器,又可以检测是否插入成功了。


multiset

multiset是一个允许存在重复元素的set,其它的效果与set完全一致。
但是有几个接口还是值得注意:

find:
multiset使用find时,由于一个val可能有多个节点,此时返回中序遍历的第一个节点

count:
对于set而言,count用于返回某个val值的个数,由于set不能重复,所以这个count接口没有多大意义。而对于multiset才有用,可以检测val的个数。


map

map是一种关联容器,用于存储键-值对(key-value)。map中的每个元素都由一个键和一个与之关联的值组成,键和值可以是任意类型。其将keyvalue封装进了pair中,所以每一个节点都是一个pair<key, value>


模板参数

set的模板如下:

template < class Key,  class T, class Compare = less<Key> >class map

其有三个模板参数:

Key:代表key值的类型
T:代表value值的类型
Compare:代表了比较规则的仿函数

同样的,map也可以在模板参数中定义仿函数,与set相似。


typedef的类型

类型含义缺省值
key_type第一个模板参数Key的类型,即key的类型
mapped_type第二个模板参数T的类型,即value的类型
value_typekeyvalue封装后 pair<const key_type,mapped_type>的类型
key_compare第二个模板参数的类型,即用于比较的仿函数的类型less<key_type>

map中,value的类型是mapped_type,而value_type却是pair<const key_type,mapped_type>的类型,这是值得注意的。


常规接口

由于map的很多接口和set一致,这里就用一张表格概括:

函数声明 功能注意事项
迭代器 begin , end等 遍历map走中序遍历,得到有序数据
emptybool empty() const;判空-
sizesize_type size() const;返回元素个数-
erasevoid erase (iterator position);删除迭代器指向的节点迭代器必须有效
size_type erase (const key_type& k);删除key值的节点 key值可以不存在
void erase (iterator first, iterator last);删除迭代器区间-
swapvoid swap (map& x);交换两棵树根节点指针-
clearvoid clear();清空map-
key_compkey_compare key_comp() const;得到比较key的仿函数-
value_compvalue_compare value_comp() const;得到比较value的仿函数-
find iterator find (const key_type& k);得到key位置的迭代器如果没有找到,返回end()等效的迭代器
count size_type count (const key_type& k) const;返回值为key的节点个数-
lower_bound iterator lower_bound (const key_type& k);返回第一个>=key值节点的迭代器-
upper_bound iterator upper_bound (const key_type& k);返回第一个>key值节点的迭代器-

特殊接口

insert:

对于map而言,insert的功能其实和set是一致的,但是不一样的是我们需要插入pair<key, value>,所以此处拿出来额外讲解。

重点看到以下insert的重载:

pair<iterator,bool> insert (const value_type& val);

其插入的值val的类型时候value_type,而我们先前说明过,value_type就是pair<key, value>的类型。也就是说,我们要构造出一个pair插入进去。
现在我们有map<string, int>

map<string, int> m;

现在我们对其进行插入:

  • 利用匿名对象插入:
m.insert(pair<string, int>("hello", 100));

以上代码,我们利用pair<string, int>("hello", 100)这种语法构造了一个匿名对象,然后进行插入。

  • 利用多参数默认构造的类型转化:
m.insert({ "hello", 100 });

由于pair具有一个多参数的默认构造,具有类型转化的功能,所以我们可以利用隐式类型转化进行传参。而我们有多个参数,所以要把这些参数用{}括起来。

  • 利用make_pair进行插入:
m.insert(make_pair("hello", 100));

即利用make_pair函数,让其自动推导类型构造pair


operator[ ]:
map还重载了[],这个重载比较复杂,但是非常有用,我们先看到声明:

mapped_type& operator[] (const key_type& k);

其接收一个key_type类型的参数,也就是接受一个key,然后返回一个mapped_type&,也就是一个value的引用。其功能为:接受一个key值,然后返回这个key对应的value的引用。

其等效于下面的代码:

(*((this->insert(make_pair(k,mapped_type()))).first)).second

现在我们来解读以上代码,我们将其拆解为四个部分:make_pair(k, mapped_type( )) + this->insert( ) + ( ).first + (*( )).second,我们一层层解析。

第一层:

make_pair(k, mapped_type( ))

可以看出,这是在利用参数k,通过make_pair构造一个pair,而这个pairvalue使用了mapped_type( )mapped_type就是value的类型)来调用默认构造。这样我们最后就得到了一个pair<key, value>

第二层:

this->insert( )

上一层我们构造了一个pair<key, value>,然后它被作为参数,传入到这个insert中,相当于把刚刚构造的节点插入进map中。map的插入后,不论成功与否,都会返回一个pair<iterator, bool>iterator用于指向key的迭代器,bool用于标识插入是否成功。所以这一层最后得到了一个pair,分别存储了指向key的迭代器和bool

第三层:

( ).first

上一层中我们得到了pair<iterator, bool>,这一层访问它的first,也就是访问了iterator,所以这一层得到了指向key值的迭代器

第四层:

(*( )).second

我们上一层拿到了指向key的迭代器,这一层先对迭代器解引用*( ),此时就得到了一个map的节点。而map的节点是pair<key, value>,所以我们解引用得到了一个pair,随后通过( ).second访问pair<key, value>second,也就是value。最后返回这个value的引用。

所以我们最后得到了key对应的value的引用。那么这有什么用呢?

假设我们有一个map<string, string>类型的字典dict,通过这个来展示operator[ ]的功能:

  1. 插入一个key值:
    dict["left"];
    以上语句在dict中插入了一个key = "left"但是没有value的节点

  1. 插入一对key - value
    dict["left"] = "左边";
    由于operator[ ]返回的是对应的引用,因此我们可以直接给返回值赋值,此时我们就插入了一个节点key = "left" - value = "左边"

  1. 修改key对应的value
    dict[“coffe”] = "咖啡";
    如果我们的dict原先就存在key = "coffe"的节点,以上代码可以修改这个keyvalue

  1. 得到key对应的value
    cout << dict["coffe"] << endl;
    由于我们拿到的是value的引用,我们也可以把它作为一个值赋值给别人或者输出

可以看到,operator[]的功能非常丰富,整体来说还是一个很好用的重载。


multimap

原本的map同一个key只能存在一个value,而multimap则可以存在多个key相同的节点,不过多赘述了。


相关文章:

C++:STL - set map

C&#xff1a;STL - set & map 关联式容器pairset模板参数typedef的类型构造函数迭代器常规接口特殊接口 multisetmap模板参数typedef的类型常规接口特殊接口 multimap 关联式容器 关联式容器是C标准库提供的一种数据结构&#xff0c;用于存储操作键值对&#xff08;key-v…...

一招鲜吃遍天之Haproxy集群

四层&#xff1a; LVS&#xff1a;Linux Virtual Server Nginx&#xff1a; HAProxy&#xff1a;High Availability Proxy 七层: HAProxy Nginx 硬件&#xff1a; F5 F5 | 多云安全和应用交付 Netscaler NetScaler: Application Delivery at Scale Array 北京华耀科技…...

数据库的筛选条件

【一】筛选过滤条件 【1】完整的查询语句 -- 查询当前表中的全部数据select * from 表名 where 筛选条件;​-- 查询当前表中的指定字段的数据select 字段名,字段名 from 表名 where 筛选条件;# 执行顺序from where select ​select 你选择的列1, 你选择的列2, ... from 查询的…...

MySQL学习笔记(一)数据库事务隔离级别与多版本并发控制(MVCC)

一、数据库事务隔离级别 数据库事务的隔离级别有4种&#xff0c;由低到高分别为Read uncommitted &#xff08;读未提交&#xff09;、Read committed&#xff08;读提交&#xff09; 、Repeatable read&#xff08;可重复读&#xff09; 、Serializable &#xff08;串行化&a…...

如何在Linux上为PyCharm创建和配置Desktop Entry

在Linux操作系统中&#xff0c;.desktop 文件是一种桌面条目文件&#xff0c;用于在图形用户界面中添加程序快捷方式。本文将指导您如何为PyCharm IDE创建和配置一个 .desktop 文件&#xff0c;从而能够通过应用程序菜单或桌面图标快速启动PyCharm。 步骤 1: 确定PyCharm安装路…...

Igraph入门指南 4

二、图的创建 图分有向图和无向图&#xff0c;所以图的创建有各自的实现方式。 1、手工创建图&#xff1a; 1-1 通过文本创建&#xff1a;graph_from_literal 通过每项提供两个顶点名&#xff08;或ID号&#xff09;作为一条边的格式&#xff0c;手动创建图&#xff0c;顶点…...

外包干了30天,技术明显退步。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 这次来聊一个大家可能也比较关心的问题&#xff0c;那就是就业城市选择的问题。而谈到这个问题&a…...

数据库 — 增删查改

一、操作数据库、表 显示 show databases;创建 create database xxx;使用 use xxx; 删除 drop database xxx;查看表&#xff1b; show tables; 查看表结构 desc 表名; 创建 create table 表名(字段1 类型1&#xff0c;字段2 类型2&#xff0c;.... ); 删除 drop table 表名; 二…...

eclipse搭建java web项目

准备条件 eclipsejdk1.8 &#xff08;配置jdk环境&#xff09;apache-tomcat-8.5.97&#xff08;记住安装位置&#xff09; 一 点击完成 开始创建javaweb项目 import java.io.IOException; import java.io.PrintWriter;import javax.servlet.ServletException; import javax.s…...

gitlab-ci_cd语法CICD

工作原理 1、将代码托管在git 2、在项目根目录创建ci文件.gitlan-ci.yml 在文件中指定构建&#xff0c;测试和部署脚本 3、gitlab将检测到他并使用名为git Runner的工具运行脚本 4、脚本被分组为作业&#xff0c;他们共同组成了一个管道gitlab-ci的脚本执行&#xff0c;需要自…...

python 蓝桥杯之动态规划入门

文章目录 DFS滑行&#xff08;DFS 记忆搜索&#xff09; 思路&#xff1a; 要思考回溯怎么写&#xff08;入参与返回值、递归到哪里&#xff0c;递归的边界和入口&#xff09; DFS 滑行&#xff08;DFS 记忆搜索&#xff09; 代码分析&#xff1a; 学会将输入的数据用二维列表…...

[LeetCode][102]二叉树的层序遍历——遍历结果中每一层明显区分

题目 102. 二叉树的层序遍历 给定二叉树的根节点 root&#xff0c;返回节点值的层序遍历结果。即逐层地&#xff0c;从左到右访问所有节点。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]] 示例 2&#xff1a; 输入…...

GIS之深度学习10:运行Faster RCNN算法

&#xff08;未完成&#xff0c;待补充&#xff09; 获取Faster RCNN源码 &#xff08;开源的很多&#xff0c;论文里也有&#xff0c;在这里不多赘述&#xff09; 替换自己的数据集&#xff08;图片标签文件&#xff09; &#xff08;需要使用labeling生成标签文件&#xf…...

appium2的一些配置

appium-desktop不再维护之后&#xff0c;需要使用appium2。 1、安装appium2 命令行输入npm i -g appium。安装之后输入appium或者appium-server即可启动appium 2、安装安卓/ios的驱动 安卓&#xff1a;appium driver install uiautomator2 iOS&#xff1a;appium driver i…...

基于springboot+vue实现高校学生党员发展管理系统项目【项目源码+论文说明】

基于springboot实现高校学生党员发展管理系统演示 摘要 随着高校学生规模的不断扩大&#xff0c;高校内的党员统计及发展管理工作面临较大的压力&#xff0c;高校信息化建设的不断优化发展也进一步促进了系统平台的应用&#xff0c;借助系统平台可以实现更加高效便捷的党员信息…...

Java代码审计安全篇-常见Java SQL注入

前言&#xff1a; 堕落了三个月&#xff0c;现在因为被找实习而困扰&#xff0c;着实自己能力不足&#xff0c;从今天开始 每天沉淀一点点 &#xff0c;准备秋招 加油 注意&#xff1a; 本文章参考qax的网络安全java代码审计&#xff0c;记录自己的学习过程&#xff0c;还希望…...

C#实现快速排序算法

C#实现快速排序算法 以下是C#中的快速排序算法实现示例&#xff1a; using System;class QuickSort {// 快速排序入口函数public static void Sort(int[] array){QuickSortRecursive(array, 0, array.Length - 1);}// 递归函数实现快速排序private static void QuickSortRecu…...

upload-labs通关记录

文章目录 前言 1.pass-012.pass-023.pass-034.pass-045.pass-056.pass-067.pass-078.pass-089.pass-0910.pass-1011.pass-1112.pass-1213.pass-1314.pass-1415.pass-1516.pass-1617.pass-1718.pass-1819.pass-19 前言 本篇文章记录upload-labs中&#xff0c;所有的通过技巧和各…...

Nginx实现高并发

注&#xff1a;文章是4年前在自己网站上写的&#xff0c;迁移过来了。现在看我之前写的这篇文章&#xff0c;描述得不是特别详细&#xff0c;但描述了Nginx的整体架构思想。如果对Nginx玩得透得或者想了解深入的&#xff0c;可以在网上找找其他的文章。 ......................…...

华为荣耀终端机试真题

文章目录 一 、字符展开(200分)1.1 题目描述1.2 解题思路1.3 解题代码二、共轭转置处理(100分)2.1 题目描述2.3 源码内容一 、字符展开(200分) 1.1 题目描述 // 64 位输出请用 printf(“%lld”)给定一个字符串,字符串包含数字、大小写字母以及括号(包括大括号、中括号…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...