博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++进阶篇一:C++ 标准模板库之容器和迭代
阅读量:6122 次
发布时间:2019-06-21

本文共 19637 字,大约阅读时间需要 65 分钟。

  hot3.png

C++容器

容器(container)是C++中能够存储几乎任何数据类型的数据结构,分为一级容器、容器适配器以及类容器。不同的容器有一些共同的成员函数,通过迭代(在性质上与指针相似)可以实现对容器元素的操作。不同容器支持的迭代(具体来说是迭代权限)是不同的,这也决定了它们所能用于的算法是不同的(因为每种算法都有其特定支持的迭代类型)。内置数组也可以作为标准库算法的操作对象,此时它的指针就作为迭代。

以下为C++容器共有的成员函数:

  • 默认构造函数:初始化一个空容器
  • 复制构造函数:复制一个现存同类型容器
  • 移动构造函数:(C++11)将一个容器中的内容移到另一个同类型容器中
  • 析构函数:详见
  • empty方法:判断容器是否为空
  • size方法:返回容器中现有元素个数,forward_list不能用
  • max_size方法:返回一个容器中所能融入的最大元素个数
  • operator=:用于复制容器内容。特别地,在C++11中用于移动容器内容。
  • operator<, operator<=, operator>, operator>=, operator==, operator!=:比较不同容器之间的属性
  • insert方法:向容器中插入元素
  • swap方法:交换两个容器的元素,C++11中作为一个使用移动构造函数的全局函数,用于交换同类型容器的地址。
  • begin方法:可返回iterator或const_iterator,用于指向容器的第一个元素
  • end方法:可返回iterator或const_iterator,用于指向容器最后一个元素的后一个位置
  • rbegin方法:可返回iterator或const_iterator,用于指向容器的最后一个元素
  • rend方法:可返回iterator或const_iterator,用于指向容器的第一个元素的前一个位置
  • cbegin:(C++11)返回const_iterator,用于指向容器的第一个元素
  • cend, crbegin和crend则可以以此类推
  • erase:从容器中删除一个或多个元素
  • clear:删除容器中所有元素(对array不适用)

C++容器共有函数使用注意点:

  1. <, <=, >, >=, ==和!=不能用于优先队列
  2. <, <=, >和 >=不能用于非顺序关联型容器(后面会详细解释)
  3. rbegin, rend, crbegin和crend不能用于forward_list

各类型容器简介如下:

一级容器:

一级容器分为序列型容器、顺序关联型容器和非顺序关联型容器。

  • 序列型容器:vector,deque, list, forward_list(为单链表,C++11新特性), array
  • 顺序关联型容器(容器中的key是排序好的):set和map(不允许重复key,此外在C++11中key是不可修改的), multiset和multimap(允许重复的key,此外在C++11中key是不可修改的)。这些头文件分别是<set>和<map>
  • 非顺序关联型容器(因为容器中的key未排序,所以性能方面可能更出色):unsorted_set, unsorted_map, unsorted_multiset和unsorted_multimap,用法与对应的顺序关联型容器类似。

在具体的算法实现方面,如果需要在容器最后进行频繁插入删除操作的话,则vector是一个理想的选择(因为vector为连续存储结构);如果需要频繁在两头进行插入删除操作,则deque是一个理想选择;如果需要在任意位置进行插入或删除操作,则list是一个理想选择。 **容器适配器:**栈、队列和优先队列 **类容器:**内置数组、比特集合(bitsets,用于对于标志集合(即flag values)和数值数组进行快速数学向量运算时使用)

C++各容器特有常用函数归纳:

序列型容器:

  • assign(n, val):将容器中的元素改为出现n次的val值。
  • assign(iters_begin, iters_end):将元素中的元素改为从begin到end的一个序列。

vector 容器(使用见例2和例3)

  • push_back(val):在vector末尾添加一个val元素
  • size:返回vector中元素的个数
  • capacity: 返回vector中能够存储的最多元素的个数
  • shift_to_fit:使得capacity与size相同,但是视编译环境不同,此指令可能被忽略。
  • at(index): 读写相应index的元素,对index范围作出检查。
  • insert(iter_index, ele):在用迭代(以begin()或cbegin()作为0加index)计算出来的index处插入ele。
  • insert(iter_insert_index, iter_start_range, iter_end_range):在被插入元素的(用迭代表示的)insert_index处插入(用迭代表示的)从start_range到end_range的一个系列。
  • erase(iter_index):删除迭代表示的index处相应元素。
  • erase(iter_begin, iter_end):删除用迭代表示的从begin到end的元素。
  • front:返回指向第一个元素的地址。
  • back:返回最后一个元素的地址。

list 容器(使用见例4)

  • push_front(ele):在list前端增加元素ele,此方法仅适用于forward_list, list和queue。
  • push_back(ele):类似vector的同名函数
  • sort:注意此处的sort与STL的sort是不同的,list特有的sort无传入参数并且默认对list中的元素按非降序排序。
  • reverse():将列表中的元素倒置。
  • splice(iter_insert_index, list& b):将list b插入本list由iterator指定的下标处并将其中所有元素删除。
  • splice(iter_insert_index, list& b, iter_delete_index):从list b中删除由迭代delete_index确定的那一个元素,并将list b中所有元素插入insert_index后删除list b中的所有元素。
  • splice(iter_insert_index, list& b, iter_start_delete_index, iter_end_delete_index):从list b中删除由迭代start_delete到end_delete中的一个范围内的元素,并将list b中所有元素插入insert_index后删除list b中的所有元素。
  • merge(list &b):(前提是本列表和列表b都已经排好序)将list b元素merge到本列表中,默认为升序排列。
  • unique():删除列表中重复的元素,每个元素仅出现一次。
  • swap(list &b):将本列表与b列表的所有元素对换。
  • remove(ele):从list中删去ele元素。
  • remove_if(未完待续)

deque 容器

与所有的vector操作基本类似,又增加了push_front和pop_front方法。

关联型容器:

  • find(x):在容器中寻找x元素并返回x元素位置的迭代。若未找到x,则返回end()位置的迭代。

multiset< T, compareObj >: (使用见例5),T为元素类型,compareObj为比较方式,一般情况下为less<T>

  • count(val):统计元素val在multiset中出现的次数
  • insert(val):将元素val插入multiset
  • insert(iter_index, val):将元素val插入iter_index
  • insert(a.iter_start(), a.iter_end()):将a容器一定范围内的值插入multiset,注意iter_start和iter_end表示反应容器元素下标的迭代
  • lower_bound(x):返回该元素最早出现的位置下标的迭代。若不存在该元素返回end位置的迭代。
  • upper_bound(x):返回该元素最晚出现的位置下标的迭代。若不存在该元素返回end位置的迭代。
  • equal_range(x):返回包含lower_bound和upper_bound两个迭代的一对元素对象(pair object),一般被赋值给自动类型的变量(如auto p)。分别用p.first和p.second两个常量获得。在去指针化时要注意这两个指针没有指向end()或rbegin()以及类似实际不存在元素的位置。

set: 与multiset一样,除了插入重复key时操作会被忽略。

multimap<T1, T2, compareObj>:(使用见例6)此处compareObj针对的是key。multimap建立了从键到值的多对一关系。

特别地,在C++11中,一个多重映射的初始化可以写成例如如下的形式:

multimap
> mMaps = { {10, 22.2}, {20, 9.345}, {5, 77.4} };
  • make_pairs:一般使用方式为mMap.insert(make_pair(key, val)); 用于向multimap中插入键值对。
  • insert(pairObj):像multimap中插入一个组对象。
  • insert({key, val}):以列表初始化的方式插入键值对。
  • pair.first:取得某个键值对的键。
  • pair.second:取得某个键值对的值。
  • count(key):统计key这个键在multimap中出现的次数。

map:在C++中用来表示严格的一对一映射。

在multimap的基础上多了用下标读取的功能。如pairs[25]表示读取map pairs中键为25的值。

容器适配器:

栈(头文件<stack>):C++中,栈可用vector, list或者deque实现(默认为deque实现)。举例如下:

stack
intDequeStack; //Stack with underlying deque.stack
> intVStack; //Stack with underlying vectorstack
> intListStack; //Stack with underlying list

队列(头文件<queue>):同样,队列也可以由vector, list或者deque实现(默认为deque实现)。常用方法如下:

优先队列:包含功能与队列完全一致,只是自动将最大的元素通过调堆放在队头。算法上的实现方式为堆(heap)。可以通过声明comparator改变推出顺序。

类容器:

bitset:编译时尺寸固定的一种用来操作比特集合的容器。定义容器示例:

//Size is an unsigned integer:bitset
b;

C++迭代器

C++的迭代用于指向一级容器、序列或范围(sequences or ranges,比如输入流和输出流),适用前面提到的begin和end方法。其中,迭代器的权限从高到低分为任意存取(random access)、双向迭代(bidiretional)、单向迭代(forward)以及输入输出流(input和output,属于同级别)。其中,高级权限的迭代器拥有本级别以及所有低于其级别的迭代权限。

各个迭代权限所对应的操作如下(从高级别权限到低级别权限):

  1. 随机存取级别:p += i, p -= i, p + i, i + p, p - i, p[i](从p所指位置开始存取对应第加i个位置操作), p - p1(p和p1的距离之差), p < p1(p的位置是否在p1之前), p <= p1, p > p1以及p >= p1
  2. 双向迭代:--p, p--
  3. 向前迭代:提供所有输入和输出级别的操作
  4. 输出迭代:*p, p1 = p2
  5. 输入迭代:*p, p->m(通过迭代读取元素m), p1 == p2, p1 != p2
  6. 所有级别:++p, p++, p1 = p2 (将迭代p2赋给迭代p1)

注意:++操作对于反向迭代对象(reverse_iterator和const_reverse_iterator)来说是指向当前元素的前一个元素。

前文提到,不同的一级容器所对应的迭代权限是不同的,各一级容器的迭代权限如下:

  1. 随机存取级别:vector, array, deque
  2. 双向迭代级别:list, 顺序关联型容器、非顺序关联型容器
  3. 向前迭代级别:forward_list

C++标准模版容器常用异常

以下为若干C++ 标准模版库使用的例子:

例1:使用输入流读取两个整数进行相加:

// Fig. 15.4: fig15_04.cpp// Demonstrating input and output with iterators.#include 
#include
// ostream_iterator and istream_iteratorusing namespace std;int main(){ cout << "Enter two integers: "; // create istream_iterator for reading int values from cin istream_iterator< int > inputInt( cin ); int number1 = *inputInt; // read int from standard input ++inputInt; // move iterator to next input value int number2 = *inputInt; // read int from standard input // create ostream_iterator for writing int values to cout ostream_iterator< int > outputInt( cout ); cout << "The sum is: "; *outputInt = number1 + number2; // output result to cout cout << endl;} // end main

输入图片说明

本例中,ostream_iterator<int>为只输出int类型(或其兼容类型)的输出流,它的头文件是<iterator>

例2: vector扩展、获取容量以及元素数量、迭代器使用若干操作

// Fig. 15.10: Fig15_10.cpp// Demonstrating Standard Library vector class template.#include 
#include
// vector class-template definitionusing namespace std;// prototype for function template printVectortemplate < typename T > void printVector( const vector< T > &integers2 );int main(){ const size_t SIZE = 6; // define array size int values[ SIZE ] = { 1, 2, 3, 4, 5, 6 }; // initialize values //vector< int > integers(4); // create vector of ints vector
integers; cout << "The initial size of integers is: " << integers.size() << "\nThe initial capacity of integers is: " << integers.capacity(); // function push_back is in vector, deque and list for(int i = 0; i < (sizeof(values) / sizeof(int)) ; i++) integers.push_back(values[i]); //Size is 7 and capacity becomes 8 in this case. cout << "\nThe size of integers is: " << integers.size() << "\nThe capacity of integers is: " << integers.capacity(); //Cause the vector to be cleaned up: integers.resize(4); integers.shrink_to_fit(); cout << "\nThe size of integers is: " << integers.size() << "\nThe capacity of integers is: " << integers.capacity(); cout << "\n\nOutput built-in array using pointer notation: "; // display values using pointer notation for ( const int *ptr = begin( values ); ptr != end( values ); ++ptr ) cout << *ptr << ' '; cout << endl; cout << "Output vector using ptr notation: "; for(auto ptr = begin(integers); ptr != integers.end(); ptr++) cout << *ptr << ' '; cout << "\nOutput vector using iterator notation: "; printVector( integers ); cout << "\nReversed contents of vector integers: "; // display vector in reverse order using const_reverse_iterator for ( auto reverseIterator = integers.crbegin(); reverseIterator!= integers.crend(); ++reverseIterator ) cout << *reverseIterator << ' '; cout << endl;} // end main// function template for outputting vector elementstemplate < typename T > void printVector( const vector< T > &integers2 ){ // display vector elements using const_iterator for ( auto constIterator = integers2.cbegin(); constIterator != integers2.cend(); ++constIterator ) cout << *constIterator << ' '; cout << endl; // //Can also be following way:// for(auto const item : integers2)// cout << item << ' ';} // end function printVector

输入图片说明

注意:capacity方法视编译器不同,效果可能不同。调用shrink_to_fit()方法(C++11中)能够使得容器的capacity和元素个数相等。

例3:Vector insert, copy, erase, clean以及异常处理

// Fig. 15.11: fig15_11.cpp// Testing Standard Library vector class template // element-manipulation functions.#include 
#include
// array class-template definition#include
// vector class-template definition#include
// copy algorithm #include
// ostream_iterator iterator#include
// out_of_range exceptionusing namespace std;int main(){// const size_t SIZE = 6; // array< int, SIZE > values = { 1, 2, 3, 4, 5, 6 };// vector< int > integers(values.cbegin(), values.cend()); int values[] = {1, 2, 3, 4, 5, 6}; vector
integers; integers.insert(integers.begin(), begin(values), end(values));// for(int i : values)// integers.push_back(i); ostream_iterator< int > output( cout, " " ); cout << "Vector integers contains: "; copy( integers.cbegin(), integers.cend(), output ); cout << "\nFirst element of integers: " << integers.front() << "\nLast element of integers: " << integers.back(); integers[ 0 ] = 7; // set first element to 7 integers.at( 2 ) = 10; // set element at position 2 to 10 // insert 22 as 2nd element integers.insert( integers.cbegin() + 1, 22 ); cout << "\n\nContents of vector integers after changes: "; copy( integers.cbegin(), integers.cend(), output ); // access out-of-range element try { integers.at( 100 ) = 777; } // end try catch ( out_of_range &outOfRange ) // out_of_range exception { cout << "\n\nException: " << outOfRange.what(); } // end catch // erase first element integers.erase( integers.cbegin() ); cout << "\n\nVector integers after erasing first element: "; copy( integers.cbegin(), integers.cend(), output ); // erase remaining elements integers.erase( integers.cbegin(), integers.cend() ); cout << "\nAfter erasing all elements, vector integers " << ( integers.empty() ? "is" : "is not" ) << " empty"; //insert elements from the array values //integers.insert( integers.cbegin(), values.cbegin(), values.cend() ); //If values is a built in type array, this sentence is: integers.insert(integers.cbegin(), begin(values), end(values)); cout << "\n\nContents of vector integers before clear: "; copy( integers.cbegin(), integers.cend(), output ); // empty integers; clear calls erase to empty a collection integers.clear(); cout << "\nAfter clear, vector integers " << ( integers.empty() ? "is" : "is not" ) << " empty" << endl;} // end main

输入图片说明

// insert 22 at 2nd element 4 timesintegers.insert(integers.begin() + 1, 4, 22);

例4:list容器使用示例:

// Fig. 15.13: Fig15_13.cpp// Standard library list class template.#include 
#include
#include
// list class-template definition#include
// copy algorithm#include
// ostream_iteratorusing namespace std;// prototype for function template printListtemplate < typename T > void printList( const list< T > &listRef );int main(){ const size_t SIZE = 4; array< int, SIZE > ints = { 2, 6, 4, 8 }; list< int > values; // create list of ints list< int > otherValues; // create list of ints // insert items in values values.push_front( 1 ); values.push_front( 2 ); values.push_back( 4 ); values.push_back( 3 ); cout << "values contains: "; printList( values ); values.sort(); // sort values cout << "\nvalues after sorting contains: "; printList( values ); // insert elements of ints into otherValues otherValues.insert( otherValues.cbegin(), ints.cbegin(), ints.cend() ); cout << "\nAfter insert, otherValues contains: "; printList( otherValues ); // remove otherValues elements and insert at end of values values.splice( values.cend(), otherValues ); cout << "\nAfter splice, values contains: "; printList( values ); values.sort(); // sort values cout << "\nAfter sort, values contains: "; printList( values ); // insert elements of ints into otherValues otherValues.insert( otherValues.cbegin(), ints.cbegin(), ints.cend() ); otherValues.sort(); // sort the list cout << "\nAfter insert and sort, otherValues contains: "; printList( otherValues ); // remove otherValues elements and insert into values in sorted order values.merge( otherValues ); cout << "\nAfter merge:\n values contains: "; printList( values ); cout << "\n otherValues contains: "; printList( otherValues ); values.pop_front(); // remove element from front values.pop_back(); // remove element from back cout << "\nAfter pop_front and pop_back:\n values contains: "; printList( values ); values.unique(); // remove duplicate elements cout << "\nAfter unique, values contains: "; printList( values ); // swap elements of values and otherValues values.swap( otherValues ); cout << "\nAfter swap:\n values contains: "; printList( values ); cout << "\n otherValues contains: "; printList( otherValues ); // replace contents of values with elements of otherValues values.assign( otherValues.cbegin(), otherValues.cend() ); cout << "\nAfter assign, values contains: "; printList( values ); // remove otherValues elements and insert into values in sorted order values.merge( otherValues ); cout << "\nAfter merge, values contains: "; printList( values ); values.remove( 4 ); // remove all 4s cout << "\nAfter remove( 4 ), values contains: "; values.reverse(); printList( values ); cout << endl;} // end main// printList function template definition; uses // ostream_iterator and copy algorithm to output list elementstemplate < typename T > void printList( const list< T > &listRef ){ if ( listRef.empty() ) // list is empty cout << "List is empty"; else { ostream_iterator< T > output( cout, " " ); copy( listRef.begin(), listRef.end(), output ); } // end else} // end function printList

输入图片说明

例 5:multiset以及unordered_multiset使用示例:

// Fig. 15.15: Fig15_15.cpp// Standard Library multiset class template#include 
#include
#include
// multiset class-template definition#include
// copy algorithm#include
// ostream_iteratorusing namespace std;int main(){ const size_t SIZE = 10; array< int, SIZE > a = { 7, 22, 9, 1, 18, 30, 100, 22, 85, 13 }; //There should be a space between the right > of int and the right > of multiset //Otherwise compiling error may occur. multiset< int, less< int > > intMultiset; // multiset of ints ostream_iterator< int > output( cout, " " ); cout << "There are currently " << intMultiset.count( 15 ) << " values of 15 in the multiset\n"; intMultiset.insert( 15 ); // insert 15 in intMultiset intMultiset.insert( 15 ); // insert 15 in intMultiset cout << "After inserts, there are " << intMultiset.count( 15 ) << " values of 15 in the multiset\n\n"; // find 15 in intMultiset; find returns iterator auto result = intMultiset.find( 15 ); if ( result != intMultiset.end() ) // if iterator not at end cout << "Found value 15\n"; // found search value 15 // find 20 in intMultiset; find returns iterator result = intMultiset.find( 20 ); if ( result == intMultiset.end() ) // will be true hence cout << "Did not find value 20\n"; // did not find 20 // insert elements of array a into intMultiset intMultiset.insert( a.cbegin(), a.cend() ); cout << "\nAfter insert, intMultiset contains:\n"; copy( intMultiset.cbegin(), intMultiset.cend(), output ); // determine lower and upper bound of 22 in intMultiset cout << "\n\nLower bound of 22: " << *( intMultiset.lower_bound( 22 ) ); cout << "\nUpper bound of 22: " << *( intMultiset.upper_bound( 22 ) ); // use equal_range to determine lower and upper bound // of 22 in intMultiset auto p = intMultiset.equal_range( 22 ); cout << "\n\nequal_range of 22:" << "\n Lower bound: " << *( p.first ) << "\n Upper bound: " << *( p.second ); cout << endl; int count = 0; while(p.first != intMultiset.begin()){ p.first--; count ++; } cout << "p.first is the " << count << "th index in the set. " << endl; cout << endl; unordered_set
intSet; intSet.insert(a.begin(), a.end()); copy( intMultiset.cbegin(), intMultiset.cend(), output );} // end main

输入图片说明

备注:所有顺序关联型容器中的key(在set中key即元素)必须支持比较型功能函数。在比较类型的声明中(此处为less<int>),被比较的类型必须要与比较功能函数相对应(此处为operator<)。

例6 multimap使用示例

// Fig. 15.17: Fig15_17.cpp// Standard Library multimap class template.#include 
#include
// multimap class-template definitionusing namespace std;int main(){ multimap< int, double, less< int > > pairs; // create multimap cout << "There are currently " << pairs.count( 15 ) << " pairs with key 15 in the multimap\n"; // insert two value_type objects in pairs pairs.insert( make_pair( 15, 2.7 ) ); pairs.insert( make_pair( 15, 99.3 ) ); cout << "After inserts, there are " << pairs.count( 15 ) << " pairs with key 15\n\n"; auto val1 = make_pair( 30, 111.11 ); // insert five value_type objects in pairs pairs.insert( val1 ); pairs.insert({10, 22.2} ); pairs.insert( make_pair( 25, 33.333 ) ); pairs.insert( make_pair( 20, 9.345 ) ); pairs.insert( make_pair( 5, 77.54 ) ); cout << "Multimap pairs contains:\nKey\tValue\n"; // walk through elements of pairs for ( auto mapItem : pairs ) cout << mapItem.first << '\t' << mapItem.second << '\n'; cout << endl;} // end main

输入图片说明

参考资料:

Paul Deitel & Harvey Deitel, C++11程序设计(英文版)(第2版)

转载于:https://my.oschina.net/Samyan/blog/855953

你可能感兴趣的文章
IIS7如何显示详细错误信息
查看>>
C++文件读写详解(ofstream,ifstream,fstream)
查看>>
Android打包常见错误之Export aborted because fatal lint errors were found
查看>>
Tar打包、压缩与解压缩到指定目录的方法
查看>>
新手如何学习 jQuery?
查看>>
配置spring上下文
查看>>
Python异步IO --- 轻松管理10k+并发连接
查看>>
mysql-python模块编译问题解决
查看>>
Oracle中drop user和drop user cascade的区别
查看>>
【Linux】linux经常使用基本命令
查看>>
HTML模块化:使用HTML5 Boilerplate模板
查看>>
登记申请汇总
查看>>
Google最新截屏案例详解
查看>>
2015第31周日
查看>>
在使用EF开发时候,遇到 using 语句中使用的类型必须可隐式转换为“System.IDisposable“ 这个问题。...
查看>>
Oracle 如何提交手册Cluster Table事务
查看>>
BeagleBone Black第八课板:建立Eclipse编程环境
查看>>
在服务器上用Fiddler抓取HTTPS流量
查看>>
文件类似的推理 -- 超级本征值(super feature)
查看>>
【XCode7+iOS9】http网路连接请求、MKPinAnnotationView自定义图片和BitCode相关错误--备用...
查看>>