c++的STL(5)-- set和multiset容器

set和multiset容器概述

  •  首先set和multiset这两种容器底层是红黑树(是一种数据结构,是树形结构)实现的。
  • 我们前面说到vector,deque容器插入数据慢,但是读取数据快list呢恰恰相反,插入数据快,查询慢。但是set和multiset数据查询和插入速度都很快(由于底层是有红黑树实现)。
  • 对于set我们依然没有办法使用下标[]或者at(),来访问数据,而且其迭代器和指针也只能进行++,--运算(前置和后置都行),!=,==的比较运算。(这个和list容器是类似的,因为在set中元素和元素之间也是通过指针来联系的,它们的内存也不挨着 -- 所以set和multiset也不需要提前开辟空间)
  • set容器中存放的元素不能有重复的,但是multiset是可以存放相同元素的
  • set和multiset会对数据进行自动排序(我们可以指定排序规则)。
表 C++ set 容器常用成员方法
成员方法功能
begin()返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end()返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
rbegin()返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
rend()返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
find(val)在 set 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
lower_bound(val)返回一个指向当前 set 容器中第一个大于或等于 val 的元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
upper_bound(val)返回一个指向当前 set 容器中第一个大于 val 的元素的迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
equal_range(val)该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的值为 val 的元素(set 容器中各个元素是唯一的,因此该范围最多包含一个元素)。
empty()若容器为空,则返回 true;否则 false。
size()返回当前 set 容器中存有元素的个数。
max_size()返回 set 容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。
insert()向 set 容器中插入元素。
erase()删除 set 容器中存储的元素。
swap()交换 2 个 set 容器中存储的所有元素。这意味着,操作的 2 个 set 容器的类型必须相同。
clear()清空 set 容器中所有的元素,即令 set 容器的 size() 为 0。
emplace()在当前 set 容器中的指定位置直接构造新元素。其效果和 insert() 一样,但效率更高。
emplace_hint()在本质上和 emplace() 在 set 容器中构造新元素的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示新元素生成位置的迭代器,并作为该方法的第一个参数。
count(val)在当前 set 容器中,查找值为 val 的元素的个数,并返回。注意,由于 set 容器中各元素的值是唯一的,因此该函数的返回值最大为 1。

先说set容器再说multiset容器,首先使用set或者multiset都需要导入头文件#include<set> 

1. set的默认构造 

代码 

set<int> s1;
set<float> s2;
set<Student> s3;
set<int *> s4;
set<Student *> s5;

2. set的有参构造 

代码 

	/*
		vector<int> v1{10,11,12,13,14,15,16};
		int arr[] = { 100,200,300,400,500 };

		set<int> s1{ 1,2,3,4,5 };
		set<int> s2(s1);
		set<int> s3(s1.begin(),s1.begin()++);
		set<int> s4(v1.begin(), v1.end());
		set<int> s5(arr, arr + 3);
	*/
相关知识点 
  • 和之前的容器没有什么区别。(set不能使用数字直接作为有参构造的参数) 

 3. set容器的元素个数

代码:   使用size()函数

int main(void) {
	set<int> s1{10,11,12,13,14,15};

	cout << "set 的元素个数: " << s1.size() << endl;  // 6

	system("pause");
	return 0;
}

代码:  使用count()函数 

int main(void) {
	set<int> s1{10,11,12,13,14,15};

	set<int>::size_type nub = s1.count(10);  // 或者使用size_t

	cout << "10出现的个数:" << nub << endl;

	system("pause");
	return 0;
}

结果 

相关知识点 
  •  count(elem);  // 返回容器中元素elem的个数为多少?
  • 注意:  因为set中存储的各个元素不能相同,所以count只能返回0或者1。对于multiset可以大于1

4. set的元素访问(有变动)

代码:  使用迭代器

int main(void) {
	set<int> s1{10,11,12,13,14,15};

	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";    // 10 11 12 13 14 15
	}

	cout << endl;

	system("pause");
	return 0;
}
相关知识点 
  • set无法使用下标进行访问元素,所以无法使用[]和()进行访问。
  • set没有函数front()和back()函数。(可以这么理解,树形结构没有直观的先后顺序)
  • 所以set只能使用迭代器访问元素。

5. set的迭代器 

表  C++ set 容器迭代器方法
成员方法功能
begin()返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end()返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
rbegin()返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
rend()返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。通常和 rbegin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
find(val)在 set 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
lower_bound(val)返回一个指向当前 set 容器中第一个大于或等于 val 的元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
upper_bound(val)返回一个指向当前 set 容器中第一个大于 val 的元素的迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
equal_range(val)该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的值为 val 的元素(set 容器中各个元素是唯一的,因此该范围最多包含一个元素)。

注意,以上成员函数返回的迭代器,指向的只是 set 容器中存储的元素,而不再是键值对。另外,以上成员方法返回的迭代器,无论是 const 类型还是非 const 类型,都不能用于修改 set 容器中的值。

 代码

int main(void) {
	set<int> s1{10,11,12,13,14,15};

	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";    // 10 11 12 13 14 15
		//   *it = 5;          //错误操作,不能直接修改set中的元素值
	}

	system("pause");
	return 0;
}
相关知识点 

注意:   set的迭代器只能进行++,--(前置或者后置)的运算操作,==,!=的比较运算。 以及不能使用迭代器修改set中的元素值。(无论迭代器有没有const修饰)

其余操作和前面介绍的容器一样。

6. set在指定位置插入元素 

代码:使用insert()函数

int main(void) {
	set<int> s1{ 10,11,12,13,14,15 };
	set<int> s2{ 19,5 };
	vector<int> v1{ 99,100 };
	int arr[] = { 1,2,3 };

	s1.insert(s2.begin(), s2.end());
	s1.insert(arr, arr+3);
	s1.insert(v1.begin(), v1.end());
	s1.insert(4);
	// s1.insert(4, 6);  // 这样写会出错,因为set中不能有重复的元素
	s1.insert({ 6 });
	s1.insert(s1.begin(), 50);
  

	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";    // 10 11 12 13 14 15
	}

	system("pause");
	return 0;
}

结果 

相关知识点 
  • insert(elem);  // 将元素elem插入到set中去
  • insert(ptr1,ptr2) ;  // 将[ptr1,ptr2)指针指向的范围中的数据插入到set中去。(数组)
  • insert(beg,end);   // 将迭代器[beg,end)范围内的数据插入到set中去。(可以相同容器的迭代器,也可以是不同容器的)
  • insert({data...});  //  将{}中的元素插入到set中
  • insert(iter,elem);  // 将元素elem插入到set中

注意:   无论是哪种插入,在元素插入到set中时,set都会进行比较,放到合适的位置。因为set是有序的。(尽管我们指定了插入位置,但数据并不一定会放到对应位置,它会根据排序规则来确定其放在哪个位置)

insert的返回值 

情况一:
set<int> s1{1,2,3};

pair<set<int>::iterator,bool> p1 = s1.insert(5);
if (p1.second) {
	cout << *(p1.first) << endl;
}

pair<set<int>::iterator, bool>p2 = s1.insert(5);
if (!p2.second) {
	cout << "插入失败" << endl;
	cout << *(p2.first) << endl;
}
相关知识点: 

 当我们直接插入单个数据的时候,对于set会存在插入失败的情况,因为set中的元素不能重复,如果我们插入的元素在set中已经存在就会插入失败。

那么我们怎么能判断是否插入成功了呢?  

insert会给我们返回一个bool值,如果插入成功返回true,如果插入失败返回false

同时insert还会返回一个迭代器,如果插入成功迭代器指向插入元素的位置,如果插入失败迭代器指向与插入值相同的元素位置

上面代码中,我们分别展示了插入成功和插入失败的情况。

其它情况 
set<int> s1;
set<int> s2{1,2,3};

s1.insert(s2.begin(), s2.end());  // 返回void

set<int>::iterator it = s1.insert(s1.begin(),5);  // 返回指向插入元素位置的迭代器
cout << *it << endl;

s1.insert({ 10,11 });  // 返回void
  • 在指定位置插入时 (但是,由于set是有序的,所以插入的数据会根据内部数据进行位置调整,不一定会放到我们指定的位置)。
  • 如果插入成功: 返回插入元素位置的迭代器;如果插入失败: 返回与插入值相同的元素位置。 

代码:  使用emplace()和emplace_hint()函数

set<int> s1;

//  使用emplace
pair<set<int>::iterator,bool> p1 = s1.emplace();   // 插入0,返回pair类对象
if (p1.second) {
	cout << *(p1.first) << endl;
}

pair<set<int>::iterator, bool> p2 = s1.emplace(1);  // 插入1,返回pair类对象
if (p2.second) {
	cout << *(p2.first) << endl;
}

// 使用emplace_hint
set<int>::iterator it = s1.emplace_hint(s1.begin(), 10);   // 在指定位置插入10,返回指向插入元素位置的迭代器
cout << *it << endl;

结果 

相关知识点 
  •  emplace()函数和之前介绍的用法是一致的,直接在()写相应的数据(类对象的话,就写相应的构造函数参数对应的数据。其它类型的话,直接写对应的数据)

其返回值是一个pair的类对象,和insert是一样的

返回一个迭代器 -> 如果插入成功:  指向插入数据的位置; 如果插入失败:  指向和插入数据相同的元素位置。

返回bool值 ->  如果插入成功:  返回true;  如果插入失败:  返回false。

  • emplace_hint(pos,elem);  //  在pos位置插入数据elem。  (但是,由于set是有序的,所以插入的数据会根据内部数据进行位置调整,不一定会放到我们指定的位置)

其返回值是一个迭代器,如果插入成功:  指向插入数据的位置; 如果插入失败:  指向和插入数据相同的元素位置。

 7. set删除元素

代码:  使用erase()和clear() 

int main(void) {
	set<int> s1{10,11,12,13,14,15};
  
	// 用法1
	set<int>::size_type t1 = s1.erase(10);
	cout << t1 << endl;
	// 用法2
	s1.erase(s1.begin(), ++s1.begin());
	// 用法3
	s1.erase(s1.begin());

	s1.clear();  // 清空set中的元素
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	system("pause");
	return 0;
}
相关知识点 
  • erase(elem);  // 删除set列表中值为elem的元素,返回删除元素的个数。(对于set只会返回0或者1,但是multiset可能会大于1)
  • erase(pos);  // 删除对应位置中的元素, 返回删除元素下一个元素的迭代器。
  • erase(beg,end); // 删除[beg,end)范围内的元素,返回删除元素下一个元素的迭代器。
  • clear(); // 删除set容器中所有的元素。

注意:  在erase和循环结合使用的时候,应该注意删除时迭代器的指向。(在vector中详述)

8. set查找元素 

代码:  使用find()函数 

int main(void) {
	set<int> s1{10,11,12,13,14,15};
	//set<int>::const_iterator cit = s1.find(10);
	set<int>::iterator it = s1.find(10);

	if (it != s1.end()) {
		cout << *it << endl;
	}
	else {
		cout << "没有找到此元素" << endl;
	}

	system("pause");
	return 0;
}

结果 

相关知识点 
  • find(elem);  // 用于查找set中elem元素。
  • 如果此元素存在,则返回该元素位置的迭代器;如果此元素不存在,则返回最后一个元素下一位的迭代器。(和end()函数返回的迭代器一样)

所以在代码中,我们先判断find返回的迭代器和end()返回的迭代器是否相同,相同则输出元素值不相同则输出查找失败。 

代码:  lower_bound(),upper_bound(),equal_range()函数 

int main(void) {
	set<int> s1{10,11,12,13,16,17};

	// lower_bound()
	//set<int>::const_iterator it = s1.lower_bound(10);
	/*
      set<int>::iterator it = s1.lower_bound(10);
	  if (it != s1.end()) {
		cout << *it << endl; // 10
	  }
	  else {
		cout << "没有此元素" << endl;
	  }	
	*/
	set<int>::iterator it = s1.lower_bound(16);
	if (it != s1.end()) {
		cout << *it << endl; // 16
	}
	else {
		cout << "没有此元素" << endl;
	}

	// upper_bound()
	set<int>::iterator it1 = s1.upper_bound(12);
	if (it1 != s1.end()) {
		cout << *it1 << endl; // 13
	}
	else {
		cout << "没有此元素" << endl;
	}

	// equal_range()
	pair<set<int>::iterator, set<int>::iterator> p1 = s1.equal_range(10);
	for (; p1.first != p1.second; (p1.first)++) {
		cout << *(p1.first) << endl;
	}

	system("pause");
	return 0;
}

结果 

相关知识点 
  • lower_bound(elem);  // 返回set中元素>=elem的第一个元素的迭代器,如果set中没有比elem>=的元素,那么就返回最后一个元素下一个位置的迭代器。(和end()返回的一样)
  • upper_bound(elem);  // 返回set中元素>elem的第一个元素的迭代器,如果set中没有比elem>的元素,那么就返回最后一个元素下一个位置的迭代器。(和end()返回的一样)
  • equal_range(elem);  // 返回一个pair对象,内部有两个迭代器类型,第一个迭代器:  表示第一个等于elem元素的位置,第二个迭代器:  表示最后一个等于elem的下一个元素的位置。(set中因为元素不相同,所以这个范围最多包含一个元素)
  • 如果elem不存在,那么两个迭代器就都指向按照规则elem的下一个元素,(如果从小到大排列就指向第一个elem的元素)。 当然如果按照对则,elem排在最后,则两个迭代器都指向最后一个元素的下一位。(比如:  从小到大排时,elem比set中的元素都要大)

9.  set的排序规则 

我们前面说到,set是有顺序的,而且在我么插入元素,查找元素等操作中,都会根据排序规则进行相应的调整。

那set的排序规则到底是怎么样的呢? 

set内部使用的是类模板,我们定义set对象的时候,会传入一个类型参数。 其实set还有第二个类型参数,用于指定set的排序规则。(类型为什么可以指定排序规则,这是因为类内部存在一个()函数的重载,没错就是函数对象)

那为什么上面的代码中我们不需要传入第二个类型参数呢?

因为第二个类型参数,有一个默认值为less<类型>,就是内部定义的函数对象类less,其指定的规则是从小到大排序。 所以在默认情况下set是以从小到大的情况进行排序的。

当然,我们也可以自己指定排序规则

代码: 使用greater使set从大到小和自定义的函数对象排列数据

int main(void) {
	set<int> s1{10,11,12,13,16,17};

	cout << "默认情况下输出: " << endl;
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	set<int,greater<int>> s2{ 10,11,12,13,16,17 };
	cout << "greater规则下输出: " << endl;
	for (set<int>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	system("pause");
	return 0;
}

结果 

相关知识点 

代码中,我们分别使用了默认情况(less -- 从小到大排序),greater --  从大到小排序。它们打印出的顺序或者元素是不相同的。

 10. set的其它方法

方法:  swap(), empty(), max_size();  

和vector中的使用方法一样。 

11. multiset与set的函数不同之处

multiset和set的函数大多数在使用的时候都是一样的,我们就不再说明了。

但是由于multiset可以存放不同的元素所以和set会有点区别。 

区别:

  • multiset在调用erase(elem),方法时期返回值可以大于1。
  • 同理count(elem)这个函数的返回值也可以大于1。
  • ower_bound(elem)、upper_bound(elem)、equal_range(elem)其对应查找的数据范围也不再是一个,所以这些函数更加常用于multiset。

注意事项: 

  • 由于set内部是有序的,所以我们不能随便修改其内部的值,因为如果修改了某一位置的值,很可能会导致其不再是有序排列的了。所以使用迭代器(即使迭代器不是const修饰的)或者其它方式都不能对set中的元素进行修改。如果要修改,那必须将这个元素删除,然后再添加一个新元素。
  • size_type和value_type和vector的用法一样。
  • multiset是类似的。

表  C++ multiset 容器常用成员方法
成员方法功能
begin()返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end()返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
rbegin()返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
rend()返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。
find(val)在 multiset 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
lower_bound(val)返回一个指向当前 multiset 容器中第一个大于或等于 val 的元素的双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
upper_bound(val)返回一个指向当前 multiset 容器中第一个大于 val 的元素的迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
equal_range(val)该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含所有值为 val 的元素。
empty()若容器为空,则返回 true;否则 false。
size()返回当前 multiset 容器中存有元素的个数。
max_size()返回 multiset 容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。
insert()向 multiset 容器中插入元素。
erase()删除 multiset 容器中存储的指定元素。
swap()交换 2 个 multiset 容器中存储的所有元素。这意味着,操作的 2 个 multiset 容器的类型必须相同。
clear()清空 multiset 容器中所有的元素,即令 multiset 容器的 size() 为 0。
emplace()在当前 multiset 容器中的指定位置直接构造新元素。其效果和 insert() 一样,但效率更高。
emplace_hint()本质上和 emplace() 在 multiset 容器中构造新元素的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示新元素生成位置的迭代器,并作为该方法的第一个参数。
count(val)在当前 multiset 容器中,查找值为 val 的元素的个数,并返回。

注意,虽然 multiset 容器和 set 容器拥有的成员方法完全相同,但由于 multiset 容器允许存储多个值相同的元素,因此诸如 count()、find()、lower_bound()、upper_bound()、equal_range()等方法,更常用于 multiset 容器。

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

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

相关文章

【算法】双指针的应用

文章目录 前言1. 移动零&#xff08;easy&#xff09;2. 复写零&#xff08;easy&#xff09;3. 快乐数&#xff08;medium&#xff09;4. 盛水最多的容器&#xff08;medium&#xff09;5. 有效三角形的个数&#xff08;medium&#xff09;6.和为 s 的两个数字&#xff08;eas…

机器学习 - 准备数据

“Data” in machine learning can be almost anything you can imagine. A table of big Excel spreadsheet, images, videos, audio files, text and more. 机器学习其实可以分为两部分 将不管是什么data&#xff0c;都转成numbers.挑选或者建立一个模型来学习这些numbers …

json字符串的数据提取

json的数据提取 学习目标 掌握 json相关的方法(load loads dump dumps)了解 jsonpath的使用(提取 json中的数据) 2 复习什么是json JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和…

高效文件管理,批量复制文件夹名称 ,轻松提升工作效率

在信息爆炸的时代&#xff0c;电脑中的文件夹数量与日俱增&#xff0c;管理和整理这些文件夹成为一项繁琐的任务。您是否曾因为需要复制大量文件夹的名称而感到苦恼&#xff1f;现在&#xff0c;我们为您带来了一款能够一键批量复制文件夹名称的神奇工具&#xff0c;让您的效率…

【C语言进阶篇】自定义类型:结构体(下)

【C语言进阶篇】自定义类型&#xff1a;结构体&#xff08;下&#xff09; &#x1f308;个人主页&#xff1a;开敲-CSDN博客 &#x1f525;所属专栏&#xff1a;C语言_开敲的博客-CSDN博客 &#x1f33c;文章目录&#x1f33c; 1. 结构体传参 2. 结构体实现位段 2.1 什么是…

【CSS】html滚动条相关

1.滚动条样式 ::-webkit-scrollbar {width: 10px;height: 10px;z-index: 101; } ::-webkit-scrollbar-thumb {border-radius: 5px;background: #cecece; } ::-webkit-scrollbar-track {// background: #f5f5f5be;background: rgba(33, 85, 163, 0); } ::-webkit-scrollbar-but…

mysql - 多表访问

多表访问 创建两个表 mysql> SELECT * FROM t1; ------------ | m1 | n1 | ------------ | 1 | a | | 2 | b | | 3 | c | ------------ 3 rows in set (0.00 sec)mysql> SELECT * FROM t2; ------------ | m2 | n2 | ------------ | 2 | …

IP地址的分配:数字世界的地址规划者

在互联网的世界里&#xff0c;IP地址扮演着类似于房屋地址的角色&#xff0c;是用于标识和定位互联网上每个连接到网络的设备的唯一标识符。然而&#xff0c;这些IP地址并非随意分配&#xff0c;而是经过精心规划和管理的。本文将探讨IP地址的分配方式&#xff0c;揭示数字世界…

婴儿洗衣机十大排名名牌:十款超高价值婴儿洗衣机综合整理

我们都知道宝宝的皮肤是超级娇嫩的&#xff0c;宝宝的衣物也一样&#xff0c;宝宝的衣物大部分都是纯棉的。如果将宝宝的衣物和大人衣服一起扔进大型洗衣机混洗&#xff0c;更可能出现细菌交叉感染&#xff0c;对小宝宝来说百害而无一利&#xff0c;会让小宝宝肌肤过敏、红肿、…

有关Theano和PyTensor库

根据Github里面的介绍&#xff0c;PyTensor是源于Theano&#xff0c; Theano目前应该已经不再开发了&#xff0c;更新都是很多年前。 因此PyTensor在背景介绍中说 PyTensor is a fork of Aesara, which is a fork of Theano. Theano和PyTensor都是计算相关的库&#xff0c;可以…

【C语言】结构体类型名、变量名以及typedef

文章目录 分类判断结构体成员的使用typedef 分类判断 struct tag {char m;int i; }p;假设定义了上面这一个结构体&#xff0c;tag 就是类型名&#xff0c; p 就是变量名&#xff0c; m 和 i 就是结构体成员列表。 可以这么记&#xff0c;括号前面的是类型名&#xff0c;括号后…

2024年超声波清洗机选购攻略,高性价超声波清洗机推荐,看这篇就够

随着科技的飞速发展和生活品质的逐步提升&#xff0c;超声波清洗机已经成为了现代家庭不可或缺的清洁工具。它以独特的超声波清洁技术&#xff0c;能够深入物品的微小缝隙&#xff0c;有效去除污垢和细菌&#xff0c;为用户提供一种安全、高效且环保的清洁解决方案。2024年&…

处理器方法的参数

处理器方法的参数&#xff1a; 处理器方法可以包含以下四类参数&#xff0c;这些参数会在系统调用时由系统自动赋值&#xff0c;即程序员可在方法内直接使用: HttpServletRequestHttpServletResponseHttpSession请求中所携带的请求参数 控制器方法&#xff1a; 前面三个参数怎…

Android 系统源码快速入门

Android源码快速入门 今天分享的内容是Android源码快速入门&#xff0c;主要分为以下几个步骤&#xff1a; * 硬件要求 * 虚拟机安装 * 开发环境搭建 * 下载编译源码 * 从一个简单的实际开发需求体验 Framework 开发硬件要求 用于 Android Framework 开发的电脑需要较强的 C…

黑平台避雷!3月上半月FX110曝光68家,无监管成常态

黑平台层出不穷&#xff0c;反诈骗是一场长期的斗争。以半个月为周期&#xff0c;FX110网对虚假交易商进行常态化曝光&#xff0c;极力压缩黑平台的生存空间&#xff0c;减少骗局的发生。 3月上半月&#xff0c;FX110网再曝光黑平台68家&#xff0c;此次曝光的黑平台大都对监管…

深入探究process.env.NODE_ENV如何区分环境

公众号&#xff1a;程序员白特&#xff0c;欢迎一起学习交流~ 通常我们在开发中需要区分当前代码的运行环境是dev、test、prod环境&#xff0c;以便我们进行相对应的项目配置&#xff0c;比如是否开启sourceMap&#xff0c;api地址切换等。 而我们区分环境一般都是通过process.…

02_设计模式

文章目录 设计模式设计模式分类UML类图设计模式的原则 常用设计模式创建型设计模式单例设计模式饿汉模式懒汉模式&#xff08;线程不安全&#xff09;懒汉模式&#xff08;线程安全&#xff09;- Synchronized懒汉模式&#xff08;线程安全&#xff09;- Double Check懒汉模式&…

mysql不等于<>取特定值反向条件的时候字段有null值或空值读取不到数据

#小李子9479# 有如下的数据结构 &#xff0c;st_dl tinyint(4)&#xff0c;想从中读取不等于1的数据 于是写了一个sql语句 select * from tbname where st_dl<>1 返回数据为0。 修改一下 select * from tbname where IFNULL(st_dl,0)<>1 正确返回数据 IFNUL…

【深度学习与神经网络】MNIST手写数字识别1

简单的全连接层 导入相应库 import torch import numpy as np from torch import nn,optim from torch.autograd import Variable import matplotlib.pyplot as plt from torchvision import datasets, transforms from torch.utils.data import DataLoader读入数据并转为ten…

深度学习之本地部署大模型ChatGLM3-6B【大模型】【报错】

文章目录 0.前言1.模型下载2.配置环境2.1 下载项目文件2.2 配置环境 3.开始推理4.总结 0.前言 本博客将介绍ChatGLM3-6B大模型在Ubuntu上的本地部署教程 1.模型下载 由于毛毛张的服务器服务无法科学上网&#xff0c;所以模型的相关文件必须现在本地下载好&#xff0c;再上传到…