stl

12. vector


12.2 存储

vector使用堆内存存储元素,即vector中的元素存储于堆



12.1 vector()

函数:vector(size_type n, const value_type &val = value_type())

功能:构造函数,初始包含「n」个元素,每个元素的值为「val」

说明:

「val」带有默认参数「value_type()」,使用的是值初始化,因此对于没有指定初值「val」的内置类型的vector来讲,元素将被妥善地初始化(初始化为0)

② 对于vector,可以通过该函数预订空间,而无需显示地调用resize()函数

示例:




11. string


11.3 erase()

函数:

string& erase(size_t pos, size_t len)

iterator erase(iterator p)

iterator erase(iterator first, iterator last)

功能:删除指定的元素

 删除起始索引为「pos」,长度为「len」的元素,若元素个数不足「len」,则取最大值;

 删除p指向的元素;

 删除[first, last)范围内的元素;



11.2 rbegin()

函数:reverse_iterator rbegin() [const]

返回值:返回指向string最后一个字符的反向迭代器

示例:



11.1 compare()

函数:int compare(size_t pos, size_t len, const std::string &str) [const]

功能:把string对象中起始索引为「pos」,长度为「len」的子串,与str进行比较

返回值:

= 0相等;

< 0对于第一个不相等的字符,string中的对应字符 < str中的对应字符;所有参与比较的字符都相等,但在「len」的范围内,string子串的长度 < str的长度;

> 0对于第一个不相等的字符,string中的对应字符 > str中的对应字符;所有参与比较的字符都相等,但在「len」的范围内,string子串的长度 > str的长度;


说明:

① 如果string从索引「pos」开始的长度,小于「len」,则取最大子串;

② 通过src.compare(pos, obj.len, obj),可以进行安全的字符串比较,不必关心超界问题;


示例:




10. list

说明:

能够调用list的push函数,如「push_front」,「push_back」的前提是:类型T具有拷贝构造函数,且为public



9. map

 lower_bound()

函数原型:iterator lower_bound(const key_type &k);

功能:返回key大于等于k的第一个元素


upper_bound()

函数原型:iterator upper_bound(const key_type &k);

功能:返回key大于k的第一个元素



8. map限制

const map不能调用operator[],即下面非法:

cmp[k]; 

其中cmp为任意类型的const map<K, V>


能够调用map下标运算符的前提是:mapped_type具有默认构造函数,且为public

示例:

std::map<K, V> mp;

mp[k];

类型V必须具有默认构造函数



7. mapset

 

7.1 迭代器类型

双向迭代器,Bidirectional迭代器,可前进可后退,一次一步。

iterator it;  

it+= n; 或 it -= n; //n等于1

std::advance(it, 3); ++it调用三次,实现前进三步。


7.2 内置类型

std::map<key_type, mapped_type> mp;

std::set<key_type> st;

 

map的value_type:std::pair<key_type, mapped_type>

set的value_type:key_type

 

7.3 判断元素存在

标准形式:

函数原型:size_t count(const key_type &k) const

功能:返回容器中键值等于k的元素个数。

返回值:对于set和map,键值唯一,故存在即1、否则为0;对于multiset和multimap,存在多键值,返回值>=0。

 

7.4 插入元素

标准形式:

函数原型:std::pair<iterator, bool> insert(const value_type &val);

功能:插入元素。

返回值:std::pair<iterator, bool>。bool为false表失败,键值已存在,否则true表成功;iterator为指向新插入元素的位置,或返回已存在的同值元素的位置。

 

7.5 map取值

标准形式:

 

7.6 删除元素

标准形式:

函数原型:size_t erase(const key_type &k);

功能:删除键值等于k的元素。

返回值:被删除的元素个数。对于map和set,键值唯一,故返回值非0即1;对于multimap和multiset,存在多键值,返回值>=0。

 

 

6. 空间分配和预定

reserve(size_t n):预定空间,增大capacity,避免容器增长导致重新分配内存;若改小,不执行

resize(size_t n, value_type v):调整实际大小,使容器内元素个数等于n

        n小于元素个数——截断,只保留前n个元素,其余删

        n大于元素个数——填,从最后插入新元素,直到元素个数达到n;新元素为v的副本,若无参数v,则使用value_type的默认值或默认构造函数构造新                                       元素

差别

                         

结果

                 

小评:std::string s; s.resize(size_t n, char c); 等价于 std::string s(size_t n, char c);


5.mapset遍历过程中不可以任何方式删除当前迭代器所指元素

std::map<UINT, std::string> map;
map.insert(std::make_pair(1, "a"));
map.insert(std::make_pair(2, "b"));
map.insert(std::make_pair(3, "c"));
map.insert(std::make_pair(4, "d"));
map.insert(std::make_pair(5, "e"));
for(auto it = map.begin(); it != map.end(); ++it)
{
	printf("%-10d%-10s\n", it->first, it->second.c_str());
	if(it->second == "c")
	{
		UINT cid = it->first;
		map.erase(cid);
	}
}

结果

 

4. multimap查询标准格式

bool IsExist(const std::string &sUsername, const UINT cid)
{
	auto beg = mmap.lower_bound(sUsername);
	auto end = mmap.upper_bound(sUsername);
	for(; beg != end; ++beg)
	{
		if(beg->second == cid)
			return true;
	}
	return false;
}

3.map添加方式的选择

typedef struct MapStruct
{
	MapStruct()
	{
		printf("Default Constructor\n");
	}

	MapStruct(const int i) : iCount(i)
	{
		printf("Simple Constructor\n");
	}

	MapStruct(const MapStruct &rhs) : iCount(rhs.iCount)
	{
		printf("Copy Constructor\n");
		printf("lhs=%p\nrhs=%p\n", this, &rhs);
	}

	MapStruct(MapStruct &&rhs) : iCount(std::move(rhs.iCount))
	{
		printf("Move Constructor\n");
		printf("lhs=%p\nrhs=%p\n", this, &rhs);
	}

	MapStruct& operator=(const MapStruct &rhs)
	{
		std::cout<<"Copy Assignmen Operator"<<std::endl;
		iCount = rhs.iCount;
		return *this;
	}

	MapStruct& operator=(MapStruct &&rhs)
	{
		std::cout<<"Move Assignmen Operator"<<std::endl;
		iCount = std::move(rhs.iCount);
		rhs.iCount = 0;
		return *this;
	}

	int iCount;
}MapStruct;

3.1 map[key] = value

int main()

{

        std::map<int, MapStruct> map;

        map[2] = MapStruct(5);

}

结果:

解释:

执行过程

        1. MapStruct(5),调用普通构造函数,生成=右侧临时对象

        2. MapStruct(),调用默认构造函数,生成临时对象,地址0012E2D0

        3. std::pair<int, MapStruct>(2,0012E2D0),因2和0012E2D0均属右值,故调用std::pair的构造函数std::pair<T1, T2> std::pair(T1&&, T2&&),生成std::pair临时对象。此构造函数原型:

pair(_Ty1x&& _Val1, _Ty2x&& _Val2)

        : _Mybase(_STD move(_Val1),

                 _STD move(_Val2)) 

{}

最终调用

_Pair_base(_Ty1x&& _Val1, _Ty2x&& _Val2) 

        : first(_STD move(_Val1)), 

                second(_STD move(_Val2))
{}

完成pair的构造,first和second为_Pair_base唯一两个成员变量,如

        _Ty1 first;// the first stored value
        _Ty2 second; // the second stored value

此例中为

        int first;

        MapStruct second;

故调用MapStruct移动构造函数生成second,地址0012E2C4

        4. 生成Node节点,Map为红黑树,以节点存储。Node中存在std::pair型成员,构造此成员时使用3中临时量进行拷贝初始化,临时量属右值,故调用移动构造函数,即

template<class _Other1,
class _Other2>
        pair(pair<_Other1, _Other2>&& _Right)
        : _Mybase(_STD forward<_Other1>(_Right.first),
        _STD forward<_Other2>(_Right.second))
{}

最终调用

template<class _Other1,
class _Other2>
_Pair_base(_Other1&& _Val1, _Other2&& _Val2)
: first(_STD forward<_Other1>(_Val1)),
second(_STD forward<_Other2>(_Val2))
{}

完成pair的构造,经过复杂的类型传递,_Other1 = int, _Other2 = MapStruct。std::forward<T>(arg)函数返回绑定到arg的T&&,T&&适用引用折叠。故再次调用MapStruct的移动构造函数生成second,地址003E2CC8

        5. 最后,由=右侧的临时量MapStruct(5),为003E2CC8赋值,临时量属右值,调用移动赋值运算符。


结论:

map以map[key] = value形式添加元素,假设map[key]不存在,则执行过程如下
        1.生成右侧value
        2.在map中添加key-默认value
        3.右侧value给默认value赋值


附加:

标准库中类拷贝构造函数定义为

        Type(const Type &)

移动构造函数定义为

        Type(Type &&)

其中const Type &可以绑定到左值也可绑定到右值,故当Type存在移动构造函数且以右值进行拷贝初始化时,右值与Type&&精确匹配,即调用移动构造函数;当Type不存在移动构造函数时,const Type &将成为最佳匹配调用拷贝构造函数。赋值运算符情况类似。

综上,当一个类存在拷贝操作而不存在移动操作,所有的移动操作将调用对应的拷贝操作完成。而且除非显示定义为delete,每个类必有拷贝操作,若无,编译器自动合成,合成条件宽泛——即不存在。


3.2 map.insert(std::make_pair(key, value))

map.insert(std::make_pair(1, MapStruct(2)));

结果:


结论:

        map以map.insert(std::make_pair(key, value))形式添加元素,与3.1相同,仅省去最后一步赋值操作。


3.3 

MapStruct tmp(2);

mp.insert(std::make_pair(1, tmp));

结果:


结论:

        与3.2相同,仅调用std::make_pair(1, tmp)时传入的参数为MapStruct左值,故在创建临时pair的second成员时执行的拷贝初始化,调用的是拷贝构造函数。


3.4

if(map[4].iCount == 5)

        std::cout<<"map[4].iCount == 5"<<std::endl;

std::cout<<map.size()<<std::endl;

结果:


实验过程:
        1.map[4]不存在
        2.以map[4].iCount作为判断条件
        3.输出"MapStruct Default Construction"
实验结论:
        1.map[key]以任何形式存在,只要程序执行到,无论key是否存在,自动插入key-value
        2.map[key].member绝对安全,即便key在map中不存在,只要执行到map[key]则自动添加


3.5

if(2==3 && map[5].iCount==3)

        std::cout<<"Ok"<<std::endl;

std::cout<<map.size()<<std::endl;

结果:


实验说明:
        1.map[5]不存在
        2.2==3 && map[5].iCount==3作为if语句判断条件
实验结果:
        1.MapStruct默认构造未被调用
        2.key=5未自动添加到map
        故map[5].iCount==3根本没有被执行
实验结论:
        condition1 && condition2作为判断条件,若condition1==false直接以false返回,condition2根本不会被执行


3.6

if(2==2 || map[5].iCount==3)

        std::cout<<"Ok"<<std::endl;

std::cout<<map.size()<<std::endl;

结果:


实验说明:
        1.map[5]不存在
        2.2==2 || map[5].iCount==3作为if语句判断条件
实验结果:
        1.MapStruct默认构造未被调用
        2.key=5没有自动添加到map
        故map[5].iCount==3根本没有被执行
实验结论:
        condition1 || condition2作为判断条件,若condition1==true直接以true返回,condition2不会被执行如同不存在


1. map 用来存储键值对,key-value的形式。

增删改查速度都很快,查找速度在log(N)

mapset的插入删除效率比用其他顺序容器高。这是因为对于关联容器来说,不需要做内存拷贝和内存移动。

map和set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多。

整数作key会提高map效率。


1.1 插入  

std::map<int,double> map;
map.insert(std::pair<int,double>(1, 24.3));
map.insert(std::pair<int,double>(2, 21.7));

1.2 遍历 

std::map<int,double>::iterator iter;
for(iter = map.begin(); iter != map.end(); iter++)
{
    int key = iter->first;
    double value = iter->second;
    std::cout<<key<<value<<std::endl;
}

1.3 查找  iterator find (const key_type& k);

//std::map<UINT, std::string> map
std::map<UINT, std::string>::iterator iter = map.find(14);
if(iter != map.end())
{
    std::cout<<"存在"<<std::endl;
}

map 是关联容器,对于关联容器来说,如果某一个元素已经被删除,那么其对应的迭代器就失效了,不应该再被使用;否则会导致程序无定义的行为。
标准写法:删除之前,迭代器先定位到下一个元素。

for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
    cout<<iter->first<<":"<<iter->second<<endl;
    mapTest.erase(iter++);
}

1.4 删除

std::map<int, std::string> map;  
map.erase(14);


2. vector 顺序容器、自适应数组、连续存储区

程序运行时会给vector分配一片连续存储区,来适应vector的增长。当vector继续增大、存储区不足以容纳时,程序扩展连续存储区。

如果没有足够连续区域分配,则程序将在其他地方申请足够容量的存储区,然后将vector拷贝过去。

优点:支持随机访问,例如:vecNames.at(16)


2.1 添加

std::vector<std::string> vecNames;
vecNames.push_back("rongbaibai");

2.2 查找

std::vector<std::string> vec;
auto pos = std::find(vec.begin(), vec.end(), "fengsha");
if(pos == vec.end())
	return false;
int iDst = std::distance(vec.begin(), pos);

2.3 空间预定

示例一

int iNum = GetResultNum();
if(iNum == 0)
	return false;
std::vector<Data> vec(iNum);
bool bRet = GetResult(&vec[0]);

利用Data的默认构造函数生成一个大小为iNum的vector。

示例二

std::vector<Data> vec;
int iNum = GetResultNum();
if(iNum == 0)
	return false;
vec.resize(iNum, data);
bool bRet = GetResult(&vec[0]);
将vector大小改为iNum,多出来的元素都是data的副本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值