C++11STL容器map和set简单介绍

发布于:2025-07-26 ⋅ 阅读:(11) ⋅ 点赞:(0)

一、引言

        map和set底层结构比较复杂,我认为我们先谈基本介绍再谈C++11,最后再谈map和set底层以及map和set封装。

二、简单介绍一下map和set

        map和set底层都是红黑树,是二叉搜索树的一种,查找非常快。不像数组、链表一样一个一个对比,可以理解为创建一个非常适合使用二分查找的结构,每次查找都可以排除掉上一次排除元素的一半。

        下面小编来介绍一个非常有意思的二叉树结构——二叉搜索树

小讲、map和set的底层红黑树的祖先——二叉搜索树

        二叉搜索树其实很简单,就是确定一个顺序,那一边(左边还是右边)大于根结点(我们将一棵子树的顶点称为根结点,任意一棵子树(只有一个点也可以被称为子树,子树是一个小单元,不是一个数量单位。)都有它的根结点)。那我们可以假设右子树(子树的右子树)的所有结点都大于子树的根节点。那左子树的结点肯定小于根结点。那我们以此作图就是这样。红黑树呢,也只是增加了几条规则保证二叉搜索树的平衡,改变根结点使二叉树像天平,这样就可以每次查找到下一层就可以排除掉一半的结点。

        2.1        map和set各自具有的特点。

                首先还是说说使用map和set所要包含的头文件时<map>、<set>头文件。

                先来说说map,这个主要是用来做映射的,映射大家可以想到什么?对应关系,例如说函数x带入到表达式中求出y的值(x,y)用坐标x通过数学图像可以指向坐标y点,通过给一个人或者一个事物取外号从而起到指代某个东西某个人,翻译过程中通过一个单词翻译出中文含义。这些都是映射。简单来说就是通过一个东西指代另一个东西。但是它不允许重复数据插入。

                set就更好说了,set并没有映射功能,所以它就是一个普通的红黑树,可以把它看成一个集合,它不允许有相同的数据插入,至于要看是否插入进去那要看插入时的返回值了,返回值为一个结构体,可以根据结构体来判断是否插入成功。

        2.2        map和set如何插入数据

                set插入很简单。考虑到map插入时,要交代映射关系就有点复杂了。我们先来说说map的插入吧。

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

int main()
{
	// map显示化模版传递类型
	std::map<std::string,std::string> dic;

	// 判断是否插入成功
	std::pair<std::map<std::string, std::string>::iterator, bool> is_insert;

	// 插入数据
	// map中存在一个pair<模版1,模版2>类型
	// 需要make_pair<>转化。
	// 为什么不像函数一样让编译器自己推导出类型呢?
	// 因为推出来的类型可能和map中显示传递的类型出现偏差。
	// 一般这种对返回值类型有精密要求都会要求模版显示化传递。
	is_insert = dic.insert(std::make_pair<std::string,std::string>("apple","苹果"));
	std::cout << is_insert.second << std::endl;

	is_insert = dic.insert(std::make_pair<std::string, std::string>("funny", "滑稽"));
	std::cout << is_insert.second << std::endl;

	is_insert = dic.insert(std::make_pair<std::string, std::string>("food", "食物"));
	std::cout << is_insert.second << std::endl;
	
	// 打印出map中存储的数据。
	std::map<std::string,std::string>::iterator it = dic.begin();
	while (it != dic.end())
	{
		std::cout << it->first << ":" << it->second << std::endl;
		++it;
	}

	return 0;
}

                set插入直接将数据往insert上甩就行了。

#include <iostream>
#include <set>

int main()
{
	std::set<int> gather;

	std::pair<std::set<int>::iterator, bool> is_insert;

	is_insert = gather.insert(0);
	is_insert = gather.insert(1);
	is_insert = gather.insert(2);
	is_insert = gather.insert(3);

	std::set<int>::iterator it = gather.begin();
	while (it != gather.end())
	{
		std::cout << *it << std::endl;
		++it;
	}

	return 0;
}

        2.3        size()函数

                毫无疑问这就是返回插入数据的个数,相信大家都能做好这里就不演示。

        2.4        find函数

                查找函数,set和map查找,都会得到一个迭代器。如果没找到迭代器就返回end()。值的一提的是map和set的迭代器都是双向迭代器(只能++或--)。

#include <iostream>
#include <set>

int main()
{
	std::set<int> gather;

	std::pair<std::set<int>::iterator, bool> is_insert;

	is_insert = gather.insert(0);
	is_insert = gather.insert(1);
	is_insert = gather.insert(2);
	is_insert = gather.insert(3);

    // 查找元素
	std::set<int>::iterator it = gather.find(3);
    
    // 判断是否存在,存在则打印,不存在不打印。
    if(it != gather.end())
    {
        std::cout << it << std::endl;
    }

	return 0;
}
#include <iostream>
#include <map>
#include <string>

int main()
{
	std::map<std::string,std::string> dic;

	std::pair<std::map<std::string, std::string>::iterator, bool> is_insert;

	is_insert = dic.insert(std::make_pair<std::string,std::string>("apple","苹果"));
	std::cout << is_insert.second << std::endl;

	is_insert = dic.insert(std::make_pair<std::string, std::string>("funny", "滑稽"));
	std::cout << is_insert.second << std::endl;

	is_insert = dic.insert(std::make_pair<std::string, std::string>("food", "食物"));
	std::cout << is_insert.second << std::endl;
	
	// 查找map中的数据。
	std::map<std::string,std::string>::iterator it = dic.find("apple");

    if(it != dic.end())
    {
    	std::cout << it->first << ":" << it->second << std::endl;
    }

	return 0;
}

        2.5        map中的count()函数和operator [] (模版)重载

                虽然find()函数很方便。但是我们很少用它,因为使用operator[]可以返回它的迭代器而且不管写起来,用起来,还是看起来都很方便、简洁。而且find()函数因为不知道里面有没有该函数还要写一老长串的判断是否等于end()。非常不方便!

                所以我们用count()和operator[]的结合。从count英文单词来看,是数数的意思,返回的是查找元素的个数,为零肯定就不存在。自然可以用operator[]访问(如果访问不存在的数据的话会报错。)。

                set虽然也有count,但是并没有operator[]的改值运算符重载,如果改值,意味着要删除重新插入。

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

int main()
{
	std::map<std::string,std::string> dic;

	std::pair<std::map<std::string, std::string>::iterator, bool> is_insert;

	is_insert = dic.insert(std::make_pair<std::string,std::string>("apple","苹果"));
	std::cout << is_insert.second << std::endl;

	is_insert = dic.insert(std::make_pair<std::string, std::string>("funny", "滑稽"));
	std::cout << is_insert.second << std::endl;

	is_insert = dic.insert(std::make_pair<std::string, std::string>("food", "食物"));
	std::cout << is_insert.second << std::endl;

    // 查看是否存在值
    if(dic.count("apple"))
    {
        // 其实返回的是映射也就是pair中的second。
    	std::cout << dic["apple"] << std::endl;
    }

	return 0;
}

        2.6      lower_bond和upper_bond函数

                lower_bond返回的是大于等于该值的起始数据的迭代器。

                upper_bond返回的是小于等于该值的起始数据的迭代器。

// set::lower_bound/upper_bound
#include <iostream>
#include <set>

int main()
{
    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);                //       ^
    itup = myset.upper_bound(60);                 //                   ^

    // 删除一段区间,从A位置删除到B位置。
    myset.erase(itlow, itup);                     // 10 20 70 80 90

    // 打印set中存储的值。
    std::cout << "myset contains:";
    for (std::set<int>::iterator it = myset.begin(); it != myset.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到