C++ primer 第五版个人笔记 第九章 顺序容器

9.1 顺序容器概述

  1. 顺序容器类型,vector 可变大小数组,支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢
  2. deque双端队列,支持快速随机访问。在头尾位置插入/删除速度很快
  3. list 双向链表,只支持双向顺序访问,在list中任何位置插入/删除操作速度都很快 
  4. forward_list 单向链表, 只支持单向顺序访问,在链表任何位置进行插入/删除操作都很快
  5. array 固定大小数组。支持快速随机访问,不能添加或删除元素
  6. string 与vector相似的容器,但专门用于保存字符。随机访问快,在尾部插入、删除速度快
  7. forward_list和array是新C++标准增加的类型;新标准库的容器比旧版本快得多;
  8. 某些操作对所有容器类型都使用,见295页
  9. 无序关联容器不支持关系运算符< , <=, >, >=;仅顺序容器的构造函数才能接受大小参数;
  10. forward_list不支持递减运算符--
  11. 当一个容器初始化另一个容器的拷贝时,两个容器的容器类型和元素类型都必须相同;但是用迭代器begin(),end()初始化时不需要,只要迭代器元素能转化成被转化的容器的元素即可;
  12. array与内置数组的一个区别在于array可以进行拷贝或者对象赋值操作而内置数组不可以
    array<int,7> digits={1,2,3,4,5,6,7};
    array<int,7> cpy = digits;         //正确,只要数组类型匹配即合法
    
    int digs[7]={1,2,3,4,5,6,7};
    int cpy[7] = digs;                 //错误,内置数组不支持拷贝或赋值

    由于右边运算对象的大小可能与左边运算对象的大小不同,因此array类型不支持assign,也不允许用花括号包围的值列表进行赋值(有的编译器可以运行);

    int main()
    {
    	array<int, 10> a1 = { 0,1,2,3,4,5,6,7,8,9 };
    	array<int, 10> a2 = { 0 };
    	// a1.assign(a2.begin(),a2.end());             //无法赋值
    	a1 = { 0 };                                    //这里书上说不可以,但是在vs2019中却能成功执行
    	for (auto i : a1)
    	{
    		cout << i << " ";
    	}
    
    	return 0;
    }

     

  13. swap操作速度很快在于它并不对元素进行拷贝,而是把两个容器 内部的数据结构交换;swap两个array会真正交换他们的元素;所以在swap操作后,原容器的迭代器指向的元素不变,但是array是交换了元素,原容器迭代器指向的元素将改为swap后对应位置的值,代码如下

    int main()
    {
    	array<int, 10> a1 = { 0,1,2,3,4,5,6,7,8,9 };
    	array<int, 10> a2 = { 0 };
    	array<int, 10>::iterator iter = a1.begin() + 1;
    	cout << *iter << endl;						//输出1
    	swap(a1, a2);	
    	cout << *iter << endl;						//输出0
    	vector<int>vec1 = { 1,2,3,4 };
    	vector<int>vec2(vec1.begin()+1, vec1.end());
    	vector<int>::iterator iter1 = vec1.begin() + 1;
    	cout << *iter1 << endl;						//输出2
    	swap(vec1, vec2);
    	cout << *iter1 << endl;						//输出2
    
    	return 0;
    }

     

  14. 练习9.14代码,vs2019运行成功

    int main()
    {
    	list<const char*> li = { "hello","myname" };    //这里不写成const char*会报错
    	vector<string> vec(li.cbegin(), li.cend());
    	for (auto str:vec)
    	{
    		cout << str << endl;
    	}
    
    	return 0;
    }

     

9.3 顺序容器操作

  1. 向一个vector, string或deque插入元素会使所有指向容器的迭代器、引用和指针失效; 

  2. 可以通过insert(iter, val)向vector/deque/string中任意位置插入元素,然而这样做会很耗时;

  3. emplace_front/emplace/emplace_back分别对应push_front/insert/push_back函数,他们之间的区别在于emplace操作将参数传递给容器,由容器调用元素的构造函数,对于容器中的元素为自定义的类的情况,可以直接将参数传入,举例

    vector<sales_data> c;
    c.emplace_back("9812-33234",25,15.99) //使用三个参数的sales_data构造函数
    c.push_back(sales_data("9812-33234",25,15.99)) //创造临时sales_data对象,效果相同
    c.push_back("9812-33234",25,15.99) //无法操作

    emplace函数在容器中直接构造元素。传递给emplace函数的参数必须与元素类型的构造函数相匹配;

  4.  

    在容器中访问元素的成员函数(front,back,下标, at)返回的都是引用,如果容器是一个const对象,返回值是const的引用;   

  5.  

    删除deque中出首位位置外的任何元素都会使所有迭代器、引用和指针失效;指向vector或string中删除点之后位置的迭代器、引用和指针都会失效;

  6.  

    不要保存end()返回的迭代器,一旦有操作改变了容器的大小,原迭代器、引用和指针将失效,可能导致意想不到的后果;

  7. capacity()和size()的区别在于size返回已经保存的元素个数,capacity返回在不分配新的内存空间的前提下最多可以保存的元素;

 

9.5 额外的string操作

  1. assign和append函数无需指定要替换string中的哪个部分:assign总是替换string中所有的内容,append总是将新字符追加到string末尾;
  2. 9.5.2节练习,使用find和replace明显比insert和erase简洁
    
    // 下标和replace方法实现
    void findstr(string& s, string& oldVal, string& newVal)
    {
    	string::size_type pos = 0;
    	while ((pos=s.find(oldVal,pos)) != -1)
    	{
    		s.replace(pos, oldVal.size(), newVal);
    		pos = pos + newVal.size();
    	}
    }
    
    //迭代器,insert和erase实现, 很麻烦不推荐
    void findstr(string& s, string& oldVal,const string& newVal)
    {
    	for (auto iter = s.begin(); iter != s.end(); ++iter)
    	{
    		if (*iter == oldVal[0])
    		{
    			int flag = 1;
    			for (int i = 0; i < oldVal.size(); ++i)
    			{
    				if ((*(iter + i) != oldVal[i]) || (iter + i) == s.end())
    				{
    					flag = 0; break;
    				}
    			}
    			if (flag)
    			{
    				iter = s.erase(iter, iter + oldVal.size());
    				iter = s.insert(iter, newVal.begin(), newVal.end()); //这里一定要赋值,否则后面对iter的操作容易越界
    				iter = iter + newVal.size() - 1;
    				if (iter >= s.end()) break;
    			}
    			
    		}
    	}
    }
    
    // compare函数版本
    void findstr(string& s, string& oldVal,const string& newVal)
    {
    	string::size_type pos = 0;
    	string::size_type osize = oldVal.size(), nsize=newVal.size();
    	for (; pos < s.size(); ++pos)
    	{
    		if (s.compare(pos, osize, oldVal) == 0)
    		{
    			s.replace(pos, osize, newVal);
    			pos += newVal.size();
    		}
    	}
    }
    
    

     

  3. find的用法较多的应该是三参数,iterator, string_tofind, pos 

  4. 整数、浮点数转换为字符的最简单方法是to_string(int i)函数,string的操作方法太多,可以反复回来看书

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值