[c++] Sequence Containers

写在前面

C++ Standard Library

For efficiency reasons, STL is not object-oriented:html

      • Makes little use of inheritance, and
      • Makes no use of virtual functions

 

STL是c++的精华,开始前先在此提一下。linux

有助于整体理解的连接:[C++ STL] 各容器简单介绍ios

The Standard Template Library (STL) is a part of the C++ standard library, Some others are:c++

分类一:算法

      • The C standard library
      • Language support: <exception>, <ctime>, ...
      • Strings: <string>, <cstring>, ...
      • Numerics: <cmath>, <complex>, ...
      • I/O: <iostream>, <fstream>, <cstdio>, ...
      • Exception classes
      • Smart pointers
      • Classes for internationalisation support

分类二:数组

Containers: vector, list, stack, ...
Algorithms: find, sort, copy, ...
Iterators are the glue between the two!安全

 

热身问题

(1) 数据流中的数据按照必定的格式<T>提取 -------> 放在vector中。数据结构

(2) 注意 vector.begin(), vector.front()的区别。"front"是返回当前vector容器中起始元素的引用。less

(3) accumulate()求sum。(与valarrary貌似有一拼,孰优孰劣?---- 可能后者效率更高)ide

accumulate(ivec.begin() , ivec.end() , 0);

(4) multiplies<int>()   c++ --> reference --> <functional> --> multiplies: 与accumulate配合使用构成了连乘的计算

#include<math.h> #include<iostream> #include<fstream> #include<algorithm> #include<functional> #include<numeric> #include<vector> #include<iterator>

int main() { std::vector<int> v; std::ifstream in("numbers.txt"); 
    std::copy(std::istream_iterator<int>(in), std::istream_iterator<int>(), std::back_inserter(v)); for (unsigned int i = 0; i < v.size(); i++) { std::cout << v[i] << std::endl; } 
 std::sort(v.begin(), v.end()); 
    std::cout << "min/max: " << v.front() << " " << v.back() << std::endl; std::cout << "median: " << *(v.begin() + (v.size()/2)) << std::endl;
std::cout
<< "average: " << accumulate(v.begin(), v.end(), 0.0) / v.size() << std::endl; std::cout << "geomean: " << std::pow( accumulate(v.begin(), v.end(), 1.0, std::multiplies<double>()), 1.0/v.size() ) << std::endl; }

(5)  copy()做为输入的技巧,以及map的使用。

int test02(void) { using namespace std; std::vector<string> v;
    std::map<string, int> m; std::ifstream in("words.txt"); std::copy(std::istream_iterator<string>(in), std::istream_iterator<string>(), std::back_inserter(v)); // The number of times it occurs in a file.
    for (auto vi = v.begin(); vi != v.end(); ++vi)     ++m[*vi]; for (auto mi = m.begin(); mi != m.end(); ++mi) std::cout << mi->first << ": " << mi->second << std::endl; return 0; } 

(6) copy()做为输出的技巧:拷贝到ostream。

int test03(void) { std::vector<int> v = {1, 3, 5, 4, 3, 2}; std::string s("string"); std::sort(v.begin(), v.end()); std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ",")); std::cout << std::endl; std::sort(s.begin(), s.end()); std::copy(s.begin(), s.end(), std::ostream_iterator<char>(std::cout, " ")); std::cout << std::endl; return 0; }

 

 

containers 蓝图

c++11新特性

In reality, not all operations are supported in all containers, 

http://www.cplusplus.com/reference/stl/

 

三大container 效率对比

须要逐个实践下,为下一节作准备

 

 

 

Vector

 插入操做

    • resize()

Ref: 关于vector的resize()的理解

resize()的做用是改变vector中元素的数目。

若是n比当前的vector元素数目要小,vector的容量要缩减到resize的第一个参数大小,既n。并移除那些超出n的元素同时销毁他们。

若是n比当前vector元素数目要大,在vector的末尾扩展须要的元素数目,若是第二个参数val指定了,扩展的新元素初始化为val的副本,不然按类型默认初始化。

注意:若是n大于当前的vector的容量(是容量,并不是vector的size),将会引发自动内存分配。因此现有的pointer, references, iterators将会失效。

int func_vector_insert(void) { cout << "== vector insert() show ==" << endl; std::vector<int> myvector (3,100); std::vector<int>::iterator it; it = myvector.begin(); it = myvector.insert ( it , 200 ); //某位置插入一个数字  for (auto p = myvector.begin(); p != myvector.end(); p++) { std::cout << (*p) << ", "; } std::cout << std::endl; myvector.insert (it,2,300);  //某位置插入若干数字  for (auto p = myvector.begin(); p != myvector.end(); p++) { std::cout << (*p) << ", "; } std::cout << std::endl; // "it" no longer valid, get a new one:
  it = myvector.begin(); std::vector<int> anothervector (2,400); myvector.insert (it+2, anothervector.begin(), anothervector.end());  //某位置插入一段动态同类的数字  for (auto p = myvector.begin(); p != myvector.end(); p++) { std::cout << (*p) << ", "; } std::cout << std::endl; int myarray [] = { 501,502,503 }; myvector.insert (myvector.begin(), myarray, myarray+3);  //某位置插入一段静态同类的数字 std::cout << "myvector contains:"; for (it=myvector.begin(); it<myvector.end(); it++) std::cout << ' ' << *it; std::cout << '\n'; return 0; } //******************************************************************************

void func_vector(void) { // vector<int> vec= new vector();
    vector<int> vec= {1, 2, 3, 4, 5}; cout << vec.at(0) << endl; cout << "size = " << vec.size() << endl; cout << "capacity = " << vec.capacity() << endl; cout << "resize(10)\n"; vec.resize(10); /* Jeff --> I don't like unsigned here. */
// for (unsigned int i = 0; i < vec.size(); i++) // { // cout << vec.at(i) << "\n"; // }

    for (auto p = vec.begin(); p != vec.end(); p++) { // Jeff --> endl == \n + flush
        cout << (*p) << ' '; } cout << endl; cout << "size = " << vec.size() << endl; cout << "capacity = " << vec.capacity() << endl; cout << "vec.clear()" << endl; vec.clear(); cout << "size = " << vec.size() << endl; cout << "capacity = " << vec.capacity() << endl; //-----------------------------------------------------------------------------
    for (int i = 1; i <= 10; i++) { vec.push_back(i); } 
// Jeff --> vector<int>::iterator iter = vec.begin();
// 可以使用通用的iterator方式,毕竟list不能直接l.begin()+1这么用!
cout << "erase(0-2)" << endl; vec.erase(vec.begin(), vec.begin() + 3); for (auto p = vec.begin(); p != vec.end(); p++) { // Jeff --> endl == \n + flush cout << (*p) << ' '; } cout << endl; cout << "size = " << vec.size() << endl; cout << "capacity = " << vec.capacity() << endl; //----------------------------------------------------------------------------- func_vector_insert(); //----------------------------------------------------------------------------- cout << "vec.front() = " << vec.front() << endl; cout << "push_back(111)" << endl; vec.push_back(111); for (auto p = vec.begin(); p != vec.end(); p++) { // Jeff --> endl == \n + flush cout << (*p) << ' '; } cout << endl; cout << "size = " << vec.size() << endl; cout << "capacity = " << vec.capacity() << endl; }

 

二维 vector

void func_vector2(void) { vector<vector<int>> vector2; vector<int> v1 = {1, 2, 3, 4, 5}; vector<int> v2 = {1, 2, 3, 4, 5}; vector2.push_back(v1); vector2.push_back(v2); for (auto it_v = vector2.begin(); it_v != vector2.end(); it_v++) { for (auto it_sub_v = (*it_v).begin(); it_sub_v != (*it_v).end(); it_sub_v++) { cout << (*it_sub_v) << ' '; } cout << endl; } }

  

vector.at() 更安全 

void func_catch(void) { vector<string> words = { "Hello", "World" }; for (unsigned int i = 0; i < words.size(); ++i) { cout << words[i] << endl; } try { cout << words.at(2) << endl; } catch(const std::out_of_range &e) { cout << e.what() << endl; } }

 

assign():相似 Copy

区别在于处理类时,若是有malloc就有有不一样,会涉及到引用计数的问题。详见:assign、retain和copy的区别

// vector assign
// 与 insert比较类似
#include <iostream> #include <vector> int main () { std::vector<int> first; std::vector<int> second; std::vector<int> third; first.assign (7, 100); // 分配 七个100
for (auto p = first.begin(); p != first.end(); p++) { std::cout << (*p) << std::endl; } std::cout << "============================" << std::endl; std::vector<int>::iterator it; it=first.begin()+1; second.assign (it, first.end()-1); // first上的一段数据 (动态数组)
for (auto p = second.begin(); p != second.end(); p++) { std::cout << (*p) << std::endl; } int myints[] = {1776, 7, 4}; third.assign (myints, myints+3); // myints上的一段数据 (静态数组) std::cout << "Size of first: " << int (first.size()) << '\n'; std::cout << "Size of second: " << int (second.size()) << '\n'; std::cout << "Size of third: " << int (third.size()) << '\n'; return0; }


void func_assign() { vector<int> v1(10); // vector<float> v2 = v1; vector<float> v2; v2.assign(v1.begin(), v1.end()); // 可能的优点:v1转化为了v2类型 }

 

 

List

advance 弥补 ++ 功能

在链表上的指针位移操做。

void func_list(void) { list<int> l  = {1, 2, 3, 4, 5}; list<int> l2(5, 8); list<int>::iterator iter  = l.begin(); list<int>::iterator iter2 = l.begin();

// Jeff --> 不知能直接++, 就设计了这个函数 advance (iter2,
2); l.erase(iter, iter2); for(auto p = l.begin(); p != l.end(); p++) { cout << (*p) << ' '; } cout << endl; //Jeff --> notice: here will be a 野指针! // l2.insert(l2.begin(), iter, iter2); l2.insert(l2.begin(), l.begin(), l.end()); for(auto p = l2.begin(); p != l2.end(); p++) { cout << (*p) << ' '; } cout << endl; }

 

splice() 弥补 insert() 功能

// splicing lists #include <iostream>
#include <list> int main ()
{
  std::list<int> mylist1, mylist2;
  std::list<int>::iterator it;

  // set some initial values:
for (int i=1; i<=4; ++i) mylist1.push_back(i); // mylist1: 1 2 3 4

for
(int i=1; i<=3; ++i) mylist2.push_back(i*10); // mylist2: 10 20 30
it
= mylist1.begin(); ++it; // points to 2 mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4 // mylist2 (empty) // "it" still points to 2 (the 5th element) mylist2.splice (mylist2.begin(),mylist1, it); // mylist1: 1 10 20 30 3 4 // mylist2: 2 // "it" is now invalid. it = mylist1.begin(); std::advance(it,3); // "it" points now to 30 mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end()); // mylist1: 30 3 4 1 10 20 std::cout << "mylist1 contains:"; for (it=mylist1.begin(); it!=mylist1.end(); ++it) std::cout << '' << *it; std::cout << '\n'; std::cout << "mylist2 contains:"; for (it=mylist2.begin(); it!=mylist2.end(); ++it) std::cout << '' << *it; std::cout << '\n'; return0; }


void func_splice(void) { list<string> words = {"hello", "world"}; list<string> words2 = {"lovely"}; words.splice(++words.begin(), words2); for (auto p = words.begin(); p != words.end(); p++) { cout << *p << endl; } cout << "=============================" << endl;
//-------------------------------------------------
// 单向链表
forward_list<int> myfl1 = {1, 2, 3}; forward_list<int> myfl2 = {4, 5, 6}; // Jeff --> iterator's next position. myfl1.splice_after(myfl1.begin(), myfl2); for (auto p = myfl1.begin(); p != myfl1.end(); p++) { cout << *p << endl; } }

 

  

Adaptor Class

认识一下

在顺序容器的基础上再包装一层,造成常见的数据结构。

容器适配器, more details: http://blog.csdn.net/thefutureisour/article/details/7751846

 

咱们已有的容器(好比vectorlistdeque)支持的操做不少,好比插入,删除,迭代器访问等等。而咱们但愿这个容器表现出来的是栈的样子:先进后出,入栈出栈等等,此时,咱们没有必要从新动手写一个新的数据结构,而是把原来的容器从新封装一下,改变它的接口,就能把它当作栈使用了。
C++中定义了三种容器适配器,它们让容器提供的接口变成了咱们经常使用的的3种数据结构:栈(先进后出),  队列(先进先出),  优先级队列


至于具体是怎么变的,咱们能够先了解一个大概:

      • 默认状况下,栈和队列都是基于deque实现的,
      • 而优先级队列则是基于vector实现的。

 

固然,咱们也能够指定本身的实现方式。可是因为数据结构的关系,咱们也不能胡乱指定:

      • 栈的特色是后进先出,因此它关联的基本容器能够是任意一种顺序容器,由于这些容器类型结构均可以提供栈的操做有求,它们都提供了push_back、pop_back和back操做。
      • 队列queue的特色是先进先出,适配器要求其关联的基础容器必须提供pop_front操做,所以其不能创建在vector容器上(内存的是固定的);
      • 对于优先级队列,因为它要求支持随机访问的功能,因此能够创建在vector或者deque上,不能创建在list上。

 

 

    


Stack

void func_stack(void)
{
    std::stack<int> foo, bar; foo.push (10); foo.push(20); foo.push(30); bar.push (111); bar.push(222); 
// 交换了两个container的内容 foo.swap(bar); std::cout << foo.top() << std::endl; foo.pop(); std::cout << foo.top() << std::endl; foo.pop(); std::cout << "size of foo: " << foo.size() << '\n'; std::cout << "size of bar: " << bar.size() << '\n'; }

 

队列 Queue

void func_queue(void) { queue<int> que; for (int i = 1; i <= 5; i++) { que.push(i); } cout << que.size() << endl; while(!que.empty()) {
// print & pop是两码事! cout << que.front() << ' '; que.pop(); } cout << endl; }

 

优先级队列 Max/Min-heap - priority_queue

void func_priority_queue(void) { priority_queue<int, vector<int>, greater_equal<int>> mypq; mypq.push(rand()); mypq.push(rand()); mypq.push(rand()); mypq.push(rand()); mypq.push(rand()); while(!mypq.empty()) { cout << mypq.top() << endl; mypq.pop(); } //--------------------------------------------------------------------------
 typedef struct { int a; int b; }Node; Node *myNode = new Node[10]; struct cmp { bool operator()(const Node &t1, const Node &t2) { // Jeff --> less return t1.b < t2.b; } }; for (int i = 0; i < 10; i++) { myNode[i].a = i; myNode[i].b = i+10; } priority_queue< Node, vector<Node>, cmp > Q(myNode, myNode+10); while(!Q.empty()) { cout << Q.top().b << endl; Q.pop(); } }

 

经常使用操做选项

1.empty()  堆栈为空则返回真 
2.pop()  移除栈顶元素 
3.push()  在栈顶增长元素 
4.size()  返回栈中元素数目 
5.top()  返回栈顶元素 
栈操做
1.back()  返回一个引用,指向最后一个元素 
2.empty()  若是队列空则返回真 
3.front()  返回第一个元素 
4.pop()  删除第一个元素 
5.push()  在末尾加入一个元素 
6.size()  返回队列中元素的个数 
队列操做
1.empty()  若是优先队列为空,则返回真 
2.pop()  删除第一个元素 
3.push()  加入一个元素 
4.size()  返回优先队列中拥有的元素的个数 
5.top()  返回优先队列中有最高优先级的元素
优先级队列操做
相关文章
相关标签/搜索