《C++Primer》 第09章 容器与算法
@学习摘录072:顺序容器
——将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素,这就是顺序容器。
——vector支持快速随机访问
——list支持快速插入/删除
——deque双端队列
@学习摘录073:顺序容器适配器
——适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型。
——stack后进先出(LIFO)栈
——queue先进先出(FIFO)队列
——priority_queue有优先级管理的队列
第一节:顺序容器的定义(初始化)
@学习摘录074:新建一个容器初始化为另一个容器的副本
——vector<int> ivec;
——vector<int>ivec2(ivec); // ok, ivec is vector<int>
——将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同。
“并不需要考虑原容器中的元素数量.”自动增长了呗!
@学习摘录075:初始化为一段元素的副本
——系统允许通过传递一对迭代器间接实现该功能。使用迭代器时,不要求容器类型相同,容器内的元素类型也可以不相同,只要它们相互兼容能进行转换即可。
——list<string>slist(svec.begin(), svec.end() );
——//find midpoint in the vector
——vector<string>::iteratormid = svec.begin() + svec.size() / 2;
——//initialize front with first half of svec: The elements up to but noteinclude *mid
——deque<string>front(svec.begin(), mid); ‘ Good !左闭右开 ’
——//initialize back with second half of svec: The elements *mid throughend of svec
——deque<string>back(mid, svec.end() );
摘录有想075:
——利用迭代器复制相当的方便,减少了很多限制,还可以不同类型的复制,只是也要考虑到一个方面,稳定性,如果需要隐式转换的地方还是少用的好。一段段的复制挺好的。同时,注意考虑它的区间是左闭右开的区间来的。
@学习摘录076:容器内元素的类型约束 “自己定理的类类型就得注意这个问题了!”Good! Good ! Good !
——元素类型必须支持赋值运算。
——元素类型的对象必须可复制。
@学习摘录077:容器的容器
——定义容器的容器时,有一个问题必须得注意的:
——vector<vector<string> > lines; // ok:space required between cblose>
——必须用空格隔开两个相邻的>符号,以示这是两个分开的符号。
@学习摘录078:迭代器范围
——C++语言使用一对迭代器标记迭代器范围,这两个迭代器分别
指向同一个容器中的两个元素或“超出末端的下一位置。” Good!
——该范围内的元素包括迭代器first指向的元素,以及从first开始一直到迭代器last指向的位置之前的所有元素。
——此类元素范围称“左闭合区间(left-inclusiveinterval) 表达式: [first,last)。
@学习摘录079:使用左闭合区间的编程意义
——左闭合区间有两个方便使用的性质,得记住:
——1.当first与last相等时,迭代器范围为空;
——2.当first与last不相等时,迭代器范围内至少有一个元素,而first指向该区间的第一个元素。
第三节:顺序容器的操作
——每种顺序容器都提供了一组有用的类型定义以及以下操作:
——1.在容器中添加元素
——2.在容器中删除元素
——3.设置容器的大小
——4.(如果有的话)获取容器内的第一个和最后一个元素。
@学习摘录080:在顺序容器中添加元素
——在容器中添加元素时,系统是将元素值复制到容器里。
@学习摘录081:在容器中的指定位置添加元素
——看代码后,你懂的! s.insert(迭代器,插入的东西);新元素是插入在迭代器指向的位置之前。返回指向新添加元素的迭代器。
——s.insert(iter,element); // insert element just before iter
摘录有想081:
——考虑到有一种特例:push_back和push_front可以相当于iter为s.begin()和s.end()时。
@学习摘录082:插入一段元素 哦 !Good !不错这样也可以!
——看代码后,你懂的!迭代器插入位置加上迭代器的前后位置构成的左闭合区间。
——stringsarray[4] = {“quasi”, “samba”, “frollo”, “scar”};
——//insert all the element in sarray at end of slist
——slist.insert(slist.end(),sarray, sarray + 4);
@学习摘录083:关系操作符(比较大小)
——/*
—— ivec1:1 3 5 7 9 12
—— ivec2:0 2 4 6 8 10 12
—— ivec3:1 3 9
—— ivec4:1 3 5 7
—— ivec5:1 3 5 7 9 12
——*/
——//ivec2 < ivec1 // true
——ivec1< ivec3 // true
——ivec1< ivec4 // false
——ivec1== ivec5 // true; each element equal and same number of elements
摘录有想083:
——很明显,在容器中,比较大小;
——1.逐位对比,先比大小。 (大者为大)
——2.再比容器长度。(长者为大)
@学习摘录084:删除容器内所有的元素
——slist.clear();
——slist.erase(slist.begin(),slist.end() );
摘录有想084:
——要删除容器内所有的元素,可以调用clear函数,或将begin和end迭代器传递给erase函数。
@学习摘录085:容器中的赋值操作符
——赋值操作符首先删除其左操作数容器中的所有元素;
——然后将右操作数容器的所有元素插入到左边容器中;
——赋值后,左右两边的容器相等;
——赋值前可能两个容器长度不相等,但赋值后两个容器都具有右操作数的长度。
——c1= c2; // replace contents of c1 with a copy of elements in c2
——//equivalent operation using erase and insert
——c1.erase(c1.begin(),c1.end() ); // delete all elements in c1
——c1.insert(c1.begin(),c2.begin(), c2.end() ); // insert c2
@学习摘录086:重设容器
——c.assign(b,e)//重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器。
——c.assign(n,t) //将容器c重新设置为存储n个值为t的元素
——//equivalent to: slist1.clear();
——//followed by slist1.insert(slist1.begin(), 10, “Hiya!”);
——slist1.assign(10,“Hiya!”); // 10 elements; each one is Hiya!
——执行了上述语句后,容器slist1有10个元素,每个元素的值都是Hiya!
摘录有想086:
——assign操作跟赋值操作符的操作原理差不多,都是先清空一个容器,然后再对已清空的容器进行插入操作。
@学习摘录087:交换容器
——swap操作实现交换两个容器内所有元素的功能。
——vector<string>svec1(10); // vector with 10 elements
——vector<string>svec2(24); // vector with 24 elements
——svec1.swap(svec2);
——执行swap后,容器svec1中存储24个string类型的元素,而svec2则存储10个元素。
——关于swap的一个重要问题:
——1.该操作不会删除或插入任何元素;
——2.保证在常量时间内实现交换。
——3.由于容器内没有移动任何元素,因此迭代器不会失效。
摘录有想087:
swap 它的原理是?猜测可能是变了变量的地址,其它一切无发生改变。
第四节:vector容器的自增长
@学习摘录088:vector的增长效率
——为了使vector容器实现快速的内存分配,其实际分配的容量要比当前所需的空间多一些。
——vector容器预留了这些额外的存储区,用于存放新添加的元素。
——于是,不必为每个新元素重新分配容器。
——所分配的额外内存容量的确切数目因库的实现不同而不同。
——比起每添加一个新元素就必须重新分配一次容器,这个分配策略带来显著的效率。
——事实上,其性能非常好,因此在实际应用中,比起list和deque容器,vector的增长效率通常会更高。Good !
@学习摘录089:capacity成员
——弄清capacity(容量)与size(长度)的区别非常重要。
——size指容器当前拥有的元素个数;
——而capacity则指容器在必须分配新存储空间之前可以存储的元素总数。
——vector<int>ivec;
——//size should be zero; capacity is implementation defined
——cout<< “ivec: size: “ << ivec.size()
—— <<“ capacity: “ << ivec.capacity() << endl;
——//give ivec 24 elements
——for(vector<int>::size_type ix = 0; ix != 24; ++x)
—— ivec.push_back(ix);
——//size should be 24; capacity will be >= 24 and is implementationdefined
——cout<< “ivec: size: “ << ivec.size()
—— <<“ capacity: “ << ivec.capacity() << endl;
——结果:
—— ivec:size: 0 capacity: 0
—— ivec:size: 24 capacity: 32
@学习摘录090:选择容器
——下面列举了四种选择容器的法则。
——1.如果程序要求随机访问元素,则应使用vector或deque容器。
——2.如果程序必须在容器的中间位置插入或删除元素,则应采用list容器。
——3.如果程序不是在容器的中间位置,而是在容器首部或尾部插入或删除元素,则应采用deque容器。
——4.如果只需在读取输入时在容器的中间位置插入元素,然后需要随机记问元素,则可考虑在输入时将元素读入到一个list容器,接着对此容器重新排序,使其适合顺序访问,然后将排序后的list容器复制到一个vector容器。
第六节:string类型
@学习摘录091:string类型的查找操作
——几乎所有的查找操作,返回的是string::size_type类型的值,以下标形式标记查找匹配所发生的位置;
——当查找没有匹配值,将返回名为string::npos的特殊值。
@学习摘录092:string类型的定义(一少部分)
——s.find(args)在s中查找args的第一次出现
——s.find_first_of(args)在s中查找args的任意字符的第一次出现
——s.find_last_of(args)在s中查找args的任意字符的最后一次出现
——s.find_first_not_of(args)在s中查找第一个不属于args的字符
——s.find_last_not_of(args)在s中查找最后一个不属于args的字符
摘录有想092:
——这几个定义,看上去,个人将其归纳两点:
——1.find操作可以分为第一次出现的关键字和最后次出现的关键字进行查找的标准。
——2.find操作可以分为查找属于args的字符和不属于args的字符。
——将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素,这就是顺序容器。
——vector支持快速随机访问
——list支持快速插入/删除
——deque双端队列
@学习摘录073:顺序容器适配器
——适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型。
——stack后进先出(LIFO)栈
——queue先进先出(FIFO)队列
——priority_queue有优先级管理的队列
第一节:顺序容器的定义(初始化)
@学习摘录074:新建一个容器初始化为另一个容器的副本
——vector<int> ivec;
——vector<int>ivec2(ivec); // ok, ivec is vector<int>
——将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同。
“并不需要考虑原容器中的元素数量.”自动增长了呗!
@学习摘录075:初始化为一段元素的副本
——系统允许通过传递一对迭代器间接实现该功能。使用迭代器时,不要求容器类型相同,容器内的元素类型也可以不相同,只要它们相互兼容能进行转换即可。
——list<string>slist(svec.begin(), svec.end() );
——//find midpoint in the vector
——vector<string>::iteratormid = svec.begin() + svec.size() / 2;
——//initialize front with first half of svec: The elements up to but noteinclude *mid
——deque<string>front(svec.begin(), mid); ‘ Good !左闭右开 ’
——//initialize back with second half of svec: The elements *mid throughend of svec
——deque<string>back(mid, svec.end() );
摘录有想075:
——利用迭代器复制相当的方便,减少了很多限制,还可以不同类型的复制,只是也要考虑到一个方面,稳定性,如果需要隐式转换的地方还是少用的好。一段段的复制挺好的。同时,注意考虑它的区间是左闭右开的区间来的。
@学习摘录076:容器内元素的类型约束 “自己定理的类类型就得注意这个问题了!”Good! Good ! Good !
——元素类型必须支持赋值运算。
——元素类型的对象必须可复制。
@学习摘录077:容器的容器
——定义容器的容器时,有一个问题必须得注意的:
——vector<vector<string> > lines; // ok:space required between cblose>
——必须用空格隔开两个相邻的>符号,以示这是两个分开的符号。
——否则,系统会认为>>是单个符号,为右移操作符,并结果导致编译时的错误。 细节决定成败。Good!
第二节:迭代器和迭代器范围@学习摘录078:迭代器范围
——C++语言使用一对迭代器标记迭代器范围,这两个迭代器分别
指向同一个容器中的两个元素或“超出末端的下一位置。” Good!
——该范围内的元素包括迭代器first指向的元素,以及从first开始一直到迭代器last指向的位置之前的所有元素。
——此类元素范围称“左闭合区间(left-inclusiveinterval) 表达式: [first,last)。
@学习摘录079:使用左闭合区间的编程意义
——左闭合区间有两个方便使用的性质,得记住:
——1.当first与last相等时,迭代器范围为空;
——2.当first与last不相等时,迭代器范围内至少有一个元素,而first指向该区间的第一个元素。
第三节:顺序容器的操作
——每种顺序容器都提供了一组有用的类型定义以及以下操作:
——1.在容器中添加元素
——2.在容器中删除元素
——3.设置容器的大小
——4.(如果有的话)获取容器内的第一个和最后一个元素。
@学习摘录080:在顺序容器中添加元素
——在容器中添加元素时,系统是将元素值复制到容器里。
@学习摘录081:在容器中的指定位置添加元素
——看代码后,你懂的! s.insert(迭代器,插入的东西);新元素是插入在迭代器指向的位置之前。返回指向新添加元素的迭代器。
——s.insert(iter,element); // insert element just before iter
摘录有想081:
——考虑到有一种特例:push_back和push_front可以相当于iter为s.begin()和s.end()时。
@学习摘录082:插入一段元素 哦 !Good !不错这样也可以!
——看代码后,你懂的!迭代器插入位置加上迭代器的前后位置构成的左闭合区间。
——stringsarray[4] = {“quasi”, “samba”, “frollo”, “scar”};
——//insert all the element in sarray at end of slist
——slist.insert(slist.end(),sarray, sarray + 4);
@学习摘录083:关系操作符(比较大小)
——/*
—— ivec1:1 3 5 7 9 12
—— ivec2:0 2 4 6 8 10 12
—— ivec3:1 3 9
—— ivec4:1 3 5 7
—— ivec5:1 3 5 7 9 12
——*/
——//ivec2 < ivec1 // true
——ivec1< ivec3 // true
——ivec1< ivec4 // false
——ivec1== ivec5 // true; each element equal and same number of elements
摘录有想083:
——很明显,在容器中,比较大小;
——1.逐位对比,先比大小。 (大者为大)
——2.再比容器长度。(长者为大)
@学习摘录084:删除容器内所有的元素
——slist.clear();
——slist.erase(slist.begin(),slist.end() );
摘录有想084:
——要删除容器内所有的元素,可以调用clear函数,或将begin和end迭代器传递给erase函数。
@学习摘录085:容器中的赋值操作符
——赋值操作符首先删除其左操作数容器中的所有元素;
——然后将右操作数容器的所有元素插入到左边容器中;
——赋值后,左右两边的容器相等;
——赋值前可能两个容器长度不相等,但赋值后两个容器都具有右操作数的长度。
——c1= c2; // replace contents of c1 with a copy of elements in c2
——//equivalent operation using erase and insert
——c1.erase(c1.begin(),c1.end() ); // delete all elements in c1
——c1.insert(c1.begin(),c2.begin(), c2.end() ); // insert c2
@学习摘录086:重设容器
——c.assign(b,e)//重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器。
——c.assign(n,t) //将容器c重新设置为存储n个值为t的元素
——//equivalent to: slist1.clear();
——//followed by slist1.insert(slist1.begin(), 10, “Hiya!”);
——slist1.assign(10,“Hiya!”); // 10 elements; each one is Hiya!
——执行了上述语句后,容器slist1有10个元素,每个元素的值都是Hiya!
摘录有想086:
——assign操作跟赋值操作符的操作原理差不多,都是先清空一个容器,然后再对已清空的容器进行插入操作。
@学习摘录087:交换容器
——swap操作实现交换两个容器内所有元素的功能。
——vector<string>svec1(10); // vector with 10 elements
——vector<string>svec2(24); // vector with 24 elements
——svec1.swap(svec2);
——执行swap后,容器svec1中存储24个string类型的元素,而svec2则存储10个元素。
——关于swap的一个重要问题:
——1.该操作不会删除或插入任何元素;
——2.保证在常量时间内实现交换。
——3.由于容器内没有移动任何元素,因此迭代器不会失效。
摘录有想087:
swap 它的原理是?猜测可能是变了变量的地址,其它一切无发生改变。
第四节:vector容器的自增长
@学习摘录088:vector的增长效率
——为了使vector容器实现快速的内存分配,其实际分配的容量要比当前所需的空间多一些。
——vector容器预留了这些额外的存储区,用于存放新添加的元素。
——于是,不必为每个新元素重新分配容器。
——所分配的额外内存容量的确切数目因库的实现不同而不同。
——比起每添加一个新元素就必须重新分配一次容器,这个分配策略带来显著的效率。
——事实上,其性能非常好,因此在实际应用中,比起list和deque容器,vector的增长效率通常会更高。Good !
@学习摘录089:capacity成员
——弄清capacity(容量)与size(长度)的区别非常重要。
——size指容器当前拥有的元素个数;
——而capacity则指容器在必须分配新存储空间之前可以存储的元素总数。
——vector<int>ivec;
——//size should be zero; capacity is implementation defined
——cout<< “ivec: size: “ << ivec.size()
—— <<“ capacity: “ << ivec.capacity() << endl;
——//give ivec 24 elements
——for(vector<int>::size_type ix = 0; ix != 24; ++x)
—— ivec.push_back(ix);
——//size should be 24; capacity will be >= 24 and is implementationdefined
——cout<< “ivec: size: “ << ivec.size()
—— <<“ capacity: “ << ivec.capacity() << endl;
——结果:
—— ivec:size: 0 capacity: 0
—— ivec:size: 24 capacity: 32
@学习摘录090:选择容器
——下面列举了四种选择容器的法则。
——1.如果程序要求随机访问元素,则应使用vector或deque容器。
——2.如果程序必须在容器的中间位置插入或删除元素,则应采用list容器。
——3.如果程序不是在容器的中间位置,而是在容器首部或尾部插入或删除元素,则应采用deque容器。
——4.如果只需在读取输入时在容器的中间位置插入元素,然后需要随机记问元素,则可考虑在输入时将元素读入到一个list容器,接着对此容器重新排序,使其适合顺序访问,然后将排序后的list容器复制到一个vector容器。
第六节:string类型
@学习摘录091:string类型的查找操作
——几乎所有的查找操作,返回的是string::size_type类型的值,以下标形式标记查找匹配所发生的位置;
——当查找没有匹配值,将返回名为string::npos的特殊值。
@学习摘录092:string类型的定义(一少部分)
——s.find(args)在s中查找args的第一次出现
——s.find_first_of(args)在s中查找args的任意字符的第一次出现
——s.find_last_of(args)在s中查找args的任意字符的最后一次出现
——s.find_first_not_of(args)在s中查找第一个不属于args的字符
——s.find_last_not_of(args)在s中查找最后一个不属于args的字符
摘录有想092:
——这几个定义,看上去,个人将其归纳两点:
——1.find操作可以分为第一次出现的关键字和最后次出现的关键字进行查找的标准。
——2.find操作可以分为查找属于args的字符和不属于args的字符。