STL学习笔记-顺序容器(vector, list, deque)的操作

主要知识点:

  1. 容器定义的类型别名;
  2. 迭代器begin指向容器的第一个元素,end不是指向最后一个元素,而是指向最后一个元素的后面一个位置;
  3. vector和deque能通过下标索引和迭代器两种方式访问,list不同使用下标索引访问,只能通过迭代器访问;
  4. const容器在初始化以后,其中的元素无法修改,且使用迭代器方位时,不用用iterator,而要用const_iterator;
  5. 容器大小操作(可能会使迭代器失效),(编程中不要缓存迭代器的值);
    1. c.size();
    2. c.max_size(); // 容器 c 能容纳的最大size
    3. c.empty(); // 判断容器 c 是否为空;
    4. c.resize(n); // 将容器 c resize 成大小为 n 的容器,若 n > c.size(), 该操作原来c中内容不变,后面填充0;若 n <= c.size(), 则取容器 c 前面的 n 个元素。
    5. c.resize(n, t); 将容器 c resize 成大小为 n,值为 t 的容器,操作逻辑同上;
  6. 顺序容器的访问:
    1. 通过迭代器访问
    2. c.back();
    3. c.front();
    4. c[n]; c.at(n); //这两种方式需要下标,所以只使用与vector和deque
  7. 在顺序容器中添加元素(需要注意,添加元素可能会使迭代器失效):
    1. 对于vector,v.push_back(); v.insert();
    2. 对于list,l.push_front(); l.push_back(); l.insert();
    3. 对于deque, d.push_front(); d.push_back(); d.insert();
    4. 关于insert,
      c.insert(p, t); 在位置 p(p为迭代器)插入元素 t;
      c.insert(p, n, t); 在位置 p 插入 n 个 t;
      c.insert(p, b, e); 在位置 p 插入 从 b 到 e 之间的所有元素;(b,e为迭代器的起始和终止位置)
  8. 删除元素:
    c.erase§; // 删除迭代器 p 所指向的元素;
    c.erase(b, e); // 删除迭代器 b(包括b) 到 e(不包括e) 之间的算有元素,即前闭后开区间;
    c.clear();
    c.pop_back(); // 删除最后元素
    c.pop_front(); // 删除最前面的元素,vector没有该方法
#include<iostream>
#include<vector>
#include<deque>
#include<list>
#include<algorithm>

template <typename Container>
void printContainer(const Container& con)
{
	for (Container::const_iterator con_it = con.begin(); con_it != con.end(); ++con_it)
		std::cout << *con_it << " ";
	std::cout << "\n------------------------------" << std::endl;
}

int main()
{
	std::vector<int> v;
	std::list<int> l;
	std::deque<int> d;
	// 1:
	std::vector<int>::size_type              v1;
	std::vector<int>::iterator               v2;
	std::vector<int>::const_iterator         v3;  // 常迭代器
	std::vector<int>::reverse_iterator       v4;  // 逆序迭代器,从后向前迭代
	std::vector<int>::const_reverse_iterator v5;  // 常逆序迭代器
	std::vector<int>::difference_type        v6;  // 用来保存两个迭代器之间的距离,类似数组下标索引之差
	//std::vector<int>::value_type           v7;
	//std::vector<int>::reference            v8;//引用
	//std::vector<int>::const_reference      v9;//常引用

	std::list<int>::size_type              l1;
	std::list<int>::iterator               l2;
	std::list<int>::const_iterator         l3;
	std::list<int>::reverse_iterator       l4;
	std::list<int>::const_reverse_iterator l5;
	std::list<int>::difference_type        l6;
	//std::vector<int>::value_type         v7;
	//std::vector<int>::reference          v8;
	//std::vector<int>::const_reference    v9;

	std::deque<int>::size_type              d1;
	std::deque<int>::iterator               d2;
	std::deque<int>::const_iterator         d3;
	std::deque<int>::reverse_iterator       d4;
	std::deque<int>::const_reverse_iterator d5;
	std::deque<int>::difference_type        d6;
	//std::deque<int>::value_type           d7;
	//std::deque<int>::reference            d8;
	//std::deque<int>::const_reference      d9;

	// 2,3:
	v.push_back(1); v.push_back(2); v.push_back(3); v.insert(v.begin(), 0); //不能 v.push_front()
	l.push_back(10); l.push_back(20); l.push_back(30); l.push_front(0); l.insert(l.end(), 40);
	d.push_back(100); d.push_back(200); d.push_back(300); d.push_front(0);; d.insert(d.end(), 400);
	// 访问输入:
	for (std::vector<int>::size_type i = 0; i < v.size(); ++i)  // vector,可通过下标索引和迭代器两种方式访问;
		std::cout << v[i] << " ";
	std::cout << std::endl; // 0 1 2 3
	for (std::list<int>::iterator iter = l.begin(); iter != l.end(); ++iter)  // list,只能通过迭代器访问;
		std::cout << *iter << " "; // 其中迭代器begin指向l的第一个元素,end不是指向最后一个元素,而是指向最后一个元素的后面一个位置
	std::cout << std::endl; // 0 10 20 30 40
	for (std::deque<int>::size_type i = 0; i < d.size(); ++i)  // deque,可通过下标索引和迭代器两种方式访问;
		std::cout << d[i] << " "; // 0 100 200 300 400
	std::cout << std::endl;

	std::cout << "逆序迭代器rbegin, rend: ";
	for (std::deque<int>::reverse_iterator iter = d.rbegin(); iter != d.rend(); ++iter)  // 链表,只能通过迭代器访问;
		std::cout << *iter << " "; // 400 300 200 100 0
	std::cout << std::endl;

	// 4:
	const std::vector<int> cv(v);  //const 容器不能修改其中的元素,cv.push_back(123); cv[1] = 123等方式均不合法。
	for (std::vector<int>::const_iterator citer = cv.begin(); citer != cv.end(); ++citer) //对于const 容器,使用迭代器访问时必须用常迭代器const_iterator,否则报错
		std::cout << *citer << " "; // 0 1 2 3
	std::cout << std::endl;

	// 5:
	std::cout << "容器l总的max_size:" << l.max_size() << std::endl;
	if (l.empty())
		std::cout << "容器l为空!\n";
	else
		std::cout << "容器l中总的元素个数:" << l.size() << std::endl;
	l.resize(10); // 原来为:0 10 20 30 40, resize后原来数量不变,后面新增的数为0,结果为: 0 10 20 30 40 0 0 0 0 0
	printContainer(l); 
	l.resize(15, -1); // 原来数据不变,新增的数据用-1填充;
	printContainer(l);  // 结果为: 0 10 20 30 40 0 0 0 0 0 -1 -1 -1 -1 -1
	l.resize(5);
	printContainer(l); // 结果为:0 10 20 30 40 
	l.resize(0);
	if (l.empty())
		std::cout << "now,容器l为空!\n";
	l.push_back(0); l.push_back(10); l.push_back(20); l.push_back(30); l.push_back(40);

	//6.1. 使用迭代器访问 *iter
	std::cout << *(--d.end()) << " " << *d.begin() << std::endl;  // 400 0
	//6.2-3: 
	std::cout << l.front() << " " << l.back() << std::endl; // 0 40; // 若容器为空,则报错
	//通过引用访问
	std::vector<int>::reference rf = v.front(); 
	std::vector<int>::reference rb = *--v.end();
	std::cout << rf << " " << rb << std::endl; // 0 3
	//5.4: 使用下标,不能用于list
	std::cout << d[0] << " " << v[1] << std::endl;  // 0 1; // 若下标越界,不会抛异常,直接报错
	std::cout << d.at(2) << " " << v.at(3) << std::endl; // 200 3; // 若下标越界,会抛异常
	try{
		std::cout << v.at(10) << std::endl;
	}
	catch (std::out_of_range) {
		std::cout << "错误,下标越界!\n";
	}

	// 7: 请参考https://blog.csdn.net/sunqin_csdn/article/details/84929609
		// 对于list
	std::list<int>::iterator ibegin = l.begin();
	//std::list<int>::iterator iend = l.end(); // 要避免存储end返回的迭代器,因为存储的迭代器可能会在更新元素后失效
	//while (ibegin != iend)  //错误,在插入新的元素之后iend不再指向l.end
	while (ibegin != l.end())
	{
		l.insert(ibegin, 123);
		++ibegin;
	} // 结果:
	printContainer(l); // 123 0 123 10 123 20 123 30 123 40
		// 对于vector和deque
	std::deque<int>::iterator ibegin2 = d.begin();
	// std::deque<int>::iterator iend2 = d.end();
	int i = 0;
	//while (ibegin != iend) //错误,在插入新的元素之后iend不再指向d.end
	while (ibegin2 != d.end() && i < 5)
	{
		ibegin2 = d.insert(ibegin2, 123);
		++ibegin2; ++i;
	} // 每次插入新的元素之后,ibegin的位置更新了,最终结果为:123 123 123 123 123 0 100 200 300 400
	printContainer(d); 
	std::vector<int>::iterator ibegin3 = v.begin();
	while (ibegin3 != v.end())
	{
		ibegin3 = v.insert(ibegin3, 123);
		++ibegin3; ++ibegin3;
	} // 每次插入新的元素之后,ibegin的位置更新了,最终结果为:123 0 123 1 123 2 123 3
	printContainer(v);

	// 8, 删除:
	l.pop_back(); l.pop_front();
	printContainer(l); // 0 123 10 123 20 123 30 123
	v.erase(find(v.begin(), v.end(), 1)); // 若v中没有元素1,则返回的迭代器指向v.end();此时程序会报错
	printContainer(v); // 123 0 123 123 2 123 3
	std::deque<int>::iterator it1 = find(d.begin(), d.end(), 123);
	std::deque<int>::iterator it2 = find(d.begin(), d.end(), 100);
	d.erase(it1, it2);
	printContainer(d); // 100 200 300 400

	// v.pop_front(); //错误,vector没有该方法
	v.clear(); // 清空v中的所有元素:
	std::cout << "now, 容器v总的元素个数:" << v.size() << std::endl;

	//system("pause");
	return 0;
}
  1. 赋值与交换:
    1. c1 = c2; // 将 c2 中的元素复制到 c1 中,直接覆盖;两种容器类型必须相同;
    2. c.assign(b, e); // 使用 assign 赋值,两种容器类型兼容即可;
    3. c.assign(n, t); // 将 c 替换 n 个值为 t 的元素;
    4. c1.swap(c2); // 将 c1 与 c2 中的元素交换;类型必须相同;
#include<iostream>
#include<vector>
#include<deque>
#include<list>
#include<string>
#include<algorithm>

template <typename Container>
void printContainer(const Container& con, std::string str)
{
	std::cout << str.c_str();
	for (Container::const_iterator con_it = con.begin(); con_it != con.end(); ++con_it)
		std::cout << *con_it << " ";
	std::cout << "\n------------------------------" << std::endl;
}

int main()
{
	std::vector<int> v1, v2, v3;
	// 9:
	v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4);
	v2.push_back(10); v2.push_back(20); v2.push_back(30);
	v3.push_back(100); v3.push_back(200); v3.push_back(300); v3.push_back(400); v3.push_back(500); v3.push_back(600);
	v1.swap(v2);
	printContainer(v1, "now, v1容器中的元素:"); // 10 20 30
	printContainer(v2, "now, v2容器中的元素:"); // 1 2 3 4
	v2 = v1;
	printContainer(v2, "now, v2容器中的元素:"); // 10 20 30
	v1.assign(v3.begin(), --v3.end()); 
	printContainer(v1, "now, v1容器中的元素:"); // 100 200 300 400 500

	std::vector<std::string> vs;
	std::list<char *> vc;
	vs.push_back("string "); vs.push_back("hello "); vs.push_back("world ");
	vc.push_back("C++"); vc.push_back("C"); vc.push_back("python"); vc.push_back("java");
	vs.assign(vc.begin(), vc.end());
	//vc.assign(vs.begin(), vs.end()); // 错误,string类型不能转成字符指针 char*
	printContainer(vs, "now, vs容器中的元素:"); // C++ C python java
	vc.assign(10, "Hello ");
	vs.assign(5, "World! ");
	printContainer(vs, "now, vs容器中的元素:"); // World!  World!  World!  World!  World!
	printContainer(vc, "now, vc容器中的元素:"); // Hello  Hello  Hello  Hello  Hello  Hello  Hello  Hello  Hello  Hello

	//system("pause");
	return 0;
}
  1. 关系运算符,所有容器类型均可使用,比较容器必须具有相同的容器类型,基于容器内元素的比较,容器内元素必须有相应的关系运算符(eg. 若两个vector<类>相比较,则该类之间必须能相互比较,即该类重载了相应的运算符)。
#include<iostream>
#include<vector>
#include<deque>
#include<list>
#include<string>
#include<algorithm>

int main()
{
	std::vector<int> v1 = { 1,3,5,7,9, 10 }, v2 = {0, 2,4,6,8,12,23};
	std::vector<int> v3(v1);
	// 10:
	if (v1 > v2)
		std::cout << "容器v1大!\n";
	v2.erase(v2.begin()); // 删除v2第一个元素;
	if (v1 < v2)
		std::cout << "容器v2大!\n";
	if (v1 == v3)
		std::cout << "容器v1和v3一样大!\n";
	//vector<int> 类型容器和vector<double> 以及 list<int> 等因为类型不一样,都不能比较;
	// 个人感觉容器比较和字符串比较大小的逻辑完全一样!!!
	// 若两个vector<类>相比较,则该类之间必须能相互比较,即该类重载了相应的运算符;

	system("pause");
	return 0;
}
  1. 顺序容器的选取,vector,list,deque的优缺点;根据插入访问等操作需要的时间来判断:
    1. vector较list缺点:
      1. vector push_back数据时,若其容量满了,则需要创建一个更大的数组,将原来的内容拷贝进去,然后在添加该元素,所以有些时候vector容器在push_back时会比较慢,但是list就不会有这种情况,list在任何时候push_back都很快;
      2. 对于insert,vector会把相应的元素全部向后移动,然后才把该元素插入到相应的位置,所以理论上vector的insert速度比list的插入速度要慢;
      3. 对于erase与insert同理;
    2. vector较list优点:
      1. 在sort和find操作时,vector等可以通过快速排序和二分查找,排序和查找速度很快,但list容器操作速度相对较慢;
    3. deque也能使用快速排序和二分查找(因为能通过下标索引访问元素)的所有操作都比vector稍微慢,但deque可以在两端操作,而vector只能在末端操作,deque操作更灵活。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值