STL总结之set/multiset和map/multimap

/******************************************************set和Multiset****************************************************/

使用set和multiset之前,必须先含入头文件: #include <set>

namespace std{

template<class T,class Compare = less<T>,class Allocator = allocator<T>>

class set;

template<class T,class Compare = less<T>,class Allocator = allocator<T>>

class multiset;

}

关于排序准则:

1)必须是反对称的:若x<y为真,则y<x为假

2)必须是可传递的:若x<y且y<z,则x<z

3)必须是非自反的:x<x永远为假,op(x,x)永远为假

set和multiset通常由平衡二叉树实现.

自动排序造成set和multiset的一个重要限制:你不能直接改变元素值这样会打乱原本的排序顺序。为此,要改变元素值,

必须先删除旧元素,再插入新元素。

通过迭代器进行元素间接存取,有一个限制:从迭代器角度看,元素值是常数。

set 和 multiset的构造析构函数:

set c;

set c(op);

set c1(c2);

set c(beg,end);

set c(beg,end,op);

c.~set()

set可为以下形式:

set/multiset<Elem>

set/multiset<Elem,op>

有两种方式可以定义排序准则(后有例子):

1)以template参数定义:

std::set<int,std::greater<int>> coll;  这种情况下,排序准则就是型别的一部分,只有排序准则相同的容器才能被合并

2)以构造函数参数定义:

typedef set<int,RuntimeCmp<int>> IntSet; 

RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse);

IntSet coll2(reverse_order);

如果执行期才获得排序准则,且需要用到不同的排序准则(但数据型别必须相同),此方式可派上用场。

元素比较动作只能用于型别相同的容器,换言之,元素和排序准则都必须有相同的型别,否则编译出错。如果要比较拥有不同排序准则的容器,必须采用比较算法。

c.size() c.empty() c.max_size() == != < > <=  >=

set和multiset的搜寻操作函数:

count(elem)

find(elem) // 找第一个,找不到就返回end()

lower_bound(elem)

upper_bound(elem)

equal_range(elem)

赋值操作的两端容器必须具有相同型别。“比较准则”本身可以不同,但其型别必须相同,如果准则不同,准则本身也会被赋值/交换

c1 = c2;   c1.swap(c2);   swap(c1,c2);  

如果要移除set/multiset的元素,只能使用它们所提供的成员函数:

c.insert(elem)   // 返回新元素位置

c.insert(pos,elem)  //返回新元素位置

c.insert(beg,end)  //void

c.erase(elem)  //返回被移除的元素个数

c.erase(pos)   //void ,vector返回的是下一个元素位置,这种差别完全是为了性能

c.erase(beg,end)   // void

c.clear()

//无 remove

multiset允许元素重复,而set不允许。因此将某元素安插至一个set内,而该set已含同值元素,则安插失败,所以set的返回型别

是以pair组织起来的两个值:pair<iterator,bool>,first 返回新元素的位置,second表示是否安插成功

set和multiset运用实例:

#include <iostream>

#include <set>

#include <iterator>

#include <algorithm>

using namespace std;

int main(){

typedef set<int,greater<int>> IntSet;

IntSet coll1;

coll1.insert(4);

coll1.insert(3);

coll1.insert(5);

coll1.insert(1);

coll1.insert(6);

coll1.insert(2);

coll1.insert(5); // 会被程序忽略

IntSet::iterator pos;

for(pos = coll1.begin();pos != coll1.end; ++pos){

cout<<*pos<" ";

}

cout<<endl;

pair<IntSet::iterator,bool> status = coll1.insert(4);

if(status.second){

cout<<"4 inserted as element "

<<distance(coll.begin(),status.first) + 1

<<endl;

}else{

cout<<"4 already exists"<<endl;

}

set<int> coll2(coll1.begin(),coll1.end());

copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));

cout<<endl;

coll2.erase(coll2.begin(),coll2.find(3));

int num;

num = coll2.erase(5);

cout<<num<< " element(s) removed"<<endl;

copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));

cout<<endl;

}

执行期指定排序准则:

#include <iostream>

#include <set>

#include "print.hpp"

using namespace std;

template<class T>

class RuntimeCmp{

public:

enum cmp_mode{normal,reverse};

private:

cmp_mode mode;

public:

RuntimeCmp(cmp_mode m=normal) : mode(m) {

}

bool operator()(const T& t1,const T& t2) const{

return mode = normal ? t1 < t2 : t2 < t1;

}

bool operator == (const RuntimeCmp& rc){

return  mode == rc.mode;

}

};

typedef set<int,RuntimeCmp<int>> IntSet;

void fill(IntSet& set);

int main(){

IntSet coll1;

fill(coll1);

PRINT_ELEMENTS(coll1,"coll1: ");

RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse);

IntSet coll2(reverse_order);

fill(coll2);

PRINT_ELEMENTS(coll2,"coll2: ");

coll1 = coll2;

coll1.insert(3);

PRINT_ELEMENTS(coll1,"coll1: ");

}

void fill(IntSet& set){

set.insert(4);

set.insert(7);

set.insert(5);

set.insert(1);

set.insert(6);

set.insert(2);

set.insert(5);

}

/******************************************************map和multimap****************************************************/

使用map和multimap之前,必须包含头文件: #include <map>

namespace std{

template<class key,class T,

class Compare = less<key>,

class Allocator = allocator<pair<const key,T>>>

class map;

template<class key,class T,

class Compare = less<key>,

class Allocator = allocator<pair<const key,T>>>

class multimap;

}

key/value 必须具备可复制,可赋值性质;对排序准则而言,key必须是可比较的。map可作为关联式数组使用。

不可以直接更改元素的key,当value是非常数时,value可更改。若一定要改变元素的key,只有一条路:以一个value相同的

新元素替换掉旧元素。map提供了一种非常方便的手法让你改变元素的key:

coll["new_key"] = coll["old_key"]; 

coll.erase("old_key");

m[key]返回一个reference,指向键值为key的元素,如果该元素尚未存在,就安插该元素。

std::cout<<coll["otto"];     // 若该键值不存在,就安插,然后打印其值,缺省情况下是0,此安插速度慢,先构造再赋值。

map/multimap绝大多数操作都与set/multiset相同,此处略过。

成员函数find用来查找拥有某个key值的第一个元素,并返回一个指向该位置的迭代器或end()。你不能用find来查找拥有某特定

value的元素,你必须用find_if,或干脆写一个显式循环:

std::multimap<std::string,float> coll;

......

std::multimap<std::string,float>::iterator pos;

for(pos = coll.begin();pos != coll.end(); ++pos){

if(pos->second == value){

do_something();

}

}

有三种不同方法可以将value传入map:

1)运用value_type:value_type是容器本身提供的型别定义。

std::map<std::string,float> coll;

coll.insert(std::map<std::string,float>::value_type("otto",22.3));

2)运用pair<>

coll.insert(std::pair<std::string,float>("otto",22.3)); 

coll.insert(std::pair<const std::string,float>("otto",22.3));

第一个型别并不正确,但会被转换成真正的元素型别,因为insert成员函数被定义为member template

3)运用make_pair():最简单,这个函数根据传入的参数构造一个pair对象

coll.insert(std::make_pair("otto",22.3)); // member template insert()  执行必要的型别转换

eg: std::map<std::string,float> coll;

if(coll.insert(std::make_pair("otto",22.3)).second){  //对于insert(value),返回pair<iterator,bool>

std::cout<<"ok can insert"<<std::endl;

}else{

std::cout<<"Oops,could not insert,key already exists"<<std::endl;

}

如果multimap内含重复元素,你不能使用erase()来删除重复元素中的第一个,你可以用成员函数find:

typedef std::multimap<std::string,float> StringFloatMMap;

StringFloatMMap coll;

StringFloatMMap::iterator pos;

pos = coll.find(key);

if(pos != coll.end()){

coll.erase(pos);

}

移除迭代器所指对象时,有一个很大的危险:

for(pos = coll.begin();pos != coll.end(); ++pos){

if(pos->second == value){

coll.erase(pos); // Error!

}

对pos所指元素实施erase(),会使pos不再成为一个有效的coll迭代器,此后未对pos重新设值就径行使用pos,前途未卜!

应该这样:

for(pos = coll.begin();pos != coll.end(); ){

if(pos->second == value){

coll.erase(pos++);

}else{

++pos;

}

}

map和multimap运用实例:

将map当做关联式数组:

#include <iostream>

#include <map>

#include <string>

using namespace std;

int main(){

typedef map<string,float> StringFloatMap;

StringFloatMap stocks;

stocks["BASF"] = 369.50;

stocks["VW"] = 413.50;

stocks["Daimler"] = 819.00;

stocks["BWM"] = 822.00;

stocks["Siements"] = 834.20;

StringFloatMap::iterator pos;

for(pos = stocks.begin(); pos != stocks.end(); ++pos){

cout<<"stock: "<<pos->first<<"\t"

<<"price: "<<pos->second<<endl;

}

cout<<endl;

for(pos = stocks.begin(); pos != stocks.end(); ++pos){

pos->second *=2;

}

for(pos = stocks.begin(); pos != stocks.end(); ++pos){

cout<<"stock: "<<pos->first<<"\t"

<<"price: "<<pos->second<<endl;

}

cout<<endl;

stocks["Volkswagen"] = stocks["VM"];

stocks.erase["VM"];

for(pos = stocks.begin(); pos != stocks.end(); ++pos){


cout<<"stock: "<<pos->first<<"\t"

<<"price: "<<pos->second<<endl;

}

}

将multimap当做字典:

#include <iostream>

#include <map>

#include <string>

#include <iomanip>

using namespace std;

int main(){

typedef multimap<string,string> StrStrMMap;

StrStrMMap dict;

dict.insert(make_pair("day","Tag"));

dict.insert(make_pair("strange","fremd"));

dict.insert(make_pair("car","Auto"));

dict.insert(make_pair("smart","elegant"));

dict.insert(make_pair("trait","Merkmal"));

dict.insert(make_pair("strance","seltsam"));

dict.insert(make_pair("smart","raffiniert"));

dict.insert(make_pair("smart","klug"));

dict.insert(make_pair("clever","raffiniert"));

StrStrMMap::iterator pos;

cout.setf(ios::left,ios::adjustfield);

cout<<' '<<setw(10)<<"english"<<"german "<<endl;

cout<<setfill('-')<<setw(20)<<""<<setfill(' ')<<endl;

for(pos = dict.begin(); pos != dict.end(); ++pos){

cout<<' '<<setw(10)<<pos->first.c_str()

<<pos->second<<endl;

}

cout<<endl;

string world("smart");

cout<<word<<": "<<endl;

for(pos = dict.lower_bound(word); pos != dict.upper_bound(word); ++pos){

cout<<" "<<pos->second<<endl;

}

word = ("raffiniert");

for(pos = dict.begin(); pos != dict.end(); ++pos){

if(pos->second ==word){

cout<<"  "<<pos->first<<endl;

}

}

}

用find_if算法搜寻具有某特定值的元素:

#include <iostream>

#include <algorithm>

#include <map>

using namespace std;

template<class K,class V>

class value_equals{

private:

V value;

public:

value_equals(const V& v) : value(v){ }

bool operator()(pair<const K,V>elem){

return elem.second == value;

}

};

int main(){

typedef map<float,float> FloatFloatMap;

FloatFloatMap coll;

FloatFloatMap::iterator pos;

coll[1] = 7;

coll[2] = 4;

coll[3] = 6;

coll[4] = 3;

coll[5] = 2;

coll[6] = 1;

coll[7] = 3;

pos = coll.find(3.0);

if(pos != coll.end()){

cout<<pos->first<<": "

<<pos->second<<endl;

}

pos = find_if(coll.begin(),coll.end(),value_equals<float,float>(3.0));

if(pos != coll.end()){

cout<<pos->first<<": "

<<pos->second<<endl;

}

}

综合实例:运用map,multimap并于执行期指定排序准则

#include <iostream>

#include <iomanip>

#incldue <map>

#include <string>

#include <algorithm>

using namespace std;

class RuntimeStringCmp{

public:

enum cmp_mode{normal,nocase};

private:

const cmp_mode mode;

static bool nocase_compare(char c1,char c2){

return toupper(c1)<toupper(c2);

}

public:

RuntimeStringCmp(cmp_mode m = normal) : mode(m){ }

bool operator()(const string& s1,const string& s2) const {

if(mode == normal){

return s1 < s2 ;

}else{

return lexicographical_compare(s1.begin(),s1.end(),s2.begin(),s2.end(),nocase_compare);

}

}

};

typedef map<string,string,RuntimeStringCmp> StringStringMap;

void fillAndPrint(StringStringMap& coll);

int main(){

StringStringMap coll1;

fillAndPrint(coll1);

StringStringMap ignorecase(StringStringMap::nocase);

StringStringMap coll2(ignorecase);

fillAndPrint(coll2);

}

void fillAndPrint(StringStringMap& coll){

coll["deutsch"] = "German";

......

StringStringMap::iterator pos;

cout.setf(ios::left,ios::adjustfield);

for(pos = coll.begin(); pos != coll.end(); ++pos){

cout<<setw(15)<<pos->first.c_str()<<" "

<<pos->second<<endl;

}

cout<<endl;

}





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值