【C++初阶(十)】set、map、multiset、multimap的介绍及使用

本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。

💓博主csdn个人主页:小小unicorn
⏩专栏分类:C++
🚚代码仓库:小小unicorn的代码仓库🚚
🌹🌹🌹关注我带你学习编程知识

C++初阶(十)

  • 关联式容器
  • 树形结构与哈希结构
  • 键值对
  • set
    • set介绍
    • set定义方式:
    • set使用
  • multiset
  • map
    • map的介绍
    • map的定义:
    • map的使用:
    • 插入:
    • map的查找
    • 删除
    • map的[ ]运算符重载
    • map的迭代器遍历
    • map的其他成员函数
  • multimap

关联式容器

C++STL包含了序列式容器关联式容器

1.序列式容器里面存储的是元素本身,其底层为线性序列的数据结构。比如:vector,list,deque,forward_list(C++11)等。

2.关联式容器里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。比如:set、map、unordered_set、unordered_map等。

注意: C++STL当中的stack、queue和priority_queue属于容器适配器,它们默认使用的基础容器分别是deque、deque和vector。

树形结构与哈希结构

根据应用场景的不同,C++STL总共实现了两种不同结构的关联式容器:树型结构和哈希结构

在这里插入图片描述
其中,树型结构容器中的元素是一个有序的序列,而哈希结构容器中的元素是一个无序的序列。

键值对

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

比如我们若是要建立一个英译汉的字典,那么该字典中的英文单词与其对应的中文含义就是一一对应的关系,即通过单词可以找到与其对应的中文含义。

在SGI-STL中关于键值对的定义如下:

template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	T1 first;
	T2 second;
	pair() : first(T1()), second(T2())
	{}
	pair(const T1& a, const T2& b) : first(a), second(b)
	{}
};

set

set介绍

1.set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。

2.set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。

3.与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对,因此在set容器中插入元素时,只需要插入value即可,不需要构造键值对。

4.set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。

5.在内部,set中的元素总是按照其内部比较对象所指示的特定严格弱排序准则进行排序。当不传入内部比较对象时,set中的元素默认按照小于来比较。

6.set容器通过key访问单个元素的速度通常比unordered_set容器慢,但

7.set容器允许根据顺序对元素进行直接迭代。

8.set在底层是用平衡搜索树(红黑树)实现的,所以在set当中查找某个元素的时间复杂度为(log N)。

set定义方式:

方式一: 构造一个某类型的空容器

set<int> s1; //构造int类型的空容器

方式二: 拷贝构造某类型set容器的复制品。

set<int> s2(s1); //拷贝构造int类型s1容器的复制品

方式三: 使用迭代器拷贝构造某一段内容。

string str("abcdef");
set<char> s3(str.begin(), str.end()); //构造string对象某段区间的复制品

方式四: 构造一个某类型的空容器,比较方式指定为大于。

set < int, greater<int>> s4; //构造int类型的空容器,比较方式指定为大于

set使用

set当中常用的成员函数如下:
在这里插入图片描述

set当中迭代器相关函数如下:
在这里插入图片描述
使用示例:

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

int main()
{
	set<int> s;
	//插入元素(去重)
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(3);
	s.insert(2);
	s.insert(2);
	s.insert(3);
	//遍历容器方式一(范围for)
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl; //1 2 3 4
	//删除元素方式一
	s.erase(3);
	//删除元素方式二
	set<int>::iterator pos = s.find(1); //查找值为1的元素
	if (pos != s.end())
	{
		s.erase(pos);
	}
	//遍历容器方式二(正向迭代器)
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl; //2 4
	//容器中值为2的元素个数
	cout << s.count(2) << endl; //1
	//容器大小
	cout << s.size() << endl; //2
	//清空容器
	s.clear();
	//容器判空
	cout << s.empty() << endl; //1
	//交换两个容器的数据
	set<int> tmp{ 11, 22, 33, 44 };
	s.swap(tmp);
	//遍历容器方式三(反向迭代器)
	set<int>::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl; //44 33 22 11
	return 0;
}

测试示例:
在这里插入图片描述
我们在看一下它的一些相关操作:
在这里插入图片描述
lower_bound与upper_bound:

这两个接口函数很简单,看一下示例:

void test_set2()
{
	std::set<int> myset;
	std::set<int>::iterator itlow, itup;

	for (int i = 1; i < 10; i++) myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90


	//itlow = myset.lower_bound(30);              //
	itlow = myset.lower_bound(25);                // >= val值位置的iterator
	itup = myset.upper_bound(70);                 // >  val值位置的iterator

	// [25, 70]
	//删除左闭右开
	myset.erase(itlow, itup);                     // 10 20 70 80 90

	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;
}

测试示例:
在这里插入图片描述
通过结果我们可以发现:lower_bound返回的是>=的val(30).
upper_bound返回的是>的 val(80);

equal_range:
在这里插入图片描述
equal_range这个接口函数,还是先看一下示例:

void test_set3()
{
	std::set<int> myset;

	for (int i = 1; i <= 5; i++) myset.insert(i * 10);   // myset: 10 20 30 40 50

	//std::pair<std::set<int>::const_iterator, std::set<int>::const_iterator> ret;
	auto ret = myset.equal_range(35);

	std::cout << "the lower bound points to: " << *ret.first << '\n';   // >= val
	std::cout << "the upper bound points to: " << *ret.second << '\n';  // > val
}

测试结果:
在这里插入图片描述
在这里插入图片描述
返回的还是一个是>=,一个是>利于删除左闭右开区间。

count:返回val的个数,可以判定在不在:

void test_set4()
{
	// 查找在不在
	// 排序 + 去重
	set<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(6);
	s.insert(1);
	s.insert(1);
	s.insert(2);

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

	//看3在不在:
	if (s.count(3))
	{
		cout << "3在" << endl;
	}
	else
	{
		cout << "3不在" << endl;
	}
}

测试结果:
在这里插入图片描述

multiset

multiset容器与set容器的底层实现一样,都是平衡搜索树(红黑树),其次,multiset容器和set容器所提供的成员函数的接口都是基本一致的,这里就不再列举了,multiset容器和set容器的唯一区别就是,multiset允许键值冗余,即multiset容器当中存储的元素是可以重复的。也可以理解为是一个变异的二叉树。
在这里插入图片描述

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

int main()
{
	multiset<int> ms;
	//插入元素(允许重复)
	ms.insert(1);
	ms.insert(4);
	ms.insert(3);
	ms.insert(3);
	ms.insert(2);
	ms.insert(2);
	ms.insert(3);
	for (auto e : ms)
	{
		cout << e << " ";
	}
	cout << endl; //1 2 2 3 3 3 4
	return 0;
}

测试结果:

在这里插入图片描述
在看下面这组示例:

void test_mutilset2()
{
	// 排序
	multiset<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(6);
	s.insert(1);
	s.insert(1);
	s.insert(2);
	s.insert(1);
	s.insert(5);
	s.insert(2);

	cout << "迭代器遍历" << endl;
	multiset<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10;
		cout << *it << " ";
		++it;
	}
	cout << endl;
	cout << "范围for遍历" << endl;
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << "如果有多个值,find返回中序第一个val" << endl;
	// 如果有多个值,find返回中序第一个val
	it = s.find(2);
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	
	cout << "可以直接用count计算val的个数,这里我们计算1" << endl;
	cout << s.count(1) << endl;

	// [>=val, >val)
	//auto ret = s.equal_range(2);
	//s.erase(ret.first, ret.second);
	size_t n = s.erase(5);
	cout << n << endl;
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

在这里插入图片描述

map

map的介绍

1.map是关联式容器,它按照特定的次序(按照key来比较)存储键值key和值value组成的元素,使用map的迭代器遍历map中的元素,可以得到有序序列。

2.在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,并取别名为pair。

3.map容器中元素的键值key不能被修改,但是元素的值value可以被修改,因为map底层的二叉搜索树是根据每个元素的键值key进行构建的,而不是值value。

4.在内部,map中的元素总是按照键值key进行比较排序的。当不传入内部比较对象时,map中元素的键值key默认按照小于来比较。

5.map容器通过键值key访问单个元素的速度通常比unordered_map容器慢,但map容器允许根据顺序对元素进行直接迭代。

6.map容器支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

7.map在底层是用平衡搜索树(红黑树)实现的,所以在map当中查找某个元素的时间复杂度为logN。

map的定义:

方式一: 指定key和value的类型构造一个空容器。

map<int, double> m1; //构造一个key为int类型,value为double类型的空容器

方式二: 拷贝构造某同类型容器的复制品。

map<int, double> m2(m1); //拷贝构造key为int类型,value为double类型的m1容器的复制品

方式三: 使用迭代器拷贝构造某一段内容。

map<int, double> m3(m2.begin(), m2.end()); //使用迭代器拷贝构造m2容器某段区间的复制品

方式四: 指定key和value的类型构造一个空容器,key比较方式指定为大于。

map<int, double, greater<int>> m4; //构造一个key为int类型,value为double类型的空容器,key比较方式指定为大于

map的使用:

插入:

在这里插入图片描述
map的插入函数的函数原型如下:

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

insert函数的参数显示是value_type类型的,实际上value_type就是pair类型的别名:

typedef pair<const Key, T> value_type;

因此,我们向map容器插入元素时,需要用key和value构造一个pair对象,然后再将pair对象作为参数传入insert函数。
在这里插入图片描述

方式一: 构造匿名对象插入。

map<int, string> m;
cout << "方法一:" << endl;
//方式一:调用pair的构造函数,构造一个匿名对象插入
m.insert(pair<int, string>(2, "two"));
m.insert(pair<int, string>(1, "one"));
m.insert(pair<int, string>(3, "three"));
for (auto e : m)
{
	cout << "<" << e.first << "," << e.second << ">" << " ";
}
cout << endl; //<1,one> <2,two> <3,three>

但是这种方式会使得我们的代码变得很长,尤其是没有直接展开命名空间的情况下,因此我们最常用的是方式二。

方式二: 调用make_pair函数模板插入。

在库当中提供以下make_pair函数模板:
在这里插入图片描述

template <class T1, class T2>
pair<T1, T2> make_pair(T1 x, T2 y)
{
	return (pair<T1, T2>(x, y));
}

我们只需向make_pair函数传入key和value,该函数模板会根据传入参数类型进行自动隐式推导,最终构造并返回一个对应的pair对象。
在这里插入图片描述

map<int, string> n;
cout << "方法二:" << endl;
//方式二:调用函数模板make_pair,构造对象插入
n.insert(make_pair(2, "two"));
n.insert(make_pair(1, "one"));
n.insert(make_pair(3, "three"));
for (auto e : n)
{
	cout << "<" << e.first << "," << e.second << ">" << " ";
}
cout << endl; //<1,one> <2,two> <3,three>

在这里插入图片描述
nsert函数的返回值也是一个pair对象,该pair对象中第一个成员的类型是map的迭代器类型,第二个成员的类型的一个bool类型,具体含义如下:

1.若待插入元素的键值key在map当中不存在,则insert函数插入成功,并返回插入后元素的迭代器和true。

2.若待插入元素的键值key在map当中已经存在,则insert函数插入失败,并返回map当中键值为key的元素的迭代器和false。

map的查找

map的查找函数的函数原型如下

iterator find (const key_type& k);

map的查找函数是根据所给key值在map当中进行查找,若找到了,则返回对应元素的迭代器,若未找到,则返回容器中最后一个元素下一个位置的正向迭代器。

    map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//获取key值为2的元素的迭代器
	map<int, string>::iterator pos = m.find(2);
	if (pos != m.end())
	{
		cout << pos->second << endl; //two
	}

删除

map的删除函数的函数原型如下:

//删除函数1
size_type erase (const key_type& k);
//删除函数2
void erase(iterator position);

也就是说,我们既可以根据key值删除指定元素,也可以根据迭代器删除指定元素,若是根据key值进行删除,则返回实际删除的元素个数。

    map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//方式一:根据key值进行删除
	m.erase(3);
	//方式二:根据迭代器进行删除
	map<int, string>::iterator pos = m.find(2);
	if (pos != m.end())
	{
		m.erase(pos);
	}

map的[ ]运算符重载

map的[ ]运算符重载函数的函数原型如下

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

[ ]运算符重载函数的参数就是一个key值,而这个函数的返回值如下:

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

就这样看着不太好理解,我们整理一下,实际上[ ]运算符重载实现的逻辑实际上就是以下三个步骤:

1.调用insert函数插入键值对。
2.拿出从insert函数获取到的迭代器。
3.返回该迭代器位置元素的值value。
对应分解代码如下:

mapped_type& operator[] (const key_type& k)
{
	//1、调用insert函数插入键值对
	pair<iterator, bool> ret = insert(make_pair(k, mapped_type()));
	//2、拿出从insert函数获取到的迭代器
	iterator it = ret.first;
	//3、返回该迭代器位置元素的值value
	return it->second;
}

那么这个函数的价值体现在哪里呢?我们来看看下面这段代码:

#include <iostream>
#include <string>
#include <map>
using namespace std;

int main()
{
	map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	m[2] = "nic"; //修改key值为2的元素的value为nic
	m[6] = "six"; //插入键值对<6, "six">
	for (auto e : m)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
	cout << endl; //<1,one> <2,dragon> <3,three> <6,six>
	return 0;
}

以代码中的m[2] = "nic"为例说明,通过[ ]运算符重载函数的三个步骤后,不管是调用insert函数插入的也好,是容器当中本来就已经存在的也好,反正无论如何map容器当中都已经有了一个key值为2的元素。而[ ]运算符重载函数的返回值就是这个key值为2的元素的value的引用,因此我们对该函数的返回值做修改,实际上就是对键值为2的元素的value做修改。

总结一下:

1.如果k不在map中,则先插入键值对<k, V()>,然后返回该键值对中V对象的引用。
2.如果k已经在map中,则返回键值为k的元素对应的V对象的引用。

map的迭代器遍历

map当中迭代器相关函数如下:
在这里插入图片描述
遍历方式一: 用正向迭代器进行遍历。

    map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//用正向迭代器进行遍历
	map<int, string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		it++;
	}
	cout << endl; //<1,one> <2,two> <3,three>

遍历方式二: 用反向迭代器进行遍历。

    map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//用反向迭代器进行遍历
	map<int, string>::reverse_iterator rit = m.rbegin();
	while (rit != m.rend())
	{
		cout << "<" << rit->first << "," << rit->second << ">" << " ";
		rit++;
	}
	cout << endl; //<3,three> <2,two> <1,one>

遍历方式三: 用范围for进行遍历。

map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//用范围for进行遍历
	for (auto e : m)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
	cout << endl; //<1,one> <2,two> <3,three>

map的其他成员函数

除了上述成员函数外,set当中还有如下几个常用的成员函数:
在这里插入图片描述

void test_map6()
{
	map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//获取容器中元素的个数
	cout << m.size() << endl; //3
	//容器中key值为2的元素个数
	cout << m.count(2) << endl; //1
	//清空容器
	m.clear();
	//容器判空
	cout << m.empty() << endl; //1
	//交换两个容器中的数据
	map<int, string> tmp;
	m.swap(tmp);
}

测试结果:
在这里插入图片描述

拓展:
我们给一个数组,里面放着水果和相应水果的个数,想查找一下每个水果的个数:

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (auto& str : arr)
	{
		auto ret = countMap.find(str);
		if (ret == countMap.end())
		{
			// 没有表示第一次出现,插入
			countMap.insert(make_pair(str, 1));
		}
		else
		{
			// 次数++
			ret->second++;
		}
	}
	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

结果:
在这里插入图片描述

这里我们还可以采取运算符重载[]来实现:

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	//for (auto& str : arr)
	//{
	//	auto ret = countMap.find(str);
	//	if (ret == countMap.end())
	//	{
	//		// 没有表示第一次出现,插入
	//		countMap.insert(make_pair(str, 1));
	//	}
	//	else
	//	{
	//		// 次数++
	//		ret->second++;
	//	}
	//	countMap[str]++;
	//}

	for (auto& str : arr)
	{
		countMap[str]++;
	}

	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

在这里插入图片描述

multimap

multimap容器与map容器的底层实现一样,也都是平衡搜索树(红黑树),其次,multimap容器和map容器所提供的成员函数的接口都是基本一致的,这里也就不再列举了,multimap容器和map容器的区别与multiset容器和set容器的区别一样,multimap允许键值冗余,即multimap容器当中存储的元素是可以重复的。

示例:

void test_map3()
{
	multimap<int, string> mm;
	//插入元素(允许重复)
	mm.insert(make_pair(2, "two"));
	mm.insert(make_pair(2, "double"));
	mm.insert(make_pair(1, "one"));
	mm.insert(make_pair(3, "three"));
	for (auto e : mm)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
	cout << endl; //<1,one> <2,two> <2,double> <3,three>
}

测试结果:
在这里插入图片描述

由于multimap容器允许键值冗余,因此两个容器中成员函数find和count的意义也有所不同:
在这里插入图片描述
其次,由于multimap容器允许键值冗余,调用[ ]运算符重载函数时,应该返回键值为key的哪一个元素的value的引用存在歧义,因此在multimap容器当中没有实现[ ]运算符重载函数。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Rust】快速教程——自定义类型、数字转枚举、Cargo运行

前言 超过一定的年龄之后&#xff0c;所谓人生&#xff0c;无非是一个不断丧失的过程而已。宝贵的东西&#xff0c;会像梳子豁了齿一样从手中滑落下去。你所爱的人会一个接着一个&#xff0c;从身旁悄然消逝。——《1Q84》 \;\\\;\\\; 目录 前言自定义类型数字转枚举Cargo.tom…

2022年高校大数据挑战赛A题工业机械设备故障预测求解全过程论文及程序

2022年高校大数据挑战赛 A题 工业机械设备故障预测 原题再现&#xff1a; 制造业是国民经济的主体&#xff0c;近十年来&#xff0c;嫦娥探月、祝融探火、北斗组网&#xff0c;一大批重大标志性创新成果引领中国制造业不断攀上新高度。作为制造业的核心&#xff0c;机械设备在…

[计算机网络] 高手常用的几个抓包工具(上)

文章目录 高手常用的抓包工具一览什么是抓包工具优秀抓包工具WiresharkFiddlerTcpdumpCharles 高手常用的抓包工具一览 什么是抓包工具 抓包工具是一种可以捕获、分析和修改网络流量的软件。它可以帮助您进行网络调试、性能测试、安全审计等任务。 抓包工具可以实时地显示网…

XML处理相关——(待完善)

记录 || Python | 提取xml/tmx文件中的文本内容 python xml处理 xml内容提取

Hdoop学习笔记(HDP)-Part.02 核心组件原理

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

[论文阅读]Generalized Attention——空间注意力机制

Generalized Attention An Empirical Study of Spatial Attention Mechanisms in Deep Networks 论文网址&#xff1a;Generalized Attention 论文代码&#xff1a;文章最后有GeneralizedAttention的实现代码 简读论文 本文主要研究了深度学习网络中的注意力机制。作者们从不…

iOS Class Guard 成功了,但无法区分差异

​ 我正在开发一个静态库&#xff0c;并使用 Polidea 的 iOS Class Guard 来混淆我的静态库。我按照步骤在项目的根路径中下载 obfuscate_project&#xff0c;更改其中所需的名称&#xff0c;最后在终端中运行 bash obfuscate_project。我收到一条消息&#xff0c;说我的构建成…

【linux】/etc/security/limits.conf配置文件详解、为什么限制、常见限制查看操作

文章目录 一. limits.conf常见配置项详解二. 文件描述符&#xff08;file descriptor&#xff09;简述三. 为什么限制四. 相关操作1. 展示当前资源限制2. 查看系统当前打开的文件描述符数量3. 查看某个进程打开的文件描述符数量4. 各进程占用的文件描述符 /etc/security/limits…

树和二叉树的基本概念和堆的实现

树的概念及结构 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 1.有一个特殊的结点&#…

第一类瑞利索末菲标量衍射模型的方孔衍射的空间像计算(附python计算代码)

记第一类瑞利索末菲标量衍射模型的方孔衍射的空间像计算(附python计算代码) RS type 1 衍射空间像计算傅里叶变换采样条件实际计算计算要求傅立叶变换法计算直接卷积方法计算代码傅立叶变换方法直接卷积https://zhuanlan.zhihu.com/p/624292239 Goodman, J. W. (2004). Intro…

logistic回归详解

为什么不直接统计标签数和预测结果数&#xff0c;计算精度&#xff1f; 因为 存在梯度为0的情况梯度不连续 为什么叫logistic回归 logistic是因为加了一个sigmoid函数&#xff0c;将输出预测值映射到【0&#xff0c;1】 有时候使用MSE损失函数&#xff0c;拟合 有时候使用c…

PyLMKit(5):基于网页知识库的检索增强生成RAG

基于网页知识库的检索增强生成RAG 0.项目信息 日期&#xff1a; 2023-12-2作者&#xff1a;小知课题: RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;是一种利用知识库检索的方法&#xff0c;提供与用户查询相关的内容&#xff0c;从而…

基于SpringBoot实现SSMP整合

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

【Gstreamer】自定义Plugin及调用Plugin

Gstreamer自定义Plugin及调用自定义Plugin Gstreamer支持开发者自己创建Plugin&#xff0c;创建后的Plugin可以通过工具gst-inspect-1.0查看&#xff0c;并在代码中调用自定义的plugin。 Gstreamer 官网中给出了Plugin创建教程&#xff0c;但实际上如果按照教程一步步走&…

kali学习

目录 黑客法则&#xff1a; 一&#xff1a;页面使用基础 二&#xff1a;msf和Windows永恒之蓝漏洞 kali最强渗透工具——metasploit 介绍 使用永恒之蓝进行攻击 ​编辑 使用kali渗透工具生成远程控制木马 渗透测试——信息收集 域名信息收集 黑客法则&#xff1a; 一&…

你好!二分查找【JAVA】

1.初次相识 二分查找又称折半查找&#xff0c;是一种在有序数组中查找特定元素的算法。二分查找的基本思想是&#xff1a;通过不断地二分数组的中间元素&#xff0c;缩小查找区间&#xff0c;直到找到目标元素或者确定目标元素不存在为止。 二分查找的时间复杂度为O(logn)&…

CIS|安森美微光近红外增强相机论文解析

引言 在之前的文章中&#xff0c;我们介绍了索尼、安森美以及三星等Sensor厂家在车载领域中的技术论文&#xff0c;分析了各个厂家不同的技术路线、Sensor架构以及差异点。今天&#xff0c;笔者借豪威科技在移动端200Mega Pixels产品的技术论文&#xff0c;讲解消费级CIS传感器…

Linux查看计算机处理器相关的信息

采用命令lscpu。部分结果如下&#xff1a;

人工智能时代:AIGC的横空出世

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 什么是AIGC?二. AIGC的主要特征2.1 文本生成2.2 图像生成2.3 语音生成2.4 视…

openGauss学习笔记-137 openGauss 数据库运维-例行维护-检查和清理日志

文章目录 openGauss学习笔记-137 openGauss 数据库运维-例行维护-检查和清理日志137.1 检查操作系统日志137.2 检查openGauss运行日志137.3 清理运行日志 openGauss学习笔记-137 openGauss 数据库运维-例行维护-检查和清理日志 日志是检查系统运行及故障定位的关键手段。建议按…