C++之set和map的运用

【C++标准模板库】一些函数的用法(vector、set、map) 变长数组”,相当于一维数组,长度根据需要而自动改变的数组。(大部分STL都是这样定义)在头文件下方要添加(都要加)typename也是一个STL容器,可以是任何的基本类型。1、在vector后面加上一个元素x,时间复杂度:O(1);2、删除vector的尾元素,时间复杂度:O(1);1、,vector本身可以作为数组使用,在一些元素个数不确定的场合可以很好的节省空间。有些场合需要根据一些条件把部分数据输出在同一行,数据中间用空格隔开。 阅读详情

目录

序列式容器和关联式容器

熟识set

在STL中的底层结构:

set的构造和迭代器

set的增删查

multiset和set的差异

练习题:

熟识map

map类的介绍

pair类型介绍

map的构造

map的增删查

map的数据修改

测试样例:

multimap和map的差异

练习


序列式容器和关联式容器

前⾯我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,⽐如交换⼀下,他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。

关联式容器也是⽤来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是⾮线性结构,两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。


本章节讲解的map和set底层是红⿊树,红⿊树是⼀颗平衡⼆叉搜索树。set是key搜索场景的结构,map是key/value搜索场景的结构。

熟识set

在STL中的底层结构:

set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数。

set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参数。 ⼀般情况下,我们都不需要传后两个模版参数。
 set底层是⽤红⿊树实现,增删查效率是 O(logN) ,迭代器遍历是⾛的搜索树的中序,所以是有序的。

set的构造和迭代器

⽀持迭代器就意味着⽀持范围for,set的iterator和const_iterator都不⽀持迭代器修改数据,修改
关键字数据,破坏了底层搜索树的结构。set迭代器是一个双向迭代器(支持的操作:*(解引用)、++(递增)、--(递减)、==和!=(比较))。

set的构造我们关注以下⼏个接⼝即可。

// empty (1) ⽆参默认构造
explicit set (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
set (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());
// copy (3) 拷⻉构造
set (const set& x);
// initializer list (5) initializer 列表构造
set (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// 迭代器是⼀个双向迭代器
iterator
-> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

测试用例: 

void test_set()
{
	//无参默认构造
	set<int> s1;
	//迭代器区间构造
	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
	v1.push_back(i);
	}
	set<int> s2(v1.begin(), v1.end());
	for (auto& e : s2)
	{
		cout << e<<' ';
	}
	cout << endl;
	//拷贝构造
	set<int> s3(s2);
	for (auto& e : s3)
	{
		cout << e <<' ';
	}
	cout << endl;
	//列表构造
	set<int> s4({ 4,5,6,7,8 });
	for (auto& e : s4)
	{
		cout << e << ' ';
	}
	cout << endl;
}

set的增删查

set的增删查关注以下⼏个接⼝即可:

Member types
key_type
-> The first template parameter (T)
value_type -> The first template parameter (T)
// 单个数据插⼊,如果已经存在则插⼊失败
pair<iterator,bool> insert (const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
// 查找val,返回val所在的迭代器,没有找到返回end()
iterator find (const value_type& val);
// 查找val,返回Val的个数
size_type count (const value_type& val) const;
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);
// 删除val,val不存在返回0,存在返回1
size_type erase (const value_type& val);
// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
// 返回大于等于val位置的迭代器
iterator lower_bound (const value_type& val) const;
// 返回小于val位置的迭代器
iterator upper_bound (const value_type& val) const;

测试用例:

void test_set()
{	
    int a[] = { 3,1,4,6,7,9,2,5,9,5,1 };
	set<int> s1;
	for(auto& e:a)
	{
		//单个数据插入
		s1.insert(e);
    }
	for (auto& e : s1)
	{
		cout << e << ' ';
	}
	cout << endl;
	 set<int>s2;
	 //列表插入
	 s2.insert({ 3,1,4,6,7,9,2,5,9,5,1 });
	 for (auto& e : s1)
	 {
		 cout << e << ' ';
	 }
	 cout << endl;
	 vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
	v1.push_back(i);
	}
	set<int>s3;
	//迭代器区间插入
	//s3.insert(v1.begin(), v1.end());
	s3.insert(s1.begin(), s1.end());
	for (auto& e : s3)
	{
		cout << e << ' ';
	}
	cout << endl;
	auto it = s1.lower_bound(2);
	auto it1 = s1.upper_bound(5);
	//删除大于等于2小于等于5的区间
	s1.erase(it, it1);
	for (auto& e : s1)
	{
		cout << e << ' ';
	}
	cout << endl;
	//find
	//用算法库寻找O(N)
	auto pos1=find(s1.begin(), s1.end(), 9);
	//用set的成员函数寻找O(logN)
	auto pos2=s1.find(9);
	//利用count快速寻找
	int x;
	//set不冗余,所以即使有相同的,在s1中存在的个数都为1
	cin >>x ;
	if (s1.count(x))
	{
		cout << "在" << endl;
	}
	else
	{
		cout << "不在" << endl;
	}
}

multiset和set的差异

multiset和set的使⽤基本完全类似,主要区别点在于multiset⽀持值冗余,那么
insert/find/count/erase都围绕着⽀持值冗余有所差异,具体参看下⾯的样例代码理解。

#include<iostream>
#include<set>
using namespace std;
int main()
{
// 相⽐set不同的是,multiset是排序,但是不去重
multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };
auto it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
// 相⽐set不同的是,x可能会存在多个,find查找中序的第⼀个
int x;
cin >> x;
auto pos = s.find(x);
while (pos != s.end() && *pos == x)
{
cout << *pos << " ";
++pos;
}
cout << endl;
// 相⽐set不同的是,count会返回x的实际个数
cout << s.count(x) << endl;
// 相⽐set不同的是,erase给值时会删除所有的x
s.erase(x);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
return 0;
}

练习题:

349. 两个数组的交集

思路:先让两个数组用set排序,再去遍历两个对象中的数据,如果第一个对象中的数比第二个对象中的数据要大,那么这时候我们就要让第二个对象向后走;同理,如果第一个对象中的数比第二个对象中的数据要小,那么这时候我们就要让第一个对象向后走;如果相同我们就尾插进vector对象中,同时记得set对象同时都要向后走。

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> v1;
        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{
                v1.push_back(*it1);
                it1++;
                it2++;
            }
        }
        return v1;
    }
};

142. 环形链表 II

当时在学习数据结构的时候我们也遇到过这道题,当时我们运用了快慢指针,即快指针走三步,而慢指针走一步。

但今天我们学习了set,就可以轻松解决这道题。在上面学习count成员函数的时候,我们可以直接用count来查找val是否存在。

思路:定义一个存放节点指针的对象,对链表进行循环的过程中用count成员函数检查set中是否存在节点,如果没有就插入进对象中,如果有就返回该节点(进入环的节点)。如果遍历完了链表还没有找到,那么就是单链表,不存在环,返回nullptr。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        set<ListNode*>s1;
        ListNode*cur=head;
        while(cur)
        {
            if(s1.count(cur))
            {
                return cur;
            }
            s1.insert(cur);
            cur=cur->next;
        }
        return nullptr;
    }
};

熟识map

map类的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key⽀持⼩于⽐较,如果不⽀持或者需要的话可以⾃⾏实现仿函数传给第⼆个模版参数,map底层存储数据的内存是从空间配置器申请的。⼀般情况下,我们都不需要传后两个模版参数。map底层是⽤红⿊树实现,增删查改效率是 O(logN) ,迭代器遍历是⾛的中序,所以是按key有序顺序遍历的。

pair类型介绍

map底层的红⿊树节点中的数据,使⽤pair<Key, T>存储键值对数据。 

typedef pair<const Key, T> value_type;
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)
{}
template<class U, class V>
pair (const pair<U,V>& pr): first(pr.first), second(pr.second)
{}
};
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair<T1,T2>(x,y) );
}

map的构造

map的⽀持正向和反向迭代遍历,遍历默认按key的升序顺序,因为底层是⼆叉搜索树,迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for,map⽀持修改value数据,不⽀持修改key数据,修改关键字数据,破坏了底层搜索树的结构。//pair(key,value)

// empty (1) ⽆参默认构造
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
map (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());
// copy (3) 拷⻉构造
map (const map& x);
// initializer list (5) initializer 列表构造
map (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// 迭代器是⼀个双向迭代器
iterator
-> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

map的增删查

map接⼝,插⼊的pair键值对数据,跟set所有不同,但是查和删的接⼝只⽤关键字key跟set是完全类似的,不过find返回iterator,不仅仅可以确认key在不在,还找到key映射的value,同时通过迭代还可以修改value.

Member types
key_type
-> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type
-> pair<const key_type,mapped_type>
// 单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败
pair<iterator,bool> insert (const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
// 查找k,返回k所在的迭代器,没有找到返回end()
iterator find (const key_type& k);
// 查找k,返回k的个数
size_type count (const key_type& k) const;
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);
// 删除k,k存在返回0,存在返回1
size_type erase (const key_type& k);
// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
// 返回⼤于等k位置的迭代器
iterator lower_bound (const key_type& k);
// 返回⼤于k位置的迭代器
const_iterator lower_bound (const key_type& k) const;

map的数据修改

map第⼀个⽀持修改的⽅式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map还有⼀个⾮常重要的修改接⼝operator[],但是operator[]不仅仅⽀持修改,还⽀持插⼊数据和查找数据,所以他是⼀个多功能复合接⼝.
需要注意从内部实现⻆度,map这⾥把我们传统说的value值,给的是T类型,typedef为
mapped_type。⽽value_type是红⿊树结点中存储的pair键值对值。⽇常使⽤我们还是习惯将这⾥的T映射值叫做value。

Member types
key_type
-> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type
-> pair<const key_type,mapped_type>
// 查找k,返回k所在的迭代器,没有找到返回end(),
//如果找到了通过iterator可以修改key对应mapped_type值
iterator find (const key_type& k);
// ⽂档中对insert返回值的说明
// insert插⼊⼀个pair<key, T>对象
// 1、如果key已经在map中,插⼊失败,则返回⼀个pair<iterator,bool>对象,返回pair对象
first是key所在结点的迭代器,second是false
// 2、如果key不在在map中,插⼊成功,则返回⼀个pair<iterator,bool>对象,返回pair对象
first是新插⼊key所在结点的迭代器,second是true
// 也就是说⽆论插⼊成功还是失败,返回pair<iterator,bool>对象的first都会指向key所在的迭
代器
// 那么也就意味着insert插⼊失败时充当了查找的功能,正是因为这⼀点,insert可以⽤来实现
operator[]
// 需要注意的是这⾥有两个pair,不要混淆了,⼀个是map底层红⿊树节点中存的pair<key, T>,另
⼀个是insert返回值pair<iterator,bool>
pair<iterator,bool> insert (const value_type& val);
mapped_type& operator[] (const key_type& k);
// operator的内部实现
mapped_type& operator[] (const key_type& k)
{
// 1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储
mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊+修改功能
// 2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的
迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能
pair<iterator, bool> ret = insert({ k, mapped_type() });
iterator it = ret.first;
return it->second;
}

测试样例:

void  map_test()
{
	map<string, string>dict;
	dict.insert(make_pair ("sort", "排序"));
	dict.insert({ "left","左边" });
	dict.insert(pair<string, string>("second", "第二"));
	pair<string, string>kv("right", "右边");
	dict.insert(kv);
	//插入失败,冗余了
	dict.insert({ "left","左边,剩余" });
	auto it = dict. begin();
	while (it != dict.end())
	{
		cout << it->first << "->" << it->second<<endl;
		it++;
	}
	cout << endl;
	for (auto& e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
	string str;
	while (cin >> str)
	{
		auto ret = dict.find(str);
		if (ret != dict.end())
		{
			cout << "找到了" << endl;
		}
		else
			cout << "没找到" << endl;
	}
	
}
void map_test1()
{
	//测试迭代器和[]运算符的使用
	string arr[] = { "苹果", "西⽠", "苹果", "西⽠", "苹果", "苹果", "西⽠",
"苹果", "⾹蕉", "苹果", "⾹蕉" };
	map<string, int> countMap;
	/*for (auto& e : arr)
	{
		auto ret = countMap.find(e);
		if (ret != countMap.end())
		{
			ret->second++;
		}
		else
		{
			countMap.insert({ e,1 });
		}
	}
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;*/
	//[]的用法
	//1.插入
	map<string, string> dict;
	dict["left"];
	//2.修改
	dict["right"] = "右边";
	dict["right"] = "右边,向右";
		//3.插入加修改
	dict["sort"] = "排序";
	for (auto& e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
	//上面的countMap可以运用[]计算个数
	for (auto& e : arr)
	{
		countMap[e]++;
	}
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
}
int main()
{
	//map_test();
	map_test1();
	return 0;
}

multimap和map的差异

multimap和map的使⽤基本完全类似,主要区别点在于multimap⽀持关键值key冗余,那么
insert/find/count/erase都围绕着⽀持关键值key冗余有所差异,这⾥跟set和multiset完全⼀样,⽐如find时,有多个key,返回中序第⼀个。其次就是multimap不⽀持[],因为⽀持key冗余,[]就只能⽀持插⼊了,不能⽀持修改。

void multimap_test()
{
	multimap<string, string> dict;
	dict.insert({ "left","左边" });
	dict.insert({ "left","剩余" });
	for (auto& e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
	//dict["left"] = "激进分子";//报错,multimap中[]不能修改value值。
}
int main()
{
	multimap_test();
	return 0;
}

练习

138.随机链表的复制

在之前我们用C语言写这道题的时候,代码要敲很多,今天我们学习了map,就可以用map类轻松解决。

思路:我们建立一个map对象,pair中放两个节点的指针,当我们在遍历链表的时候,让新链表和原链表构成映射关系。(新链表和原链表有着一一对应的关系,可以通过原链表的节点就可以找到新链表的节点,且节点内容相同)

1.遍历链表。往新链表中插入节点,并让新链表的节点和原链表的节点构成映射关系。

2.处理random。在重新遍历数组,让新链表中的节点的random成员等于原链表中的节点的random。

class Solution {
public:
    Node* copyRandomList(Node* head) {
        //先复制单链表
        Node*cur=head;
        map<Node*,Node*>copyNode;
        Node*copyhead=nullptr;
        Node*copytail=nullptr;
        while(cur)
        {
            if(copyhead==nullptr)
            {
                copyhead=copytail=new Node(cur->val);
            }
            else
            {
                copytail->next=new Node(cur->val);
                copytail=copytail->next;
            }
            copyNode[cur]=copytail;//成映射关系
            cur=cur->next;
        }
        //复制
        cur=head;
        Node*pre=copyhead;
        while(cur)
        {
            if(cur->random==nullptr)
            {
                pre->random=nullptr;
            }
            else
            {
                pre->random=copyNode[cur->random];//不可pre->random=cur->random,
//指向的地址不一样,相当于pre节点的random指针指向了原链表,不是指向新链表。
            }
            cur=cur->next;
            pre=pre->next;
        }
        return copyhead;
    }
};

692. 前K个⾼频单词 - ⼒扣(LeetCode)
题目中让我们按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。在排序之前我们应该对数组中的字符串进行统计个数,然后才能按照它的要求排序。

该题有三种排序思路:

1.运用算法库中的sort函数进行排序。sort函数是运用快排的思想,是不稳定的,所以在仿函数的时候我们不仅要比较字典顺序还要比较出现频率。

2.运用stable_sort函数进行排序。在插入map对象的时候,map对象里的字符串都已经按照字典顺序进行排序了,而stable_sort函数具有稳定性,那么在仿函数中我们只需要比较出现的频率就可以了。

3.运用priority_queue容器适配器进行建大堆实现。在前面的学习中我们就了解到priority_queue是优先级队列,每个元素都会有一个优先级概念,会按照固定的顺序定义。 在C++ STL中,默认情况下,优先级队列(priority_queue)的首元素始终是最大的元素。

思路1:

class Solution {
public:
struct compare
{
    bool operator()(pair<string,int> v1,pair<string,int>v2)
    {
        return (v1.second==v2.second&&v1.first<v2.first)||v1.second>v2.second;
    }
};
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int>mapsort;
        for(auto&e:words)
        {
            mapsort[e]++;
        }
        vector<pair<string,int>>v(mapsort.begin(),mapsort.end());
        sort(v.begin(),v.end(),compare());
        vector<string>v1;
        for(int i=0;i<k;i++)
        {
            v1.push_back(v[i].first);
        }
        return v1;
    }
};

思路2:

class Solution {
public:
struct compare
{
    bool operator()(pair<string,int> v1,pair<string,int>v2)
    {
        return v1.second>v2.second;
    }
};
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int>mapsort;
        for(auto&e:words)
        {
            mapsort[e]++;
        }
        vector<pair<string,int>>v(mapsort.begin(),mapsort.end());
        stable_sort(v.begin(),v.end(),compare());
        vector<string>v1;
        for(int i=0;i<k;i++)
        {
            v1.push_back(v[i].first);
        }
        return v1;
    }
};

思路3:

class Solution {
public:
struct compare
{
    bool operator()(pair<string,int> v1,pair<string,int>v2)
    {
        //要注意优先级队列底层是反的,⼤堆要实现⼩于⽐较,所以这⾥次数相等,想要字典
        //序⼩的在前⾯,要⽐较字典序⼤的为真
        return (v1.second==v2.second&&v1.first>v2.first)||v1.second<v2.second;
    }
};
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int>mapsort;
        for(auto&e:words)
        {
            mapsort[e]++;
        }
        //创建一个优先队列 p,其元素类型是 pair<string, int>。
        //使用 vector<pair<string, int>> 作为底层容器。
        //使用自定义的比较函数 Compare 来确定元素的优先级顺序。
        //将 mapsort 中的所有键值对初始化到优先队列 p 中,并按照 Compare 的规则进行排序。
        priority_queue<pair<string,int>,vector<pair<string,int>>,compare>p(mapsort.begin(),mapsort.end());
        vector<string>v1;
        for(int i=0;i<k;i++)
        {
            v1.push_back(p.top().first);
            p.pop();
        }
        return v1;
    }
};

【鸿蒙游戏上架审核规范指南】 华为鸿蒙游戏上架审核规范指南摘要 阅读详情

相关推荐

数字IC后端设计实战:从floorplan到powerplan的优化策略

本文深入探讨了数字IC后端设计中从Floorplan到Powerplan的核心优化策略。文章强调了Floorplan作为布局基础的重要性,并详细解析了Powerplan规划,特别是针对低功耗设计中MTCMOS的应用与IR Drop分析。通过实战经验分享,提供了从模块摆放到电源网络构建、再到IR Drop问题层层递进的解决方案,旨在帮助后端工程师构建稳健高效的芯片物理设计。

weixin_28338005的博客 349

【C++】 --如何运用map和set?他们的区别是什么?

前言 我们知道C++的STL库,不只是向我们提供了vector,string,list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和数据结构操作。vector封装了数组,list封装了链表,map和set封装了二叉树,在这些容器中,都会提供基础的操作:增加,删除,排序,查找等。 1、set map和set都是关联性容器,他的特点是增加或者删除对迭代器的影响都很小,除了操作的节点,对其...

Vicky_Cr的博客 1339

微信小程序获取用户手机号全流程实战(附完整代码)

本文详细介绍了微信小程序获取用户手机号的全流程实战,包括前端授权、后端解密及安全合规要点。通过传统授权按钮和新版手机号快速验证组件两种方案,帮助开发者高效实现功能,并附完整代码示例。重点解析了微信小程序接口的使用技巧和常见问题解决方案,确保数据安全与用户体验。

weixin_29280219的博客 568

C++ 11中unordered_set和unordered_map简单介绍和运用

C++STL中的hash数据结构 ——unordered_set 参考链接 leetcode题目推荐 用于存放hash散列,其搜索插入移除通常为常数时间,其原理是声明一个有n个桶的数据结构 特点: unordered_set为一种容器,以不特定的顺序存储唯一元素,可根据值检索 unordered_set中,元素的值同时事唯一标识它的键,键不可变,只可以增删。 在内部,unordered_set中的元素没有按照任何特定的顺序排序,而是根据它们的散列值组织成桶(一个线性链表代表一个桶),从而允许通过它们的值直

小雨的分享斋 4557

Web自动化神操作:如何用OpenCV 破解滑块验证码?

验证码作为一种安全机制,可以有效防止暴力破解密码、发帖、灌水、刷票等,大家在做 Web 自动化的时候应该有碰到验证码这个难题,一般我们可以和开发沟通请求他们的帮助:去掉验证码或者设置一个万能验证码,而如果开发不帮忙我们该如何去解决呢? 本篇文章以 Java 语言为例教你怎么破解验证码。 现在大多数网址会采用滑块验证码的方式,下面以腾讯的滑块验证码为例,先来看看破解的效果: 要破解滑块验证码,我们一般采取的思路如下: 获取滑块到背景缺口图的距离 通过 selenium 的 Actio

不喝枸杞的程序员 2036

滑模控制实战:用Python从零实现SMC算法(附完整代码)

本文通过Python实战,从零详解滑模控制(SMC)算法的核心原理与代码实现。文章聚焦于一阶系统,使用NumPy和Matplotlib逐步构建控制器,并针对SMC固有的抖振问题,详细讲解了边界层法的原理与实现,提供了完整的代码和参数调优指南,帮助读者直观理解并掌握这一鲁棒性极强的非线性控制方法。

weixin_29285605的博客 465

《C++进阶之STL》【set/map 使用介绍】

摘要: 本文是C++ STL系列教程的一部分,主要介绍关联容器set和map的使用方法。文章首先对比了序列容器和关联容器的核心特征差异,强调关联容器基于键值访问元素的非线性结构特点。随后详细讲解了set容器的模板参数、构造方式及常用操作接口,包括元素插入、删除、查找等成员函数的使用示例。文章采用轻松活泼的语言风格,通过比喻和示例代码帮助读者理解set/map容器的核心概念和实用技巧,为后续深入学习STL容器奠定基础。

序属秋秋秋的博客 1895

Sony SLVS-EC接口实战:如何用Xilinx K7 FPGA接收IMX421传感器数据(附电气特性匹配技巧)

本文详细介绍了在Xilinx Kintex-7 FPGA平台上实现Sony IMX421图像传感器SLVS-EC接口数据接收的完整实战方案。内容涵盖从硬件选型、PCB布局的电气特性匹配技巧,到FPGA内部GTX收发器配置、多通道绑定以及SLVS-EC协议数据解析与图像重组的关键步骤,为高速视觉系统开发提供了宝贵的调试经验和系统集成指导。

efc12345678的博客 264

map和set的使用

我们需要熟悉set/multiset和map/multiset并且能够运用得当:主要弄清楚容器中的迭代器的使用和注意事项;新名词如"pair"的意义;能够利用容器常见的接口,能对其进行增删查;能够了解multiset、multimap与set、map的区别,能能够分辨清楚multi的冗余在其中起到什么不同作用.

Frenemy__的博客 985

Axure RP9.0 教程:左侧菜单列表导航 ( 点击父级菜单,子菜单自动收缩或展开)【响应式的菜单导航】

1. 设置目标原件时,选择切换,这样就可以实现,当原件展示时,点击自动隐藏,隐藏时自动显示; 2. 展开/收起原件(推动/拉动原件)设置为方向**向下**

专注于计算机研发知识和资讯分享 1380

《嵌入式-STM32开发指南》第三部分 外设篇 - 第2章 温度传感器DS18B20

2.1 理论分析 2.1.1概述 DS18B20 是 DALLAS 最新单线数字温度传感器,新的"一线器件"体积更小、适用电压更宽、更经济。Dallas 半导体公司的数字化温度传感器 DS1820 是世界上第一片支持 "一线总线"接口的温度传感器。 DS18B20采用的单总线协议,也就是只需占用主机一个I/O口,无需其他外围电路,直接将环境温度转换为数字信号,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。另外,以"一线总线"的数字方式传输,大大提高了系统的抗干扰性。适合于恶劣环境的现场温度测量

不问归期的博客 8305

【C++】论如何封装红黑树模拟实现set和map

本文基于红黑树实现STL中的set和map容器。首先分析STL源码,发现set和map通过红黑树实现,其中set存储key类型,map存储pair<key,value>类型。在红黑树实现中引入Key_Of_T仿函数解决不同类型数据比较问题:set直接返回key,map返回pair的first成员。文章详细展示了红黑树节点的定义、插入操作及旋转平衡处理。通过模板参数K、T和Key_Of_T实现泛型编程,使同一红黑树能同时支持set和map的存储需求,为后续实现迭代器和map的[]操作符重载奠定基础

记录我一步步的学习历程,期待无限进步,向星举目! 2144

MATLAB计算各种复合干热指数,如SDHI、DHMI等

MATLAB编程实现各种复合干热指数

WW、forever的博客 5079

c++进阶之----set和map

在C++中,std::map是一个非常强大的容器,属于标准模板库(STL)的一部分。它是一个基于红黑树实现的关联容器,用于存储键值对(key-value),并且保证键的唯一性。在C++中,std::pair是一个非常实用的模板类,用于将两个不同类型的数据组合在一起。它属于标准模板库(STL)的一部分,通常用于需要同时处理两个相关数据的场景。std::pairfirst:存储第一个数据。second:存储第二个数据。std::map的[]运算符是一种非常重要的成员函数,用于访问或插入元素。1)如果key。

2401_85878549的博客 1328

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C++容器map和set使用

pair就是存放两个不同数据类型的结构体。pair就是一个模板map的[ ]可以说专为计数而生。模拟实现这个[ ]就是返回对应的value就可以了。

qq_45849625的博客 456

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

C++ - map 和 set的 例题

本博客在 一下文章关于 map 和 set 讲解之下,对 map 当中的 operator[] ()函数的功能运用,感受 map 功能强大。

chihiro1122的博客 866

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

STL模板 map set的使用和模拟实现

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息T1 first;T2 second;{}{}我们从上述的定义可以看出来,这里的pair就是键值对<first,second>的标志,同时键值对的本质是一个类,因此我们访问键值对的数据的时候,就可以按照访问类的成员那样访问即可。

hbw040115的博客 929

C++:set和map

map的插入后,不论成功与否,都会返回一个pair<iterator, bool>,iterator用于指向key的迭代器,bool用于标识插入是否成功。而map的节点是pair<key, value>,所以我们解引用得到了一个pair,随后通过( ).second访问pair<key, value>的second,也就是value。它是基于红黑树实现的,它可以存储不重复的元素,并且会自动按照元素的大小进行排序。中的每个元素都由一个键和一个与之关联的值组成,键和值可以是任意类型。的类型)来调用默认构造。

m0_61088872的博客 1132

【STL详解 —— map和set的使用】

set是按照一定次序存储元素的容器。默认情况下,std::set 使用 std::less 作为比较函数,这意味着它会使用小于运算符(

jokr_的博客 1289

【C++】:STL详解 —— 红黑树封装map和set

那能不能不要红黑树的第一个模板参数,只保留第二个模板参数呢? 乍眼一看好像是可以的,因为此时红黑树的第二个模板参数当中也是有键值Key的,但实际上红黑树的第一个模板参数是不能省略的。 对于set容器来说,省略红黑树的第一个参数当然没问题,因为set传入红黑树的第二个参数与第一个参数是一样的。但是对于map容器来说就不行了,因为map容器所提供的接口当中有些是只要求给出键值Key的,比如find和erase。

元清的博客 423

C++容器完全指南:掌握set和map的使用

include // 包含pair的头文件 // 创建pair的几种方式 std::pair<int, double> p1;// 默认构造,两个元素被值初始化 std::pair<int, double> p2(1, 3.14);// 直接初始化 std::pair<int, double> p3 = {2, 2.718};// 列表初始化(C++11起) auto p4 = std::make_pair(3, 1.618);// 使用make_pair辅助函数。

m0_74823364的博客 803

map与set

7-11 悄悄关注(25 分) 新浪微博上有个“悄悄关注”,一个用户悄悄关注的人,不出现在这个用户的关注列表上,但系统会推送其悄悄关注的人发表的微博给该用户。现在我们来做一回网络侦探,根据某人的关注列表和其对其他用户的点赞情况,扒出有可能被其悄悄关注的人。 输入格式: 输入首先在第一行给出某用户的关注列表,格式如下: 人数N 用户1 用户2 …… 用户N 其中N是不超过

逆水行舟 不进则退 571

【15】map、set、unordered_map、unordered_set

map、set、unordered_map、unordered_set在C++中使用频率较高的几种数据存储结构,因此,熟练掌握其基本的方法对于深入学习C++就先得尤为重要 1、map 2、set 3、unordered_map 4、unordered_set

Utotao的博客 291

map , multimap , set , multiset的用法

先介绍一下pair的用法 pair类型等价于: struct { T1 first; T2 second; }; 例如 pair a; 等价于 struct { int first; double second; }a; a.first = 1; a.second = 93.33; 会发现,其实这四种都是利用二叉平衡树实现的(AVL), multi

mazicwong的博客 433

set ,map 容器

前一阵自学深度学习,很有没有回来写博客了,编程不能扔,所以继续写,最近参加编程的网站答题,发现自己太菜了,根本不会,脑袋转不过来,真的觉得自己太low了,所以还需要从底层来。还是老套路从题目中看代码。 给一个数据表 输入 The first line contains an integer N denoting the number of lists. (1

weixin_35650592的博客 208

C++ 关联式容器完全指南:set和map的深度掌握之旅

C++关联容器指南:set和map核心要点

先做,然后做对,最后做得更好。学习就是为了自由呀,当你学会了怎么学习,想要学什么就学什么,需要什么就学什么,你就自由了。 2052
上一篇: C++之红黑树
下一篇: Linux权限
噜啦噜啦嘞好
博客等级 码龄3年 212粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值