(C++)std::map&std::list

std::map

map一般由键值(Key)和指向元素构成。

构建map

map<K,T> 类模板定义在 map 文件头中,它定义了一个保存 T 类型对象的 map,每个 T 类型的对象都有一个关联的 K 类型的键。容器内对象的位置是通过比较键决定的。可以用适当的键值从 map 容器中检索对象。

map<K,T> mapname

初始化map

因为 map 中包含的是 pair<const K,T> 类型的元素,所以初始化列表中的值也必须是这种类型。下面展示了如何为 people 容器设置初始值:

std::map<std::string, size_t> people{{"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32}};

utility 头文件中定义了 make_pair < T1,T2 >() 函数模板,它提供了一种组合 T1 和 T2 类型对象的简单方法。因此,可以按如下方式创建 pair 对象来初始化 map:

std::map<std::string,size_t> people{std::make_pair("Ann",25),std::make_pair("Bill", 46),std::make_pair("Jack", 32),std::make_pair("Jill", 32)};

map<K,T> 模板定义了移动和复制构造函数,所以可以复制现有的容器。例如:

std::map<std::string, size_t> personnel {people}; // Duplicate people map

可以用另一个容器的一段元素来创建一个 map,用开始和结束迭代器以通常的方式指定元素。显然,迭代器指向的 pair 元素的类型必须和容器兼容。这里有一个示例:

std::map<std::string, size_t> personnel {std::begin(people),std::end(people)};

map 容器提供了双向迭代器,这样就可以通过自增或自减访问元素。map 容器还提供了反向迭代器,所以可以从最后一个元素遍历到第一个元素。personnel 容器包含的元素和 people 完全相同。当然,也可以用另一个容器的元素子集来创建容器:

std::map<std::string,size_t> personnel {++std::begin(people),std::end(people)};

map<K,T> 容器的成员函数 insert() 有多个版本,它们可以在 map 中插入一个或多个 pair<const K,T> 对象。只能插入 map 中不存在的元素。下面这个代码片段展示了如何插入单个元素:

std::map<std:: string,size_t> people {std::make_pair ("Ann",25),std::make_pair("Bill",46) , std::make_pair ("Jack",32), std::make_pair("Jill",32)};
auto pr = std::make_pair("Fred",22); //Create a pair element and insert it
auto ret_pr = people.insert(pr);
std::cout << ret_pr.first->first << " "<< ret_pr.first->second<< "" << std:: boolalpha <<ret_pr.second << "\n"; // Fred 22 true

成员函数 insert() 会返回一个 pair<iterator,bool> 对象。对象的成员 first 是一个迭代器,它要么指向插入元素,要么指向阻止插入的元素。如果 map 中已经保存了一个和这个键相同的对象,就会出现后面这种情况。这个对象的成员变量 second (布尔型)是返回对象,如果插入成功,返回值为 true,否则为 false。

当元素已经存在时,如果想将键值“Bill”对应的年龄值改为 48,可以像下面这样使用 insert() 返回的 pair 对象来做到这一点:

if(!ret_pr.second) // If the element is there change the age
    ret_pr.first—>second = 48;

也可以将外部源中的一段元素插入 map 中,这些元素不必来自另一个 map 容器,但必须和被插入容器中的元素是同类型。这里有一些示例:

std::map<std::string, size_t> crowd {{"May", 55}, {"Pat",66}, {"Al", 22}, {"Ben", 44}};
auto iter = std::begin(people);
std::advance(iter, 4);  // begin iterator+ 4
crowd.insert(++std::begin(people),iter); // Insert 2nd, 3rd, and 4th elements from people

map构造函数

map 容器的成员函数 emplace() 可以在适当的位置直接构造新元素,从而避免复制和移动操作。它的参数通常是构造元素,也就是 pair<const K,T> 对象所需要的。只有当容器中现有元素的键与这个元素的键不同时,才会构造这个元素。下面是一个示例:

std::map<Name, size_t> people;
auto pr = people.emplace (Name { "Dan","Druff"},77);

emplace()整体用法与insert()类似,感觉主要只是避免了复制和移动操作。
map 的成员函数 emplace_hint() 和 emplace() 生成元素的方式在本质上是一样的,除了必须为前者提供一个指示元素生成位置的迭代器,作为 emplace_hint() 的第一个参数。例如:

std::map<Name, size_t> people;
auto pr = people.emplace(Name{"Dan","Druff"}, 77);
auto iter = people.emplace_hint (pr.first, Name {"Cal","Cutta"}, 62);

这里,emplace_hint() 调用使用一个迭代器作为指示符,指向先前 emplace() 调用返回的 pair 对象。如果容器使用这个提示符,那么新元素会在这个指示符表示的位置之前生成,并尽可能靠近这个位置。提示符后面的参数用来构造新元素。需要注意的是,它和 emplace() 的返回值是不一样的。emplace_hint() 的返回值不是一个 pair 对象,如果新元素被插入,它返回的是指向新元素的迭代器;如果没有插入,返回的是和这个键匹配的现有元素的迭代器,拥有相同的 key 值,如果不是现有元素的话。没有提示可以直接判断是否生成了新元素。唯一的方法是,用 size() 成员函数来获取 map 中对应元素的数量来检查 map 元素增加的数量。例如:

auto pr = people.emplace(Name{"Dan", "Druff"}, 77);
auto count = people.size ();
auto iter = people.emplace_hint (pr.first, Name {"Cal", "Cutta"}, 62);
if(count < people.size ()) std::cout <<"Success!\n";

map删除元素

map 的成员函数 erase() 可以移除键和参数匹配的元素,然后返回所移除元素的个数,例如:

std::map<std::string, size_t> people {{ "Fred", 45}, {"Joan", 33},{"Jill", 22}};
std::string name{"Joan"};
if(people.erase(name))
    std::cout << name << " was removed." << std::endl;
else
    std::cout << name << " was not found" << std::endl;

显然,map 容器的返回值只可能是 0 或 1,0 表明元素不在容器中。也可以用指向删除元素的迭代器作为 erase() 的参数。这种情况下,返回的迭代器指向被删除元素的下一个位置。这个参数必须是容器中的有效迭代器,不能是结束迭代器。如果迭代器参数指向的是容器的最后一个元素,那么会返回结束迭代器。例如:

auto iter = people.erase(std::begin(people));
if(iter == std::end(people))
    std::cout << "The last element was removed."<< std::endl;
else
    std::cout << "The element preceding " << iter->first << "was removed." << std::endl;

当最后一个元素被移除时,这段代码会输出一条消息或被移除元素后面元素的键。也有更高级版本的 erase(),它可以移除两个迭代器参数所定义范围内的元素,例如:

auto iter = people.erase(++std::begin(people), --std::end(people));//Erase all except 1st & last

map循环

遍历循环:

for (const auto& p : people)
    std::cout << std::setw(10) << std::left << p.first << " "<< p.second <<"\n";

使用迭代器进行循环:

for(auto iter=people.begin();iter!=people.end();iter++)
{
    //iter为指向循环元素的迭代器
    //iter->first表示键值
    //iter->second表示键值对应的内容
}

map查找元素

通常情况下我们使用find(Key)的方法查找一个Key值对应的元素在map中是否存在:

//查找people这个map中键值为key的元素,存在则返回对应的迭代器
auto iter=find(people.begin(),people.end(),key);
if(iter==people.end())
{
    cout<<"not found!"<<endl;
    //若返回的迭代器指向map末尾,则未查找到对应值
}

map.less(K)

不要因为 map 使用 less 对元素排序就被误导,这些元素并没有被组织成一个简单的有序序列,STL map 容器对元素的组织方式并没有具体要求,但元素一般都会保存在一个平衡二叉树中。容器中的元素被组织成一个平衡二叉树,因而树的高度——根节点和叶节点之间的高度是最低的。如果每个节点的左子树和右子树的高度差不超过 1,那么可以说这棵二叉树就是平衡的。下图展示了 map 容器可能的平衡二叉树。
map容器二叉树

std::list

具体操作参考:https://blog.csdn.net/sinat_41104353/article/details/84900018#_41

参考内容

map:http://c.biancheng.net/view/488.html
list:https://blog.csdn.net/sinat_41104353/article/details/84900018#_41

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值