C++ Primer第九章!
#include "stdafx.h"
#include<iostream>
#include<list>
#include<string>
#include<array>
#include<vector>
#include<deque>
#include<forward_list>
#include<stack>
using namespace std;
int main()
{
//容器就是一些特定类型对象的集合,顺序容器为程序员提供了控制元素存储和访问的能力!(即数据按地址顺序存储)
//vector 可变大小的数组,支持快速访问,在尾部之外插入或删除元素都可能很慢
//deque 双端队列,支持快速访问,在头尾位置插入或删除元素速度很快
//list 双向列表,只支持双向顺序访问,在list任何位置插入或删除元素都很快
//forward_list 单向列表,只支持单向顺序访问,在forward_list任何位置插入或删除元素都很快,其迭代器不支持--!
//array 固定大小数组,支持快速访问,不能添加或删除元素
//string 与vector相似的容器,只用于储存字符
//vector和string,元素连续存储,支持下标快速访问;list和forward_list,不支持随机访问,中间插入数据快,内存开销大;deque,支持下标快速访问,支持头尾插入删除元素;array固定大小数组。
//使用原则:1、除非有更好的选择,否则选用vector;2、如果元素很多且在乎内存开销,则不要使用list或forward_list;3、如果程序要求随机访问元素,应使用vector和deque;4、如果程序头尾操作而中间不操作,应选用deque;
//容器通用操作
//iterator 迭代器
//const_iterator const迭代器
//size_type 无符号整型,容器最大容积
//difference_type 带符号整型,两个迭代器之间的距离
//value_type 元素类型
//reference 元素的引用,用value_type &
//const_reference const
//C c 定义容器,默认构造函数构造空容器
//C c1(c2) 构造c2的拷贝c1!创建容器的2种拷贝方式,使用迭代器时两个容器类型和函数类型可以不匹配,只要被拷贝的元素可以隐式转换!
//C c(b,e) 构造c,将迭代器b和e指定范围内的元素拷贝到c。
//C c{a,b,c...} 列表初始化c
//C seq(n),seq(n,t) seq包含n个元素,这些元素值被初始化(string不适用)。只有顺序容器才接受大小参数(不包括array)
//c1=c2 将c1中元素替换为c2中元素
//c1={a,b,c...} 将c1中元素替换为列表中元素
//a.swap(b) 交换容器a和容器b中的元素
//swap(a,b) 等价于上
//c.size() 返回c中的元素数目(不支持单向forward_list)
//c.max_size() 返回c中所能容纳最大元素数目
//c.empty() 容器c是否为空,当size为0返回true
//c.insert(args) 将args中元素拷贝进c
//c.emplace(inits) 使用inits构造c中的一个元素
//c.rease(args) 删除指定元素
//c.clear() 删除所有元素
//==,!=,<,> 容器关系运算符,关系运算符左右两边的运算对象必须是相同类型的容器和相同类型的元素(元素必须定义了比较运算符)
//c.begin(),c.cbegin(),c.end(),c.cend() 迭代器
//reverse_iterator,const_reverse_iterator,c.rbegin(),c.rend(),c.crbein(),c.crend() 反向迭代器,执行++操作,会得到上一个元素!
list<string> a = { "aa","bb","cc" };
list<string> b(a);
auto beg = a.crbegin();
while (beg!=a.crend())
{
cout << " " << *beg;
++beg;
}
cout << endl;
//标准库array初始化方式
array<int, 10> ary1; //类型为:保存10个int的数组
array<int, 10> ary2 = { 0,1,2,3,4 };
array<int, 10> ary3 = ary2; //不能对内置数组进行拷贝或对象赋值,但是array可以,不过却不能使用ary3={0}形式!(元素类型和大小必须相同)
//容器赋值运算(适用于所有容器)
//c1=c2
//c={a,b,c} array不适用
//swap(c1,c2)
//c1.swap(s2) 交换两个相同类型容器的内容
//assign操作不适用于关联容器和array,assign将右侧运算对象中所有元素拷贝到左边元算对象中
//seq.assign(b,e) 将seq中元素替换为迭代器be所示范围内的元素,迭代器不能指向seq
//seq.assign(il) 将seq中的元素替换为初始化列表il中的元素
//seq.assign(n,t) 将seq中的元素替换为n个值为t的元素(assign是分配的意思!)
list<string> lst1 = { "aa","bb","cc" };
vector<string> vec1;
vec1.assign(lst1.cbegin(), lst1.cend());
list<string> lst2;
swap(lst1, lst2); //除了array外,swap不对任何元素进行操作,因此保证操作时间很短!
lst2.insert(lst2.cbegin(), { "a","b" });
if (lst1 == lst2)
cout << "lst1 等于 lst2" << endl;
else
cout << "lst1 不等于 lst2" << endl;
//顺序容器特有操作!这些操作会改变容器的大小,array不支持这些操作!
//forward_list有自己专用insert和emplace,并且不支持push_back和emplace_back。
//vector和string不支持push_front和emplace_front
//当用对象初始化容器,或者将一个对象插入容器中,实际放入的是拷贝,而不是对象本身!
//将元素插入(insert)到vector、deque、string合法,但是很耗时!
//c.push_back(t)
//c.emplace_back(args)
//c.push_front(t)
//c.emplace_front(args) args为实参,传递给类的构造函数,直接在容器内构造元素。c.emplace_back(a,b,c)等价于c.push_back(class(a,b,c))!
//c.insert(p,t) 在迭代器p指向元素之前创建一个值为t的元素(或由args创建的元素),返回指向新元素的迭代器!
//c.emplace(p,args)
//c.insert(p,n,t) 同下
//c.insert(p,b,e) 同下
//c.insert(p,il) il为花括号包围的元素值列表({a,b,c}),插到迭代器p指向元素之前,返回指向新添加的第一个元素的迭代器,若列表为空返回p!
//顺序容器中访问元素的操作
//at和下标操作只适用于string、vector、deque、array
//back不适用于forward_list
//c.back() 返回c中尾元素的引用,若c为空则函数行为未定义
//c.front() 返回c中首元素的引用···
//c[n] 返回c中下标为n的元素的引用,n为无符号整数,若n>c.size(),则行为未定义
//c.at(n) 同上,但是如下标越界,抛出out_of_range异常!推荐使用at函数!
deque<int> deq1 = { 1,2,3 };
auto &r = deq1.front(); //使用auto&获取第一个元素的引用!
r = 3;
//顺序容器删除元素。这些操作会改变容器的大小,array不支持这些操作!
//forward_list有特殊版本的erase,并且不支持pop_back;vector和string不支持pop_front
//c.pop_back() 删除c中尾元素。若c为空,则行为未定义。
//c.pop_front() 删除c中首元素。若c为空,则行为未定义。
//c.erase(p) 删除迭代器P所指元素,返回被删除元素之后元素的迭代器。若p指向尾迭代器,行为未定义!
//c.erase(b,e)
//c.clear() 删除所有元素!
//特殊的forward_list操作,单向链表,只有后驱(指向下一个元素)
//lst.before_begin() 返回首元素之前不存在元素的迭代器,此迭代器不能解引用
//lst.cbegore_begin()
//lst.insert_after(p,t) 在迭代器p之后插入元素t。若p为尾后迭代器,则函数行为未定义!
//lst.insert_after(p,n,t)
//lst.insert_after(p,b,e)
//lst.insert_after(p,il)
//lst.emplace_after(p,args)
//lst.erase_after(p)
//lst.erase_after(b,e) 返回被删元素之后元素的迭代器!
forward_list<int> flst = { 1,2,3,4,5,6 };
auto prev = flst.before_begin();
auto curr = flst.begin();
while (curr != flst.end())
{
if (*curr % 2)
curr = flst.erase_after(prev); //删除某个元素,要使用指向前一个元素的迭代器!该函数返回指向被删元素之后的迭代器
else
{
prev = curr;
curr++;
}
}
for (auto &r : flst)
{
cout << r << "--";
}
cout << endl;
//改变容器大小,array不支持resize()
//c.resize(n) 若容器缩小,则删除多余元素;若容器扩大,则默认初始化(推荐使用t初始化!)
//c.resize(n,t)
//容器的操作可能会使迭代器(包括指针、引用)失效!必须保证每次改变容器的操作后都能正确地重新定位迭代器!(每次操作后必须重新调用end()获取尾后迭代器)
//vector对象是如何增长的?vector和string通常会分配比需求更大的空间,留作备用!
//shrink_tofit只使用于vector、string和deque
//capacity和reserve只适用于vector和string
//c.shrink_to_fit() 将capacity减小为与size()相同大小,但不保证一定退回内存空间
//c.capacity() 不重新分配内存,c可以保存多少元素
//c.reserve(n) 分配至少能容纳n个元素的内存空间(调用reserve后,capacity将会大于或等于n)
vector<int> vec_cap = { 0,1,2,3 };
vec_cap.push_back(4);
cout << vec_cap.size() << " " << vec_cap.capacity()<<endl;
//额外的string操作
//n,len2和pos2都是无符号值
//string s(cp,n) cp指向数组的前n个字符的拷贝(char *cp)
//string s(s2,pos2) 从string s2的下标pos2开始的拷贝,如果pos2越界,行为未定义!
//string s(s2,pos2,len2) 至多拷贝s2.size()-pos2(遇见空字符结尾停止)
//s.substr(pos,n) 返回一个string,包含s从pos开始的n个字符,pos的默认值为0,n的默认值为s.size()-pos。
//修改string的操作,P324
//s.insert(pos,args),s.erase(pos,len),s.assign(args)(替换所有内容),s.append(args)(将新字符追加到末尾),s.replace(range,args).(args实参可以是str/str,pos,len/cp,len/cp/n,c/b,e/初始化列表等)
//string搜索操作,如果搜索成功则返回string::size_type()下标值(无符号类型,建议使用无符号类型保存函数返回值),如果搜索失败则返回string::npos的static成员。
//s.find(args) 查找args第一次出现的位置
//s.rfind(args) 查找args最后一次出现的位置
//s.find_first_of(args) 在s中查找args任何一个字符第一次出现的位置
//s.find_last_of(args) 在s中查找args任何一个字符最后出现的位置
//s.find_first_not_of(args) 在s中查找第一个不再args中的位置
//s.fing_last_not_of(args) 在s中查找最后一个不再args中的位置
//args必须是如下形式:c,pos/s2,pos/cp,pos/cp,pos,n(pos和n无默认值)等。其余pos默认值为0!
string s_out_exp = "-a-b-c";
cout << s_out_exp.substr(s_out_exp.find_first_of("-")+1)<<endl;
//string的比较compare函数,根据结果等于、大于、小于,返回0、整数、负数!
//s.compare(args),其参数args有如下形式:s2/pos1,n1,s2/pos1,n1,s2,pos2,n2/cp/pos1,n1,cp/pos1,n1,cp,n2
string s_out_com = "-b";
cout << s_out_com.compare(s_out_exp) << endl;
//string的数值转换
//to_string(val) 返回数值val的string表示
//stoi(s,p,b)/stol(a,p,b)/stoul/stoll/stoull/,b表示基数(默认为10),若转换失败返回out_of_range异常
//stof(s,p)/stod/stold
string s_pi = "pi=3.14";
double d_pi;
d_pi = stod(s_pi.substr(s_pi.find_first_of("+-.0123456789"))); //第一个非空白字符必须是···
cout << d_pi << endl;
//容器适配器,即stack栈、queue队列、priority_queue,是某种事物的行为看起来像另一种事物!
//所有容器适配器都支持的操作
//size_type 一种类型,大小
//value_type 元素类型
//container_type 适配器底层容器类型
//A a 创建空适配器a
//A a(c) 创建适配器a,带有容器c的一个拷贝
//a.empty()
//a.size()
//swap(a,b)/a.swap(b) 同类型,且底层容器类型相同
//stack只要求push_back、pop_back和back操作,可以使用deque/list/vector容器!queue要求使用back、push_back、front、push_front,可以使用list/deque/vector容器!priority_queue要求使用front、push_back、pop_back、随机访问能力,可以使用vector和deque!
deque<int> deq_sta = { 0 };
stack<int> stk(deq_sta); //默认情况stack和queue是基于deque实现的,priority_queue是基于vector实现的!
stack<string, vector<string>> str_stk;
//stack操作,不能使用deque的操作,只能使用自己的!(先进后出)
//s.pop() 删除栈顶元素,但不返回该值!
//s.push(item) 创建新元素,压入栈顶
//s.emplace(args)
//s.top() 返回栈顶元素,但不将元素删除
str_stk.push("abc");
cout << str_stk.top() << endl;
//queue和priority_queue队列的操作(queue先进先出,priority_queue为每个元素建立优先级(默认使用<运算符),新加入元素根据优先级排列(饭店根据预约时间排座,而不是到店时间))
//q.pop() 删除queue首元素或priority_queue最高优先级元素,但不返回此元素
//q.front() 返回首元素或尾元素,但不删除此元素
//q.back() 只适用于queue
//q.top() 返回最高优先级元素,但不删除此元素,只适用priority_queue
//q.push(item) 在queue末尾或priority_queue中适当位置创建一个元素
//q.emplace(args)
system("pause");
return 0;
}
//容器是c++相当重要的一部分,推荐使用好容器!