学习笔记_容器

总的来说,分为两大类:顺序容器,关联容器。

顺序容器,在于,元素的位置排序按其添加次序决定的,而与元素本身的值无关。反之,关联容器中元素的位置排序与元素值相关(想想搜索树就知道了,map,set都是基于红黑树的)。

这里先讲顺序容器:vector, list, deque.

vector元素的存放内存是连续的,跟数组类似。因此,可以按照元素之间的间隔n来访问元素,即,假设迭代器iter指向vector(或deque)的第i个元素,则可以用iter+n来访问位置与i距离n的元素。而list却没有此操作,因为元素的位置不连续,只能从头到尾访问。list的迭代器只能自增,并没有+n或者其他运算<,>,<=,>=


vector,deque,list都有push_back()函数,而deque,list更有push_front()函数.vector却没有。只因为连续存放……但是可以用循环来实现push_front()

如下:

<pre name="code" class="cpp">vector<int> vec;
vector<int>::iterator iter = vec.begin();
while(cin>>word)
        iter = iter.insert(iter,word);

 

但是这个代价很昂贵,每插入一个元素,vec里的所有元素都要向后移动一位。此外,这里还要注意,利用insert(iter,element)函数插入时,是在迭代器iter的前面插入element,且返回指向element的迭代器。要充分理解这,可以看下面的代码。


	vector<int> v;
	for(int i = 1; i < 10;++i)
		v.push_back(i);

	vector<int>::iterator first = v.begin(), last = v.end();
	int j = 11;
	while(first != v.end())
	{

		first = v.insert(++first,j);
		++j;
		++first;
	}

	for(vector<int>::iterator iter = v.begin(); iter != v.end();++iter)
		cout<<*iter<<" ";
	cout<<endl;
这里的输出是:1 11 2 12 3 13 4 14 5 15 6 16 7 17 8 18 9 19

 对于元素连续存放,还有一个注意的是,容器的容量!要了解vector的自增:
capacity():当前容器能够存储的元素总数。

reserve(n):表明应该有n个元素的存储空间。

如:

vector<int> vec;
//此时size = 0, capacity= 0
for(int i = 0; i < 24; ++i)
     vec.push_back(i);
//此时size = 24, capacity= 32
</pre><pre name="code" class="cpp">vec.reserve(100);
/此时size = 24, capacity= 100

 而当size() == capacity()时,若再向容器插入新元素,则标准库会给vec重新开辟新的内存空间,以保证连续存放,把vec原来的全部元素复制到新内存里去,因此为了提高效率,当不得不重新分配内存时,并不是以capacity+1来开辟空间,而是加倍capacity来开辟新空间(目前编译器不同,开辟多少也不同,也不一定是加倍开辟,但是肯定不是+1开辟,哈哈~)。 

删除元素:可以用pop_back(), pop_front()(这个只有deque和list有)这俩函数都是void型,无返回值。

清空:clear()

这里要讲的是erase(p):p是指向被删除元素的迭代器。返回被删除元素后面的元素。如果p指向最后一个元素,则返回end(),若p本身指向end(),则该函数未定义(运行出错!)

erase(p,e)删除迭代器p,e所标记的范围内所有元素,返回被删除元素段后面的元素。

	vector<int> vec;
	for(int i = 1; i < 11; ++i)
		vec.push_back(i);

	for(vector<int>::iterator iter = vec.begin(); iter != vec.end();++iter)
		cout<<*iter<<" ";
	cout<<endl;
	vector<int>::iterator del = vec.end();
	cout<<"删除前del------>"<<*del<<endl;

	del = vec.erase(del);
</pre><pre name="code" class="cpp">	cout<<"删除后del------>"<<*del<<endl;
	cout<<*vec.end()<<endl;

结果输出

1 2 3 4 5 6 7 8 9 10
删除前del------>842150451这里运行错误,因为del指向了超出元素未端的位置end(),所以erase(del)出错。

如果改成:

vector<int>::iterator del = vec.end()-1;
	cout<<"删除前del------>"<<*del<<endl;

	del = vec.erase(del);

	cout<<"删除后del------>"<<*del<<endl;
	cout<<"此时end()指向---->"<<*vec.end()<<endl;
则输出:

1 2 3 4 5 6 7 8 9 10
删除前del------>10
删除后del------>10
此时end()指向---->10


 程序运行并未发错误,但是输出却是有问题的。因为end()本来指向超出未端的下一个元素,虽然已删除,但是vector元素连续存放,所以还是输出了10,但是该内存的元素已失效的,删除后del还是指向end(),所以输出了失效的10. 

若是list容器,则

	list<int> vec;
	for(int i = 1; i < 11; ++i)
		vec.push_back(i);

	for(list<int>::iterator iter = vec.begin(); iter != vec.end();++iter)
		cout<<*iter<<" ";
	cout<<endl;
	list<int>::iterator del = --vec.end();  //这里不能用vec.end()-1,上面已经说了list的迭代器只能自增或自减
	cout<<"删除前del------>"<<*del<<endl;

	del = vec.erase(del);

	cout<<"删除后del------>"<<*del<<endl;
	cout<<*vec.end()<<endl;
程序运行未发生错误,输出:

1 2 3 4 5 6 7 8 9 10
删除前del------>10
删除后del------>-842150451
-842150451


而关联容器map也有erase(p),这里要非常的小心,erase(p)无返回值!迭代器p必须指向容器中确定存在的元素,且不能为end();所在,在循环中用map容器的erase(p)时,要注意,这是错误的写法:

map<string,int> m;
	for(map<string,int>::iterator iter = m.begin(); iter != m.end();++iter)
	{

		m.erase(iter);
	}
而正确的是:

map<string,int> m;
	for(map<string,int>::iterator iter = m.begin(); iter != m.end();)
	{

		m.erase(iter++);
	}
map的内部数据结构是红黑树,也就是二叉平衡树,使用erase删除一个元素后,树需要进行重新调整,因为不同于vector的顺序存储,所以map中erase方法中当前迭代器没有自动指向下一个节点位置,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值