【C++进阶】set和map的基本使用(灰常详细)

news2024/11/18 9:23:34

在这里插入图片描述

👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:C++航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨


目录

  • 一、关联式容器
  • 二、键值对
  • 三、set容器
      • 3.1 概念
      • 3.2 set的使用
        • 3.2.1 构造
        • 3.2.2 insert + 迭代器
        • 3.2.3 find
        • 3.2.4 erase
        • 3.2.5 count
  • 四、multiset容器
  • 五、map容器
      • 5.1 概念
      • 5.2 insert
      • 5.3 访问容器数据 - 迭代器
      • 5.4 operator[]
  • 六、multimap
  • 七、交集与差集
      • 7.1 如何查找交集
      • 7.2 如何查找差集
  • 八、map和set的总结

一、关联式容器

来自【STL源码剖析】

  • 我们已经接触过STL中的部分容器,例如:vectorlistdeque等,这些容器统称为序列式容器(其底层为线性序列的数据结构)

那关联式容器与序列式容器有什么区别?

  • 所谓关联式容器,就是每个元素都有一个键值(key)和一个实值(value)。当元素被插入到关联式容器中时,容器内部结构(可能是红黑树,也可能是哈希表)便依照其键值大小,以某种特点规则将这个元素放在一个合适的位置(类似于二叉树搜索树)。注意:关联式容器没有所谓头尾(只有最大元素和最小元素),所以不会有所谓push_backpush_frontpop_backpop_front这样的操作行为

一般而言,关联式容器的内部结构是一个平衡二叉树,以便获得良好的搜索效率

二、键值对

在以上我们提到了键值,那么键值是什么呢?

  • 键值对是 一种用来表示具有一一对应关系的结构,该结构中一般只包含两个成员变量:keyvalue。其中,key表示键值,value表示与key对应的信息

关联式容器的实现离不开键值对,因此在标准库中,专门提供了这种pair

pair就不在这里细说了,可以参考往期博客:点击跳转

三、set容器

3.1 概念

【文档介绍】

在这里插入图片描述

  • set其实就是之前在二叉搜索树说的key的模型。但是注意,set并不是完全是二叉搜索树,它的底层其实是一颗红黑树(一颗搜索树)
    *set不像map那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,实值就是键值。
  • set不允许有两个元素有相同的键值。

3.2 set的使用

3.2.1 构造

在这里插入图片描述

  1. 默认构造
  2. 迭代区间构造
  3. 拷贝构造

和以往学习的STL容器类似,就不一一演示了

3.2.2 insert + 迭代器

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <set>

using namespace std;

int main()
{
	int a[] = { 2,1,5,6,3,4,8,10,7 };
	set<int> s;
	for (auto x : a)
	{
		s.insert(x);
	}

	set<int>::iterator sit = s.begin();
	while (sit != s.end())
	{
		cout << *sit << " ";
		++sit;
	}
	cout << endl;

	return 0;
}

【程序结果】

在这里插入图片描述

以上代码的逻辑是将数组a中元素全部插入到set容器中,可是有一个问题:为什么迭代器遍历出来的结果为升序呢?我们可以联想【二叉搜索树】,它的中序遍历是一个升序。因此,set容器底层迭代器的实现方式就是中序。

那如果我在set容器中插入重复元素,结果又会是如何呢?

在这里插入图片描述

我们发现:当插入的数出现冗余,它就有去重的效果。其实它的底层其实是:遇到键值冗余的数据就不插入。

那么接下来又牵扯到一个知识点:如果一个容器支持迭代器,那么它必定支持范围for,因为其底层就是靠迭代器实现的

#include <iostream>
#include <set>

using namespace std;

int main()
{
	int a[] = { 2,1,5,6,3,4,8,10,7 };
	set<int> s;
	for (auto x : a)
	{
		s.insert(x);
	}

	for (auto x : s)
	{
		cout << x << " ";
	}
	cout << endl;

	return 0;
}

【程序结果】

在这里插入图片描述

3.2.3 find

在这里插入图片描述

在这里插入图片描述

#include <set>
#include <iostream>
using namespace std;

int main()
{
	set<int> s1;
	s1.insert(2);
	s1.insert(5);
	s1.insert(1);
	s1.insert(4);
	s1.insert(3);
	
	// 查找3
	set<int>::iterator pos = s1.find(3);
	if (pos != s1.end())
		cout << "找到了3" << endl;
	else
		cout << "没找到3" << endl;

	return 0;
}

【输出结果】

在这里插入图片描述

  • 问题1:似乎算法库algorithm中也有一个find函数,那么为什么set容器还要再设计find函数呢?

它们除了功能是相同的以为,在效率方面不是一样set实现的find函数查找的时间复杂度是O(logN),大的往右子树查找,小的往左子树查找,因此只需要查找高度次;而算法库中的find是利用迭代器来遍历整颗树(暴力查找),时间复杂度为O(N)因此,实际中有运用到find函数,建议使用内置的。

  • 问题2:我们可以通过set的迭代器改变set的元素值吗?
#include <set>
#include <iostream>
using namespace std;

int main()
{
	set<int> s1;
	s1.insert(2);
	s1.insert(5);
	s1.insert(1);
	s1.insert(4);
	s1.insert(3);

	// 查找4,找到了修改成100
	set<int>::iterator pos = s1.find(4);
	if (pos != s1.end())
	{
		*pos = 100;
	}
	else
	{
		cout << "没找到3" << endl;
	}

	return 0;
}

【程序结果】

在这里插入图片描述

答案已经很明显了!不能修改!因为set元素值就是其键值,修改了会关系到set元素的排列规则。如果任意改变set元素值,会严重破坏set组织。通过查阅文档,我们发现普通迭代器被定义为const迭代器

在这里插入图片描述

3.2.4 erase

在这里插入图片描述

大家看上图,迭代器方式删除和给值删除方式有没有什么差异? 第给值删除不是更加方便吗?直接给个值删除就行,为什么要提供第一种?

大家可以认为第二种就是依靠第一种实现的。这是因为在大多情况,还是要依靠查找来删除值。

除此之外,给值删除方式有个特点:删除除容器以外的值不会报错

#include <iostream>
#include <set>

using namespace std;

int main()
{
	int a[] = { 2,1,5,6,3,4,8,10,7 };
	set<int> s;
	for (auto x : a)
	{
		s.insert(x);
	}

	// 删除100
	s.erase(100);

	for (auto x : s)
	{
		cout << x << " ";
	}
	cout << endl;

	return 0;
}

【程序结果】

在这里插入图片描述

如果使用迭代删除方式,没有对find的返回值进行特判,就会发生断言错误

#include <iostream>
#include <set>

using namespace std;

int main()
{
	int a[] = { 2,1,5,6,3,4,8,10,7 };
	set<int> s;
	for (auto x : a)
	{
		s.insert(x);
	}

	// 删除100
	set<int>::iterator sit = s.find(100);
	s.erase(sit);

	for (auto x : s)
	{
		cout << x << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.2.5 count

在这里插入图片描述
在这里插入图片描述

除了find可以查找,count也可以。count作用是:传一个值,就会返回这个值出现了几次。因此,它也可以用来查找。

在这里插入图片描述

但是有了find函数,再设计count函数是不是有点冗余。其实count在后面另有用处…

四、multiset容器

在这里插入图片描述

set 还有一个亲兄弟:multiset,它和set容器最大的区别是:允许出现数据冗余,即插入冗余的数据一定是成功的。

除此之外,multisetset的操作没什么区别,都是一模一样。大家可以通过文档自行查阅:点击跳转

这里单独演示一下允许数据冗余的效果

在这里插入图片描述

所以,multiset 才是真正的排序,可以出现数据冗余的情况,set则是去重 + 排序

除此之外,刚刚说的 count函数其实就是为multiset准备的

在这里插入图片描述

在这里插入图片描述

那么问题来了,如果我想查找的数据恰好出现冗余的情况,请问返回的数据是第几次出现的数据呢?

可以打印出它们的地址来看

#include <iostream>
#include <vector>
#include <set>
using namespace std;

int main()
{
	vector<int> v = { 1,3,5,7,5,9,2,3,3,3 };
	multiset<int> ms1(v.begin(), v.end());

	auto pos = ms1.begin();
	while (pos != ms1.end())
	{
		cout << *pos << ":" << &(*(pos)) << endl;
		pos++;
	}
	cout << endl;

	// 查找5
	cout << "5:" << &(*(ms1.find(5))) << endl;

	return 0;
}

【输出结果】

在这里插入图片描述

在实际中,multiset用的比较少,重点掌握set即可

五、map容器

5.1 概念

在这里插入图片描述

  • map是二叉搜索树改造后的key/value模型,是一个真正意义上的 键值对
  • map的特性是:所有元素都会根据元素的键值自动被排序map的所有元素都是用pair结构存储的,同时拥有实值(value)和键值(key)。pair的第一个元素(first)被视为键值,第二个元素(second)被视为实值。
  • 注意:map不允许两个元素拥有相同的键值

5.2 insert

在这里插入图片描述

我们首先可以看看插入接口,注意看其参数类型:value_type,它是key的类型还是value的类型呢?可以查阅文档:

在这里插入图片描述

value_type是一个pair结构,并且key_type(也就是键值key)是由const修饰的,表明不能被修改!

想补充pair知识可以参考往期博客:点击跳转

接下来举一个代码样例:字典

在这里插入图片描述

插入的方式不能向上面这样写,这是很多初学者犯的错误。刚刚说过,键值和实值需要用pair结构来存

int main()
{
    map<string, string> dict;
    // 写法一:创建pair的结构对象
    pair<string, string> p("插入", "insert");
    dict.insert(p);

    // 写法二:pair的匿名对象
    dict.insert(pair<string, string>("插入", "insert"));

    // 写法三:以上的写法非常繁琐,如果没有展开命名空间的话
    // 因此可以使用make_pair简化代码
    dict.insert(make_pair("删除", "erase"));

    // 写法四:用花括号括起来
    // 这种方式非常简洁,但是有一个限制
    // 编译器必须支持C++11:多参数构造函数支持隐式类型转化
    // C++98:单参数构造函数支持隐式类型转换
    dict.insert({"查找", "find"});

    return 0;
}

5.3 访问容器数据 - 迭代器

  • map同样支持迭代器

在这里插入图片描述

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std;

int main()
{
    map<string, string> dict;
    pair<string, string> p("插入", "insert");
    dict.insert(p);
    dict.insert(pair<string, string>("插入", "insert"));
    dict.insert(make_pair("删除", "erase"));
    dict.insert({ "查找", "find" });

    // 迭代器遍历
    map<string, string>::iterator mit = dict.begin();
    while (mit != dict.end())
    {
        cout << *mit << " ";
        ++mit;
    }
    cout << endl;

    return 0;
}

在这里插入图片描述

很多初学者大概率会写出以上代码,但是编译不通过!从提示可以看出:pair不支持流插入<<

再回过头来分析:数据是存在pair结构里的,那么像访问结构体内的元素,是不是可以用->或者*操作符来访问数据。并且在【map概念部分】说过了:pair的第一个元素(first)被视为键值,第二个元素(second)被视为实值

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std;

int main()
{
    map<string, string> dict;
    pair<string, string> p("插入", "insert");
    dict.insert(p);
    dict.insert(pair<string, string>("插入", "insert"));
    dict.insert(make_pair("删除", "erase"));
    dict.insert({ "查找", "find" });

    // 迭代器遍历
    // ->访问方式
    map<string, string>::iterator mit = dict.begin();
    while (mit != dict.end())
    {
        cout << mit->first << ":" << mit->second << endl;
        ++mit;
    }
    cout << endl;

    // *访问方式
    mit = dict.begin();
    while (mit != dict.end())
    {
        cout << (*mit).first << ":" << (*mit).second << endl;
        ++mit;
    }
    cout << endl;

    return 0;
}

【运行结果】

在这里插入图片描述

同理地,既然map也支持迭代器,那么就必定支持范围for

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std;

int main()
{
    map<string, string> dict;
    pair<string, string> p("插入", "insert");
    dict.insert(p);
    dict.insert(pair<string, string>("插入", "insert"));
    dict.insert(make_pair("删除", "erase"));
    dict.insert({"查找", "find"});

    // 访问for
    for (const auto &x : dict)
    {
        cout << x.first << ":" << x.second << endl;
    }
    return 0;
}

【运行结果】

在这里插入图片描述

  • 那么现在就有一个问题:可以通过map的迭代器改变map的元素内容吗?

如果是想修改键值(key)是不行的。还是和set一样的原因:map元素的键值关系到map元素的排列规则。任意改变map元素的key将会严重破坏map组织。
但如果想要修改元素的实值(value),那么是可以的。因为map元素的实值并不影响map的排列规则

在这里插入图片描述

官方文档同样也给出了答案:键值keyconst修饰,表示不能被修改。

5.4 operator[]

大家可能会感到奇怪,map底层是一个树形结构,按理来说是不支持随机访问的,可是为什么map支持operator[]呢?

map常见的使用场景是:统计出现过的次数

假设我要写一个统计水果出现的次数,大部分人都可以写出以下代码

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std;

// ### 5.3 operator[]
// 大家可能会感到奇怪,map底层是一个树形结构,按理来说是不支持随机访问的,可是为什么map支持`operator[]`呢?

int main()
{
    string s[] = {"西瓜", "西瓜", "香蕉", "苹果", "桃子", "香蕉", "香蕉", "香蕉"};
    map<string, int> dict;
    // 将数组内的元素放进map中来统计次数
    for (auto x : s)
    {
        // 如果水果刚刚出现第一次出现,就将记为1
        map<string, int>::iterator pos = dict.find(x);
        if (pos == dict.end())
        {
            dict.insert(make_pair(x, 1));
        }
        // 否则就是出现过两次以上
        else
        {
            pos->second++;
        }
    }

    for (const auto &x : dict)
    {
        cout << x.first << ":" << x.second << endl;
    }
    return 0;
}

【运行结果】

在这里插入图片描述

但是以上代码还可以优化:使用operator[]

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std;

// ### 5.3 operator[]
// 大家可能会感到奇怪,map底层是一个树形结构,按理来说是不支持随机访问的,可是为什么map支持`operator[]`呢?

int main()
{
    string s[] = { "西瓜", "西瓜", "香蕉", "苹果", "桃子", "香蕉", "香蕉", "香蕉" };
    map<string, int> dict;
    // 将数组内的元素放进map中来统计次数
    for (auto x : s)
    {
        dict[x]++;
    }

    for (const auto& x : dict)
    {
        cout << x.first << ":" << x.second << endl;
    }
    return 0;
}

【运行结果】

在这里插入图片描述

代码改进后结果也是正确的,并且比第一种简洁多了!那么,operator[]到底是何方神圣呢?我们一起来研究一下

我们可以通过文档来分析

在这里插入图片描述

在这里插入图片描述

注意看它的参数和返回类型,这里的operator[]并不是以往我们所认识的下标访问。它是通过键值key来返回实值value的引用!

那么这里有个问题,它是如何找到实值,然后进行修改的呢?

文档同样给出了答案,operator[]等价于调用以下这么个长东西

在这里插入图片描述

面对这么长的代码一定要耐下心来从内向外剖析

在这里插入图片描述

因此,就要研究insert的返回值

在这里插入图片描述

简单翻译一下:

insert会返回一个pair结构,其中这个pairfirst被设置成了一个迭代器,而迭代器的指向分两种情况:

  1. 键值key已经在树里,那么就返回树里面key所在结点的迭代器
  2. 键值key不在树里,那么就返回新插入key所在结点的迭代器

在这里插入图片描述

以上的长代码可以分解如下:

V &operator[](const K &key)
{
    pair<iterator, bool> res = insert(make_pair(key, V()));
    return res.first->second;
}

通过以上解释,会发现operator[]有插入、修改、插入+修改、查找

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std;

// ### 5.3 operator[]
// 大家可能会感到奇怪,map底层是一个树形结构,按理来说是不支持随机访问的,可是为什么map支持`operator[]`呢?

int main()
{
    // 有插入、修改、插入+修改、查找
    map<string, string> m1;
    
    // 插入
    m1["hello"] = "你好";
    m1["sort"] = "插入";

    for (const auto& x : m1)
    {
        cout << x.first << ":" << x.second << endl;
    }

    // 修改
    m1["sort"] = "排序";

    for (const auto& x : m1)
    {
        cout << x.first << ":" << x.second << endl;
    }
    return 0;
}

【运行结果】

在这里插入图片描述

六、multimap

在这里插入图片描述

multimap中允许出现多个重复的键值。因此,operator[]就无法确认调用者的意图,也就是不知道要返回哪个 键值对应的结点。所以multimap中没有提供operator[],当然其他操作都是和map相同

还有的是:查找find时,返回的是中序遍历中第一次出现元素的迭代器;另外计数count返回的则是当前键值的数量

七、交集与差集

7.1 如何查找交集

交集,指两个数组中相同的元素所构成的集合

求交集的步骤如下:

  1. 先将两个数组 排序 + 去重
  2. 遍历两个数组
  3. 如果不相等,小的 ++
  4. 相等就是交集,记录下来
  5. 其中一方走完,所有交集就查找完了

排序 + 去重,就可以使用set

相关题目:点击跳转

//349. 两个数组的交集
//https://leetcode.cn/problems/intersection-of-two-arrays/description/

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        //排序 + 去重
        set<int> s1(nums1.begin(), nums1.end());
        set<int> s2(nums2.begin(), nums2.end());

        //查找交集
        vector<int> v;
        auto it1 = s1.begin();
        auto it2 = s2.begin();

        while(it1 != s1.end() && it2 != s2.end())
        {
            if(*it1 < *it2)
                ++it1;
            else if(*it1 > *it2)
                ++it2;
            else
            {
                v.push_back(*it1);
                ++it1;
                ++it2;
            }
        }

        return v;
    }
};

7.2 如何查找差集

至于差集的查找,思路和交集差不多

求差集的步骤如下:

  1. 先将两个数组 排序 + 去重
  2. 遍历两个数组
  3. 如果相等,同时 ++
  4. 不相等,小的一方记录后,再 ++
  5. 其中一方走完,再遍历另一方,此时其中的所有元素都是差集

八、map和set的总结

  • set
  1. 只有键值,其键值就是实值,所以传递参数时,只需要传递实值
  2. 自带去重机制,不允许出现数据冗余
  3. 使用迭代器遍历容器时,结果为有序,并且默认为升序
  4. 即使是普通迭代器,也不运行修改键值
  • map
  1. 既包含键值,也包含实值。插入时,需要传pair对象
  2. 自带去重机制,不允许出现数据冗余
  3. 使用迭代器遍历容器时,结果为有序,并且默认为升序。是靠键值进行排序的
  4. 普通迭代器不运行修改键值,但运行修改实值

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

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

相关文章

QQ云端机器人登录系统php源码开心版

可能很多人不知道这源码有什么用&#xff0c;这款源码主要是针对群机器人爱好者的&#xff0c; 这是一个通过对接挂机宝里面机器人框架的一个网页站点&#xff0c; 用户通过网页登录 QQ 账号至挂机宝里面框架&#xff08;可扫码登录、账密登录、跳转 QQ 快捷登录&#xff09;…

Canal整合SpringBoot详解(一)

文章目录 Canal整合SpringBoot详解&#xff08;一&#xff09;什么是canal搭建Kafka3.2.1集群⭐Kafka集群机器规划创建3台虚拟机&#xff08;centos7系统&#xff09;必要的环境准备&#xff08;3台虚拟机都要执行如下操作&#xff09;⭐分别修改每个服务器的hosts文件&#xf…

【2021集创赛】Robei杯一等奖:基于Robei EDA工具的隔离病房看护机器人设计

本作品参与极术社区组织的有奖征集|秀出你的集创赛作品风采,免费电子产品等你拿~活动。 团队介绍 参赛单位&#xff1a;重庆交通大学 队伍名称&#xff1a;一丘之貉 指导老师&#xff1a;毕波 李艾星 参赛队员&#xff1a;郁航 张坤 秦衡 总决赛奖项&#xff1a;Robei杯一等奖…

iOS开发-CoreNFC实现NFC标签Tag读取功能

iOS开发-CoreNFC实现NFC标签Tag读取功能 一、NFC近场通信 近场通信&#xff08;NFC&#xff09;是一种无线通信技术&#xff0c;它使设备能够在不使用互联网的情况下相互通信。它首先识别附近配备NFC的设备。NFC常用于智能手机和平板电脑。 二、实现NFC标签Tag读取功能 在…

Linux | 进程终止与进程等待

目录 前言 一、进程终止 1、进程终止的几种可能 2、exit 与 _exit 二、进程等待 1、为什么要进程等待 2、如何进行进程等待 &#xff08;1&#xff09;wait函数 &#xff08;2&#xff09;waitpid函数 3、再次深刻理解进程等待 前言 我们前面介绍进程时说子进程退出…

Canal整合SpringBoot详解(二)

文章目录 Canal整合SpringBoot详解&#xff08;二&#xff09;什么是canal案例2&#xff1a;CanalKafka实现mysql和elasticsearch的数据同步⭐Docker搭建elasticsearch7.8.0&#xff08;单机版本&#xff09;⭐Docker安装elasticsearch-head5⭐解决es-head 406错误问题直接修改…

实用篇-Eureka注册中心

一、提供者与消费者 服务提供者&#xff1a;一次业务中&#xff0c;被其他微服务调用的服务。(提供接口给其他微服务) 服务消费者&#xff1a;一次业务中&#xff0c;调用其他微服务的服务。(调用其他微服务提供的接口) 例如前面的案例中&#xff0c;order-service微服务是服…

系列七、动态代理

一、概述 二、Jdk动态代理案例 2.1、Star /*** Author : 一叶浮萍归大海* Date: 2023/10/27 17:16* Description:*/ public interface Star {/*** 唱歌* param name 歌曲名字* return*/String sing(String name);/*** 跳舞*/void dance(); } 2.2、BigStar /*** Author : 一叶…

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细)

&#xff08;1&#xff09;acwing 4557. 最长上升子序列 4557. 最长上升子序列 - AcWing题库 给定一个长度为 N 的整数序列 a1,a2,…,aN。请你计算该序列的最长上升子序列的长度。上升子序列是指数值严格单调递增的子序列 输入格式 第一行包含整数 N第二行包含 N个整数 a1,a…

LLM系列 | 23:多模态大模型:浦语·灵笔InternLM-XComposer解读、实战和思考

引言 ​简介 模型解读 模型架构 训练 实战 环境准备 本地实测 服务部署 总结 引言 谁念西风独自凉&#xff0c;萧萧黄叶闭疏窗&#xff0c;沉思往事立残阳。 Created by DALLE 3 小伙伴们好&#xff0c;我是《小窗幽记机器学习》的小编&#xff1a;卖热干面的小女孩…

在Golang中理解错误处理

处理Golang中临时错误和最终错误的策略和示例 作为一名精通Golang的开发人员&#xff0c;您了解有效的错误处理是编写健壮可靠软件的关键因素。在复杂系统中&#xff0c;错误可能采取各种形式&#xff0c;包括临时故障和最终失败。在本文中&#xff0c;我们将探讨处理Golang中…

源码解析SpringMVC之RequestMapping注解原理

1、启动初始化 核心&#xff1a;得到应用上下文中存在的全部bean后依次遍历&#xff0c;分析每一个目标handler & 目标方法存在的注解RequestMapping&#xff0c;将其相关属性封装为实例RequestMappingInfo。最终将 uri & handler 之间的映射关系维护在类AbstractHand…

Java入门篇 之 数据类型(简单介绍)

博主回归学习状态的第三篇文章&#xff0c;希望对大家有所帮助 今日份励志文案:你若决定灿烂&#xff0c;山无遮&#xff0c;海无拦 加油&#xff01; Java中一共存在2种数据类型 1 . 基本数据类型,基本数据类型四种和八种之说(具体看下图) 四种说的是&#xff0c;整数型&…

vscode打开settings.json方法

cmd shift p&#xff0c;输入setting Open Workspace Settings 也会打开UI设置界面&#xff1b; Open User Settings (JSON) 会打开用户设置 settings.json 文件&#xff1b; Open Workspace Settings (JSON) 会打开工作区设置 settings.json 文件 vscode存在两种设置 sett…

损失函数和目标函数|知识补充

这张图中&#xff0c;横坐标size表示房屋的大小&#xff0c;纵坐标price表示房屋的价格&#xff0c;现在需要建立模型来表示两者之间的关系。 对于给定的输入x&#xff0c;模型会有一个输出f(x)&#xff0c;用一个函数来度量拟合的程度&#xff0c;也就是真实值和预测值之间的…

前端工程化面试题及答案【集合】

前言&#xff1a; 欢迎浏览和关注本专栏《 前端就业宝典 》&#xff0c; 不管是扭螺丝还是造火箭&#xff0c; 多学点知识总没错。 这个专栏是扭螺丝之上要造火箭级别的知识&#xff0c;会给前端工作学习的小伙伴带来意想不到的帮助。 本专栏将前端知识拆整为零&#xff0c;主要…

工业相机常见的工作模式、触发方式

参考&#xff1a;机器视觉——工业相机的触发应用(1) - 知乎 工业相机常见的工作模式一般分为&#xff1a; 触发模式连续模式同步模式授时同步模式 触发模式&#xff1a;相机收到外部的触发命令后&#xff0c;开始按照约定时长进行曝光&#xff0c;曝光结束后输出一帧图像。…

子集生成算法:给定一个集合,枚举所有可能的子集

给定一个集合&#xff0c;枚举所有可能的子集。 &#xff08;为简单起见&#xff0c;本文讨论的集合中没有重复元素&#xff09; 1、方法一&#xff1a;增量构造法 第一种思路是一次选出一个元素放到集合中&#xff0c;程序如下&#xff1a; void print_subset(int n, int …

C++系列之list的模拟实现

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; list的节点类 template struct list_Node { public: list_Node* _prev; list_…

Tomcat服务部署和优化

目录 一、Tomcat&#xff1a; 1、Tomcat作用&#xff1a; 2、Tomcat的核心组件&#xff1a; 3、servlet作用&#xff1a; 4、Tomcat的核心功能&#xff1a; 二、tomcat配置 一、Tomcat&#xff1a; 是一个开源的web应用服务器&#xff0c;nginx主要处理静态页面&#xff…