IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> set和map的使用 -> 正文阅读

[数据结构与算法]set和map的使用

1. 关联式容器

在初阶阶段,我们已经接触过 STL 中的部分容器,比如: vector list deque forward_list(C++11) 等,这
些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容
器?它与序列式容器有什么区别?
关联式容器 也是用来存储数据的,与序列式容器不同的是,其 里面存储的是 <key, value> 结构的键值对,在 数据检索时比序列式容器效率更高

2. 键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量 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)
 {}
};

3. 树形结构的关联式容器

根据应用场景的不桶, STL 总共实现了两种不同结构的管理式容器:树型结构与哈希结构。 树型结构的关联式
容器主要有四种: map set multimap multiset 。这四种容器的共同点是:使用平衡搜索树 ( 即红黑树 )
作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器

3.1 set

3.1.1 set 的介绍
? 翻译:
1. set 是按照一定次序存储元素的容器
2. set 中,元素的 value 也标识它 (value 就是 key ,类型为 T) ,并且每个 value 必须是唯一的。 set 中的元素 不能在容器中修改( 元素总是 const) ,但是可以从容器中插入或删除它们。
3. 在内部, set 中的元素总是按照其内部比较对象 ( 类型比较 ) 所指示的特定严格弱排序准则进行排序。
4. set 容器通过 key 访问单个元素的速度通常比 unordered_set 容器慢,但它们允许根据顺序对子集进行直接迭代。
5. set 在底层是用二叉搜索树 ( 红黑树 ) 实现的。
注意:
1. map/multimap 不同, map/multimap 中存储的是真正的键值对 <key, value> set 中只放 value ,但在底层实际存放的是由<value, value> 构成的键值对。
2. set 中插入元素时,只需要插入 value 即可,不需要构造键值对。
3. set 中的元素不可以重复 ( 因此可以使用 set 进行去重 )
4. 使用 set 的迭代器遍历 set 中的元素,可以得到有序序列
5. set 中的元素默认按照小于来比较
6. set 中查找某个元素,时间复杂度为:
7. set 中的元素不允许修改 ( 为什么 ?)
8. set 中的底层使用二叉搜索树 ( 红黑树 ) 来实现
3.1.2 set 的使用
1. set 的模板参数列表

T: set 中存放元素的类型,实际在底层存储 <value, value> 的键值对。
Compare set 中元素默认按照小于来比较
Alloc set 中元素空间的管理方式,使用 STL 提供的空间配置器管理
2. set 的构造

?3. set的迭代器

?4. set的容量

? 5. set 修改操作
? ? ? ? ? ? 函数声明? ? ? ? ? ? ? ? ? ? ? ? ?功能介绍
pair<iterator,bool> insert (
const value_type& x )
set 中插入元素 x ,实际插入的是 <x, x> 构成的键值对,
如果插入成功,返回 < 该元素在 set 中的位置, true>, 如果
插入失败,说明 x set 中已经存在,返回 <x set 中的位
置, false>
void erase ( iterator position )
删除 set position 位置上的元素
size_type erase ( const
key_type& x )
删除 set 中值为 x 的元素,返回删除的元素的个数
void erase ( iterator fifirst,
iterator last )
删除 set [fifirst, last) 区间中的元素
void swap (
set<Key,Compare,Allocator>&
st );
交换 set 中的元素
void clear ( )
set 中的元素清空
iterator fifind ( const
key_type& x ) const
返回 set 中值为 x 的元素的位置
size_type count ( const
key_type& x ) const
返回 set 中值为 x 的元素的个数
6. set 的使用举例

?删除一个元素可以通过迭代器删除,也可以通过值删除。但是通过值删除可以得到删除元素的个数,通过迭代器删除如果元素不存在会报错,所以一般我用迭代器删除的时候一般要判断要删除的元素是否存在

7.multiset

?可以看出multiset可以插入相同的元素,删除元素可以删除多个

3.2 map

3.2.1 map的介绍

1. map 是关联容器,它按照特定的次序 ( 按照 key 来比较 ) 存储由键值 key 和值 value 组合而成的元素。
2. map 中,键值 key 通常用于排序和惟一地标识元素,而值 value 中存储与此键值 key 关联的内容。键值
key 和值 value 的类型可能不同,并且在 map 的内部, key value 通过成员类型 value_type 绑定在一起,
为其取别名称为 pair:
typedef pair value_type;
3. 在内部, map 中的元素总是按照键值 key 进行比较排序的。
4. map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行
直接迭代 ( 即对 map 中的元素进行迭代时,可以得到一个有序的序列 )
5. map 支持下标访问符,即在 [] 中放入 key ,就可以找到与 key 对应的 value
6. map 通常被实现为二叉搜索树 ( 更准确的说:平衡二叉搜索树 ( 红黑树 ))。
1. map 是关联容器,它按照特定的次序 ( 按照 key 来比较 ) 存储由键值 key 和值 value 组合而成的元素。
2. map 中,键值 key 通常用于排序和惟一地标识元素,而值 value 中存储与此键值 key 关联的内容。键值
key 和值 value 的类型可能不同,并且在 map 的内部, key value 通过成员类型 value_type 绑定在一起,
为其取别名称为 pair:
typedef pair value_type;
3. 在内部, map 中的元素总是按照键值 key 进行比较排序的。
4. map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行
直接迭代 ( 即对 map 中的元素进行迭代时,可以得到一个有序的序列 )
5. map 支持下标访问符,即在 [] 中放入 key ,就可以找到与 key 对应的 value
6. map 通常被实现为二叉搜索树 ( 更准确的说:平衡二叉搜索树 ( 红黑树 ))

3.2.2 map的使用

1. map 的模板参数说明
key: 键值对中 key 的类型
T : 键值对中 value 的类型
Compare: 比较器的类型, map 中的元素是按照 key 来比较的,缺省情况下按照小于来比较,一般情况
( 内置类型元素 ) 该参数不需要传递,如果无法比较时 ( 自定义类型 ) ,需要用户自己显式传递比较规则
( 一般情况下按照函数指针或者仿函数来传递 )
Alloc :通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
注意:在使用 map 时,需要包含头文件。

2.map的构造

3. map的迭代器

?我们先看一段代码

void MapTest1()
{
	string array[] = { "苹果","香蕉","橘子","苹果","香蕉","橘子","樱桃" };
	map<string, int> mp;
	for (const auto& e : array)
	{
		auto it = mp.find(e);
		if (it == mp.end())    //说明该水果没有插入
		{
			mp.insert(make_pair(e, 1));
		}
		else
		{
			++it->second;
		}
	}
	for (const auto& e : mp)
	{
		cout << e.first << ":" << e.second << endl;
	}

}
int main()
{
	//SetTest();
	//MultisetTest();
	//MapTest();
	MapTest1();
}

?这段代码时统计水果的出现的次数

第二种方法:

void MapTest1()
{
	string array[] = { "苹果","香蕉","橘子","苹果","香蕉","橘子","樱桃" };
	map<string, int> mp;
	/*for (const auto& e : array)
	{
		auto it = mp.find(e);
		if (it == mp.end())
		{
			mp.insert(make_pair(e, 1));
		}
		else
		{
			++it->second;
		}
	}*/
	for (const auto& e : array)
	{
		auto kv = mp.insert(make_pair(e, 1));
		if (kv.second == false)
			++kv.first->second;
	}
	for (const auto& e : mp)
	{
		cout << e.first << ":" << e.second << endl;
	}

}
int main()
{
	//SetTest();
	//MultisetTest();
	//MapTest();
	MapTest1();
}

可以看出insert插入之后会返回一个pair,如果插入成功就返回插入之后的迭代器,返回true,插入失败就返回false,所以我们可以根据?第二个参数得到是否插入成功,失败就说明该水果存在我们就让value加1;

第三种方法:

for (const auto& e : array)
	{
		mp[e]++;
	}
	for (const auto& e : mp)
	{
		cout << e.first << ":" << e.second << endl;
	}
}
int main()
{
	//SetTest();
	//MultisetTest();
	//MapTest();
	MapTest1();
}

mapped_type& operator[] (const key_type& k)
{
    return (*((this->insert(make_pair(k,mapped_type()))).first)).second
}

//我们可以简化一下
mapped_type& operator[] (const key_type& k)
{
    auto kv = insert(make_pair(k,mapped_type());
    return kv.first->second;
}
【总结】
1. map 中的的元素是键值对
2. map 中的 key 是唯一的,并且不能修改
3. 默认按照小于的方式对 key 进行比较
4. map 中的元素如果用迭代器去遍历,可以得到一个有序的序列
5. map 的底层为平衡搜索树 ( 红黑树 ) ,查找效率比较高
6. 支持 [] 操作符, operator[] 中实际进行插入查找。

1. 本公司现在要给公司员工发波福利,在员工工作时间会提供大量的水果供员工补充营养。由于水果种类 比较多,但是却又不知道哪种水果比较受欢迎,然后公司就让每个员工报告了自己最爱吃的k种水果,并且告知已经将所有员工喜欢吃的水果存储于一个数组中。然后让我们统计出所有水果出现的次数,并 且求出大家最喜欢吃的前k种水果。

void GetFavoriteFruit ( const vector & fruits size_t k )
{
}
struct ComCol
{
	bool operator()(pair<int,string>& r, pair<int, string>& l)
	{
		return r.first > l.first;
	}
};
struct ComColIt
{
	bool operator()(multimap<int, string>::iterator& rt, multimap<int, string>::iterator& lt)
	{
		return rt->first > lt->first;
	}
};
void GetFavoriteFruit(const vector<string> & fruits, size_t k) 
{
	map<string, int> mp;
	for (const auto& e : fruits)
	{
		mp[e]++;
	}

	multimap<int, string> mmp;
	for (const auto& e : mp)
	{
		mmp.insert(make_pair(e.second, e.first));
	}
	//以为mp是双向迭代器,所以不支持sort所以需要把mp中数据放入vector中
	//方法一:将数据放入vector中
	
	/*
	vector<pair<int, string>> v;
	for (const auto& e : mmp)
	{
		v.push_back(e);
	}
	sort(v.begin(), v.end(),ComCol());
	*/
	//方法二:将迭代器放入vector中
	vector<multimap<int, string>::iterator> v;
	auto it = mmp.begin();
	while (it != mmp.end())
	{
		v.push_back(it);
		++it;
	}
	sort(v.begin(), v.end(), ComColIt());
	for (int i = 0; i < k; ++i)
	{
		cout << v[i]->first << " : " << v[i]->second << endl;
	}
    //方法三:
    priority_queue<map<string,int>::iterator, vector<map<string, int>::iterator>,         
    ComColIt> q;
	auto it = mp.begin();
	while (it != mp.end())
	{
		q.push(it);
		++it;
	}
	while (k--)
	{
		cout << q.top()->first << " : " << q.top()->second << endl;
		q.pop();
	}
}
int main()
{
	//SetTest();
	//MultisetTest();
	//MapTest();
	//MapTest1();
	vector<string> v{ "苹果","橘子", "樱桃" ,"苹果", "樱桃", "橘子" ,"哈密瓜" ,"西瓜", "香蕉", "香蕉" ,"哈密瓜", "苹果" ,"苹果", "橘子", "苹果" };
	GetFavoriteFruit(v, 3);
}

692. 前K个高频单词

class Solution {
public:
    struct ComCoV
    {
        bool operator()(map<string,int>::iterator &l,map<string,int>::iterator &r)
        {
             if(l->second < r->second)
             return true;
             else if(l->second ==  r->second && l->first > r->first)
             return true;
             else
             return false;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        vector<string> v;
        map<string,int>mp;
        for(const auto & e: words)
        {
            ++mp[e];    //统计次数
        }
        priority_queue<map<string,int>::iterator,vector<map<string,int>::iterator>,ComCoV> q;
        auto it = mp.begin();
        while(it != mp.end())
        {
            q.push(it);
            ++it;
        }
        while(k--)
        {
            v.push_back(q.top()->first);
            q.pop();
        }
        return v;
    }
};

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:39:00  更:2022-05-11 16:41:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:47:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码