您的位置:首页 > 编程语言 > C语言/C++

重学C++Primer笔记10---容器常用用法总结与归纳

2015-10-14 12:40 375 查看

0 迭代器

  注意点:

迭代器的操作是有限的:均可自增、自减、==、!=、解引用、读取对象成员(.);

对于顺序容器vector支持迭代器加减一个整数,其他的常用容器不支持;

  测试程序:

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <map>
#include <set>

using namespace std;

int main(int argc,char *argv[])
{
vector<string> svec;
list<string> slist;
deque<string> sdeque;
map<string, int> smap;
set<string> sset;

//vector在内存是连续存储的,类似数组,可以通过加上一个整数来移动下标
vector<string>::iterator svec_it = svec.begin() + svec.size()/2;
//list<string>::iterator slist_it = svec.begin() + svec.size()/2;       //error:list不支持加减一个整数
//deque<string>::iterator sdeque_it = svec.begin() + svec.size()/2;     //error:deque不支持加减一个整数
//map<string, int>::iterator smap_it = svec.begin() + svec.size()/2;    //error:map不支持加减一个整数
//set<string>::iterator sset_it = svec.begin() + svec.size()/2;         //error:set不支持加减一个整数

return 0;
}


1 顺序容器

  注意点:

指定元素个数的容器初始化只适用于顺序容器。如形式为C c(n,t)或C c(n)这两种形式的初始化。

直接将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同,如vector ivec2(ivec1);。

使用迭代器时,不要求容器类型相同,容器内的元素类型也可以不相同,只要相互兼容,能够将要复制的元素转换为所构建的形容器的元素类型,即可实现复制,如list slist(svec.begin(),svec.end());。

指针就是迭代器,允许通过使用内置数组中的一对指针初始化容器:

  char *color[] = {“black”,”red”,”yellow”,”blue”};

  size_t color_size = sizeof(color)/sizeof(char *);

  list color1(color,color + color_size);

除了引用类型,所有内置或复合类型都可以做元素类型。

除IO标准库类型之外,所有其他标准库类型都是有效的容器元素类型,容器本身也是。

容器的容器注意尖括号: vector< vector > lines;隔开,不然会导致编译时错误。

list容器的迭代器既不支持算术运算(加法或减法),也不支持关系运算(<=,<,>=,>),只提供前置和后置的自增和自减运算以及相等和不等运算。

使用无效的迭代器会导致严重的运行时错误,如erase函数删除了元素,指向该元素的迭代器就无效了。

所有的顺序容器都支持push_back操作,在容器尾部插入一个元素的功能。而push_font只适用于list和deque容器类型。

不要存储end操作返回的迭代器,添加或删除deque或vector容器内的元素都会导致存储的迭代器失效。while(fisrt != v.end()){…}才好。

所有的容器都提供四种与容器大小相关的操作:size(),max_size(),empty(),resize(n),resize(n,t),包括关联容器。

c.back()、c.front()分别返回容器c的最后一个元素的引用,如果c为空,则该操作未定义。相当于对begin()、end()-1进行解引用。

pop_front()pop_back()函数用于删除容器内的第一个和最后一个元素,当vector容器不支持pop_front操作,删除指定元素返回void。当然还有c.erase(p),c.erase(b,e)函数。

vector:

  最常用的容器类型,支持对元素的快速随机访问,可以高效的在容器尾部添加和删除元素,但是在其他任何位置上的插入或删除运算则需要付出昂贵的代价。

list:

  只支持元素的顺序访问,但是在list内部任何位置的插入和删除都非常迅速。

deque:

  支持在首尾部快速的删除和插入元素

string:

  字符串类型,一般的,可视为字符容器,支持大多数容器操作,与vector有大多数相同操作,但不支持栈方式操纵容器,即不能在string类型中使用font、back和pop_back操作。

  s.substr(pos,n),返回一个下标从pos开始的n个字符的string。

  s.substr(pos),返回一个下标从pos开始到s末尾的所有字符的string。

  s.replace(pos,len,args),删除s中从下标pos开始的len个字符,用args指定的字符替换,返回s的引用。

  s.replace(b,e,args),删除迭代器b和e标记范围内的所有字符,用args代替,返回s的引用。

  s.find(args),在s中查找args第一次出现的pos,没有则返回string::npos

  s.rfind(args),在s中查找args最后一次出现的pos

  s.find_first_of(args)

  s.find_first_of(string),查找任意字符,s中是否有string中的字符。

  s.find_first_of(string,pos);

  s.find_last_of(args)

  s.find_first_not_of(args)

  s.find_last_not_of(args)

2 关联容器

  注意点:

关联容器不提供front、push_front、pop_front、back、push_back及pop_back操作。

map是pair类型(对组类型)的集合,键+值

在使用迭代器遍历map容器时,迭代器指向的元素按键的升序排列。

map的键值不能修改,为const修饰,只能修改值成员。

对map迭代器进行解引用将产生pair类型的对象,即可以使用first或second获取内容。

使用下标访问map与使用下标访问数组或vector的行为截然不同:用下标访问不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标。使用insert代替下标运算,可以避免这个不必要的初始化。使用insert插入元素时,如果键已经存在容器中,则insert不做任何操作,即不做值替换。

set不支持下标操作符,键值唯一,不能修改。

multimap中,同一个键可以关联多个值,且同一个键所关联的元素必然相邻存放。因此只要找到首端迭代器,就可以遍历同一键所关联的所有的值。

使用关联容器需包含对应的头文件,如
#include<map>
#include<set>


map

  m.count(k),返回m中k出现的次数,适用于multimap和map,很明显,在map中,如果k存在,则返回值肯定为1。

  m.find(k),在m中按k索引,存在,则返回指向该元素的迭代器。不存在,则返回超出末端迭代器。

  m.erase(k),

  m.erase(p),

  m.erase(b,e),

  m.insert(e),e是一个用在m上的value_type类型的值。

  m.insert(b,e)

  m.insert(iter,e)

set

  insert

  count

  find

  erase

multimap

  

multiset

3 应用:文本查询

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <cstdlib>
#include <stdexcept>
#include <sstream>

using namespace std;

class TextQuery{

public:
typedef vector<string>::size_type line_no;

void read_file(ifstream &is);

set<line_no> run_query(const string&) const;
string text_line(line_no) const;

private:
ifstream& open_file(ifstream &,const string &);
void store_file(ifstream&);
void build_map();
vector<string> lines_of_text;
map< string, set<line_no> > word_map;
};

void TextQuery::read_file(ifstream &is)
{
store_file(is);
build_map();
}

string TextQuery::text_line(line_no line) const
{
if(line < lines_of_text.size())
return lines_of_text[line];
//out_of_range,c++异常类,
throw out_of_range("line number out of range");
}

set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const
{
map<string, set<line_no> >::const_iterator loc = word_map.find(query_word);
if(loc == word_map.end())
//返回空set对象
return set<line_no>();
else
return loc->second;
}

ifstream& TextQuery::open_file(ifstream &in,const string &file)
{
in.close();
in.clear();
in.open(file.c_str());
return in;
}

//-----------------------------------------------------------
//将文件中的每一行字符串作为一个元素依次存放到vector中
//-----------------------------------------------------------
void TextQuery::store_file(ifstream&is)
{
string textline;
while(getline(is,textline))
lines_of_text.push_back(textline);
}
//-----------------------------------------------------------
//将存放每一行字符串的vector的元素依次取出,将其分解为单词,并将单词的行数保存到map< string, set<line_no> >中
//-----------------------------------------------------------
void TextQuery::build_map()
{
for(line_no line_num = 0; line_num != lines_of_text.size(); ++line_num){
//绑定行字符串到istringstream
istringstream line(lines_of_text[line_num]);
string word;
//循环从行字符串读取单词到string类型word
while(line >> word){
//将行号插入到键值为word,值为vector类型的map中
word_map[word].insert(line_num);
}
}
}

string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr == 1) ? word : word + ending;
}

void print_results(const set<TextQuery::line_no>& locs,
const string& sought,const TextQuery &file)
{
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size();

cout << "\n" << sought << " occurs "
<< size << " "
<< make_plural(size,"time","s") << endl;
line_nums::const_iterator it = locs.begin();
for(; it != locs.end(); ++it){
cout << "\t(line "
<< (*it) + 1
<< ") "
<< file.text_line(*it) <<endl;
}
}

int main(int argc,char *argv[])
{
ifstream infile;

if(argc < 2 || !open_file(infile,argv[1])){
cerr << "No input file!" << endl;
return EXIT_FAILURE;
}

TextQuery tq;
tq.read_file(infile);

while(true){
cout << "Enter word to look for,or q to quit: ";
string s;
cin >> s;

if(!cin || s == "q")break;

set<TextQuery::line_no> locs = tq.run_query(s);

print_results(locs,s,tq);
}

return EXIT_SUCCESS;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息