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

0 迭代器

  注意点:

  1. 迭代器的操作是有限的:均可自增、自减、==、!=、解引用、读取对象成员(.);
  2. 对于顺序容器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 顺序容器

  注意点:

  1. 指定元素个数的容器初始化只适用于顺序容器。如形式为C c(n,t)或C c(n)这两种形式的初始化。
  2. 直接将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同,如vector ivec2(ivec1);。
  3. 使用迭代器时,不要求容器类型相同,容器内的元素类型也可以不相同,只要相互兼容,能够将要复制的元素转换为所构建的形容器的元素类型,即可实现复制,如list slist(svec.begin(),svec.end());。
  4. 指针就是迭代器,允许通过使用内置数组中的一对指针初始化容器:
      char *color[] = {“black”,”red”,”yellow”,”blue”};
      size_t color_size = sizeof(color)/sizeof(char *);
      list color1(color,color + color_size);
  5. 除了引用类型,所有内置或复合类型都可以做元素类型。
  6. 除IO标准库类型之外,所有其他标准库类型都是有效的容器元素类型,容器本身也是。
  7. 容器的容器注意尖括号: vector< vector > lines;隔开,不然会导致编译时错误。
  8. list容器的迭代器既不支持算术运算(加法或减法),也不支持关系运算(<=,<,>=,>),只提供前置和后置的自增和自减运算以及相等和不等运算。
  9. 使用无效的迭代器会导致严重的运行时错误,如erase函数删除了元素,指向该元素的迭代器就无效了。
  10. 所有的顺序容器都支持push_back操作,在容器尾部插入一个元素的功能。而push_font只适用于list和deque容器类型。
  11. 不要存储end操作返回的迭代器,添加或删除deque或vector容器内的元素都会导致存储的迭代器失效。while(fisrt != v.end()){…}才好。
  12. 所有的容器都提供四种与容器大小相关的操作:size(),max_size(),empty(),resize(n),resize(n,t),包括关联容器。
  13. c.back()、c.front()分别返回容器c的最后一个元素的引用,如果c为空,则该操作未定义。相当于对begin()、end()-1进行解引用。
  14. 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 关联容器

  注意点:

  1. 关联容器不提供front、push_front、pop_front、back、push_back及pop_back操作。
  2. map是pair类型(对组类型)的集合,键+值
  3. 在使用迭代器遍历map容器时,迭代器指向的元素按键的升序排列。
  4. map的键值不能修改,为const修饰,只能修改值成员。
  5. 对map迭代器进行解引用将产生pair类型的对象,即可以使用first或second获取内容。
  6. 使用下标访问map与使用下标访问数组或vector的行为截然不同:用下标访问不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标。使用insert代替下标运算,可以避免这个不必要的初始化。使用insert插入元素时,如果键已经存在容器中,则insert不做任何操作,即不做值替换。
  7. set不支持下标操作符,键值唯一,不能修改。
  8. multimap中,同一个键可以关联多个值,且同一个键所关联的元素必然相邻存放。因此只要找到首端迭代器,就可以遍历同一键所关联的所有的值。
  9. 使用关联容器需包含对应的头文件,如#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值