C++ primer 笔记(二)

C++ primer 笔记(二)

第9章   sequential container

顺序容器: vector 快速随机访问    list快速插入删除   deque双端,随机访问

C<T> c;

C c(c2);

C c(b,e);  //迭代器,数组,指针,不要求两个容器类型相同

C<T> c(n,t); //只适用与顺序容器

C<T> c(n); //只适用与顺序容器

char *words[]={"a","b","c"};

list<string>::size_type list_size=sizeof(words)/sizeof(char*);

list<string> slist(words, words+list_size);

 

容器元素类型必须满足:1) 支持赋值运算(引用不支持)  2)可复制

除IO标准库类型及auto_ptr类型外,其他所有标准库类型都是有效的容器类型。容器本身也满足。

vector<Foo> empty;//ok

vector<Foo> bad(10);// error, Foo无默认构造函数但有int参数的构造函数

vecotr<Foo> ok(10,1);//ok

 

容器的容器 vector<vector<string> > lines;   //   >>之间必须有空格

 

iter->mem等价于 (*iter).mem;

 

list容器不支持算术运算(iter+n,iter-n,iter+=n,iter-=n), 也不支持关系运算(<=,<,>=,>),

只提供前置后后置自增自减,以及相等不等运算。vector和deque都支持。

list<int> ilist(vec.begin(), vec.end());

ilist.begin()+ilist.size()/2; // error:no addition on list iterators

 

容器定义的类型别名:

size_type  

difference_type//迭代器差值的有符号类型

iterator                 const_iterator  

reverse_iterator  const_reverse_iterator

value_type

reference  //元素的左值类型,value_type&同义词

const_reference  //const value_type&同义词

 

c.begin(); c.end();

c.rbegin(); //返回reverse_iterator,指向c的最后一个元素

c.rend();//返回reverse_iterator,指向第一个元素前面的位置

容器c为const则返回const_reverse_iterator

 

c.push_back(t);

c.push_front(t); //只适用于list和deque

c.insert(p,t);//迭代器p前面插入t,返回新元素的迭代器

c.insert(p,n,t);//返回void

c.insert(p,b,e);//返回void

 

容器的关系运算:容器类型和元素类型都完全相同。

容器大小操作:

c.size(); //返回c::size_type

c.max_size();

c.empty();

c.resize(n);//n<c.size()删除多余,n>c.size(),值初始化新元素

c.resize(n,t);//新元素值为t

 

c.front();c.back();//返回引用,若c为空则未定义

c[n];c.at(n);// vector,deque

 

c.erase(p);//返回迭代器,指向被删元素后面的元素,若p指向超出末端的下一位置,则未定义。

c.erase(b,e);//返回迭代器,若e指向超出末端的下一位置,则也返回超出末端的下一位置。

c.clear();//void

c.pop_back();//void,若c为空,则未定义

c.pop_front();//void,若c为空,则未定义,只适用于list或deque

 

c1=c2;//c1和c2类型要完全相同,类型不同则使用assign

c1.swap(c2);//c1和c2类型要完全相同,速度比赋值快,不会使迭代器失效

c.assign(b,e);//b和e必须不指向c中元素,执行后迭代器失效

c.assign(n,t);

 

v.capacity();//vector在必须分配新的存储空间前可以存储的元素总数。

v.reverse(n);//预留存储空间大小,改变capacity的值

 

容器的选择:

1.随机访问:vector,deque

2.在中间位置插入 list

3.只在头部或尾部插入,deque

4.只在读取输入时在容器中间插入元素,然后随机访问,则先list,后复制到vector

5.如果既要随机访问,又要在中间位置插入删除元素,则考虑两者的使用的频率

 

string支持大部分vector操作,除了栈操作:不能使用front,back,pop_back,pop_front

string s1;

string s2(5,’a’);

string s3(s2);

string s4(s3.begin(), s3.end());

string s5(cp);//cp指向以null结尾的C风格字符串

string s6(cp, n);

string s7(s2, pos2);//从pos2开始

string s8(s2, pos2, len2);//从pos2开始的len2个字符,无论len2值多少,最多只能复制s2.size()-pos2个字符

 

与容器共有的string操作:

s.insert(p, t);

s.insert(p, n, t);

s.insert(p, b, e);

s.assign(b, e);

s.assign(n, t);

s.erase(p);

s.erase(b, e);

 

string特有的版本:

s.insert(pos, n, c);

s.insert(pos, s2);

s.insert(pos, s2, pos2, len);

s.insert(pos, cp, len);

s.insert(pos, cp);

s.assign(s2);

s.assign(s2, pos2, len);

s.assign(cp, len);

s.assign(cp);

s.erase(pos, len);

 

string特有操作

s.substr(pos, n);

s.substr(pos);

s.substr();

 

s.append(args);//追加,返回引用

s.replace(pos, len, args);//删除,用args替换,返回引用

s.replace(b, e, args);

append和replace的参数args

s2

s2, pos2, len2

cp                             // cp指向以null结束的数组

cp, len2                  // cp指向以null结束的数组

n, c

b2, e2

 

find操作都返回string::size_type,没找到则返回string::npos

s.find(args);

s.rfind(args);

s.find_first_of(args);

s.find_last_of(args);

s.find_first_not_of(args);

s.find_last_not_of(args);

find操作的参数args

c, pos                         //从下标pos开始查找字符c,pos默认值为0

s2, pos                       //从下标pos开始查找string对象上,pos默认值为0

cp, pos                      //cp指向null结尾的C风格字符串,pos默认值为0

cp, pos, n                 //pos和n无默认值,从pos开始查找cp指向的前n个字符

 

string::size_type pos=0;

while ((pos = name.find_first_of(numerics, pos)) != string::npos)

{

//…

++pos;}

 

s.compare(s2);

s.compare(pos1, n1, s2);

s.compare(pos1, n1 ,s2, pos2, n2);

s.compare(cp);  //cp指向以null结尾的字符串

s.compare(pos1, n1, cp);

s.compare(pos1, n1, cp, n2);

 

顺序容器适配器:stack  queue   priority_queue有优先级管理的队列

适配器通用操作和类型:

size_type

value_type

container_type

A a;

A a(c);

关系操作符: == != <  <=  >  >=

支持关系运算

 

覆盖基础容器类型:stack,queue都基于deque,priority_queue基于vector

创建适配器时,通过指定适配器的第二个类型实参覆盖基础容器类型

stack可任意,queue的基础容器要有push_front运算,因此不能建立在vector上

priority_queue需要随机访问,因此可建立在vector和deque上

 

stack适配器操作

s.empty();

s.size();

s.pop();

s.top();

s.push(item);

 

队列queue和优先级队列priority_queue支持的操作:

q.empty();

q.size();

q.pop();

q.front();           //只适用于queue

q.back();           //只适用于queue

q.top();             //返回最高优先级的元素值,只适用于priority_queue

q.push(item);  //对于queue在队尾压入,对于priority_queue放在优先级比它低的元素前面

 

 

 

第10章 associative container 关联容器

map         set

multimap//支持同一个键多次出现的map类型

multiset//支持同一个键多次出现的set类型

 

#inlcude<ultility> pair类型

pair<T1, T2> p1;  //值初始化

pair<T1, T2> p1(v1,v2);

make_pair(v1,v2);

p1 < p2

p1 == p2

p.firist

p.second

 

关联容器支持的操作:

1.关联容器共享大部分顺序容器操作,但不支持front,back,push_front,pop_front,push_back,pop_back.

2. C<T> c;

    C<T> c1(c2);

    C<T> c(b,e);

3. 关系运算

4.begin,end,rbegin,rend;

5.容器类型别名: map的value_type是pair类型

6.swap和赋值操作,但不支持assign

7.clear和erase,但关联容器的erase返回void

8.size,max_size,empty,但不支持resize

 

map<k, v> m;

map<k, v> m(m2);

map<k, v> m(b, e); //元素的类型必须能转换为pair<const k, v>

键类型k必须定义<操作符,严格弱排序 strict weak ordering

 

map<k, v>::key_type                       //键类型

map<k, v>::mapped_type              //关联的值类型

map<k, v>::value_type                   //pair<const k,v>类型,即first元素为const map<k,v>::key_type,second元素为map<k,v>::mapped_type.

                                                   //值可改,键不可改,对迭代器解引用获得指向value_type的引用

用下标访问不存在的元素将导致在map容器中添加新元素,它的键即为下标值,并对值类型值初始化。

 

m.insert(e); //若e.first不在m中则插入,反之m不变。返回pair类型对象,包含指向e.first元素的map迭代器,及bool对象表示是否插入了该元素.

m.insert(beg, end);//返回void

m.insert(iter, e); //以iter为起点搜索,查找是否有e.first对应的键元素,如果没有,则插入e。返回一个迭代器,指向具有e.first键的元素

 

使用insert可避免使用下标操作符带来的副作用:不必要的初始化。

word_count["Anna"]=1;    //查找Anna,若没有则创建,值初始化,插入map对象中, 最后读取并将值赋为1

pair<map<string, int>::iterator, bool> ret = word_count.insert(map<string, int>::value_type("Anna",1);

word_cound.insert(make_pair("Anna",1);

 

查找或读取map中元素,下标会自动插入新元素,考虑使用

m.count(k);   //返回k出现的次数,map中只能为0或1

m.find(k);      //返回指向k的迭代器,若k不存在则返回超出末端的迭代器

 

if (word_count.count("foobar"))  occurs = word_count["foobar"];    //对元素两次查找

map<string, int>::iterator it = word_count.find("foobar");

if (it != word_count.end()) occurs = it->second;                                   //一次查找

 

m.erase(k);  //返回size_type类型的值,表示删除的元素个数

m.erase(p);//p不能等于m.end(),  返回void

m.erase(b, e);//返回void

 

 

set容器支持的操作基本与map容器一致,构造函数,insert count find erase

除了不支持下标操作符,没有定义mapped_type类型,value_type不是pair类型而等价于key_type。

与map一样,带有一个键参数的insert返回pair类型,包含一个指向该键元素的迭代器和是否插入元素的bool。

set的键元素与map一样,不能修改。

 

mutimap multiset 头文件也是 map和set

带有一个键参数的erase删除拥有该键的所有元素并返回删除的个数。

查找元素:

1)typedef mutimap<string, string>::size_type sz_type;

   sz_type entries = authors.count(k);

mutimap<string, string>::iterator iter = authors.find(k);

for (sz_type cnt = 0; cnt != entries; ++cnt, ++iter)

               cout <<iter->second << endl;

2)map,set,mutimap,multiset都使用

   m.lower_bound(k);   //返回指向键不小于k的第一个元素的迭代器

   m.upper_bound(k); //返回指向键大于k的第一个元素的迭代器

   m.equal_range(k);  //返回pair对象,包含两个迭代器,first等价于m.lower_bound(k), second等价于m.upper_bound(k).

   typedef multimap<string, string>::iterator author_it;

   author_it beg = authors.lower_bound(k), end=authors.upper_bound(k);

   while (beg != end){cout<<beg->second<<endl; ++beg;}

   

   pair<author_it, author_it> pos = authors.equal_range(k);

    while(p->first != pos->second){cout<<pos.first->second<<endl; ++pos.first;}

 

第11章 泛型算法  generic algorithm

#include<algorithm>

#include<numeric>

accumulate(v.begin(), v.end(),a);   //累加初值a与容器元素类型匹配

fill(v.begin(), v.end(), t);  //将t的副本分别写入,要保证输入范围有效

fill_n(v.begin(), n, t);  //写入n个t的副本,要保证输入范围有效,n个元素必须已经存在

back_inserter迭代器适配器,back_inserter(container);生成一个绑定在容器上的插入迭代器,

试图通过这个迭代器给元素赋值时,赋值运算将调用push_back来添加元素。

vector<int> ivec; //empty

fill_n (back_inserter(ivec),10,0);  //ok

copy (ilst.begin(), ilst.end(), back_inserter(ivec));  //效率差,一般直接vector<int> ivec(ilst.begin(), ilst.end());

replace(ilst.begin(), ilst.end(), a, b);//将所有等于a的元素替换为b

如果不想改变原序列则用replace_copy

vector<int> ivec;

replace_copy(ilst.begin(), ilst.end(), back_inserter(ivec), a, b);

 

sort(words.begin(), words.end());       //使用<操作符比较,

vector<string>::iterator end_unique =

                             unique(words.begin(),words.end());  //"删除"相邻的重复元素,把重复的元素移动到序列末尾,返回的迭代器指向超出无重复的元素范围末端的下一位置

words.erase(end_unique,words.end());

stable_sort(words.begin(), words.end(), isShorter);  //稳定排序,重复元素相对位置不变,第3个参数使用谓词predicate

// bool isShorter(const string &s1, const string &s2){return s1.size() < s2.size();}

//bool GT6(const string &s){return s.size()>=6;}

vector<string>::size_type wc= count_if (words.begin(), words.end(), GT6); //返回谓词函数返回条件成立的元素个数

 

插入迭代器

1)back_inserter : push_back实现插入的迭代器

2)front_inserter: push_front实现插入,vector不能用

3)inserter: insert实习插入,第二个实参指向插入起始位置的迭代器

  list<int> ilst,ilst2,ilst3;

for (list<int>::size_type i=0; i!=4; ++i) ilst.push_back(i);

copy (ilst.begin(), ilst.end(), front_inserter(ilst2);   // 0123

copy(ilst.begin(),ilst.end(), inserter(ilst3, ilst3.begin()); //3210

 

iostream 迭代器: 自增,解引用,赋值。 istream提供==,!=运算,ostream不提供比较运算

都是类模板,任何定义<<操作符的类型都可以定义istream_iterator,定义>>的类型都可以定义ostream_iterator

istream_iterator<T> in(strm);  // 创建从输入流strm中读取T类型对象的istream_iterator对象

istream_iterator<T> in;            //istream_iterator对象的超出末端迭代器

ostream_iterator<T> in(strm);  //创建将T类型的对象写到输出流strm的ostream_iterator对象, ostream_iterator不提供超出末端迭代器

ostream_iterator<T> in(strm, delim);//创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分隔符,delim是以空字符结束的字符数组

 

istream_iterator<int> in_iter(cin);

istream_iterator<int> eof;

while(in_iter != eof) vec.push_back(*in_iter++);  //vector<int> vec(in_iter, eof);读cin,直到文件结束或输入的不是int为止

 

ostream_iterator<string> out_iter(cout,"\n");

istream_iterator<string> in_iter(cin), eof;

while(in_iter !=eof) *out_iter++ = *in_iter++;

 

一旦给ostream_iterator对象赋值,写入就提交了,没法改变这个值

ostream_iterator没有->操作符

 

从标准输入读取一些数,将不重复的数写到标准输出

istream_iterator<int> cin_it(cin),eof;

vector<int> ivec(cin_it, eof);

sort(ivec.begin(), ivec.end());

ostream_iterator<int> out_it(cout," ");

unique_copy(ivec.begin(), ivec.end(), out_it);

 

反向迭代器:需要使用自减操作符,流迭代器没有。

sort(vec.rbegin(), vec.rend());  //实现降序

find(vec.rbegin(),vec.rend(),',');//反向开始搜索

 

const迭代器

使用时注意迭代器范围

find_first_of(it, roster1.end(), roster2.begin(), roster2.end());

//如果it为const_iterator, 而roster为非const容器end()返回非const迭代器,用来指定迭代器范围的两个迭代器类型不同,将无法编译

 

迭代器种类:低级别迭代器可使用任意更高级迭代器替代

1.输入迭代器   == != ++ * –>           find accumulate   istream_iterator

2.输出迭代器  ++ *    只能写一次       copy  ostream_iterator

3.前向迭代器:读写指定同期,以一个方向遍历序列,支持输入输出迭代器的所有操作,还支持对同一元素的多次读写  replace

4.双向迭代器: --   reverse  标准库容器提供的迭代器至少达到双向迭代器的要求   list map set

5.随机访问迭代器:关系操作符< <= > >= iter+n, iter-n, iter1-iter2,iter[n]              sort  vector deque string      所以list不能用sort排序

 

算法的形参模式

alg (beg, end, other parms);

alg (beg, end, dest, other parms);

alg (beg, end, beg2, other parms); //假定以beg2开始的范围与beg end一样大

alg (beg, end, beg2, end2, other parms);

 

sort (beg, end);  //  <操作符

sort (beg, end, cmp);

find (beg, end, val);   //==操作符   带谓词形参加_if,因形参个数相同导致二义性

find_if (beg, end, pred);

reverse(beg, end);

reverse_copy(beg, end, dest);

 

list特有操作:对list容器应优先使用特有的成员版本,而不是泛型算法

lst.merge(lst2);

lst.merge(lst2, comp); //两个版本都要先排序, 合并后lst2为空,返回void

 

lst.remove(val);

lst.remove_if(unaryPred);//调用lst.erase实现,返回void

 

lst.reverse();

lst.sort();

lst.sort(comp);

 

lst.splice(iter, lst2);

lst.splice(iter, lst2, iter2);

lst.splice(iter, beg, end);//将lst2的元素移到lst中迭代器iter指向元素的前面,在lst2中删除移出的元素

 

lst.unique();

lst.unique(binaryPred);//调用erase删除同一个值的连续副本,第一个用==判断,第二个用指定谓词函数判断

 

list特有版本与其泛型算法两个重要区别:

1.remove和unique真正删除了指定元素

2.merge和splice会破坏实参

使用merge的泛型算法时将合并的序列写入目标迭代器指向的对象,两个输入序列不变。

你可能感兴趣的:(C++ primer 笔记(二))