C++复习 10 关联容器




声明,所有的朋友,如果要转我的帖子,务必注明"作者:黑啤来源:CSDN博客"和具体的网络地址http://blog.csdn.net/nx500/archive/2007/10/22/1838229.aspx,并且我的所有博客内容,禁止任何形式的商业用途,请大家尊重我的劳动.谢谢!

目 录

十.关联容器(map/set/multimap/multiset).
  001 pair类型.定义在utility头文件中.
        pair<T1, T2> p;
        pair<T1, T2> p(v1, v2);
        make_pair(v1, v2);
        p1 < p2
        p1 == p2
        p.first
        p.second
      创建pair和初始化.
        pair<string, int> word_count;
        pair<string, string> author("James", "Joyce");
        typedef pair<string, string> Author;
        Author proust("Marcel", "Proust");
      pair对象的操作.
        string firstBook;
        if(author.first == "James" && author.second == "Joyce")
          firstBook = "Stephen Hero";
      生成pair对象.
        string first, last;
        while(cin>>first>>last){
          author = make_pair(first, last);
        }
        // 也可以这样.
        while(cin>>author.first>>author.second){
          // ..
        }
        // 或者这样.
        while(cin>>first>>last){
          author = pair<string, string>(first, last);
        }
  002 关联容器.关联容器的元素根据键的次序排列,可以按照键的顺序访问容器元素,但元素的实际存放并不一定按照键的次序.
      关联容器支持大部分普通容器的操作.但不提供front,push_front,pop_front,back,push_back以及pop_back操作.
      支持的构造函数.
        C<T> c;
        C<T> c1(c2);
        C<T> c(b, e);
      关联容器不能通过容器大小来定义,因为这样就无法知道键所对应的值是什么.
      支持容器的关系运算.
        支持begin(), end(), rbegin(), rend()操作.
        支持typedef和value_type类型.
        支持swap和赋值操作,但不提供assign函数.
        支持clear和erase操作,但关联容器的erase返回void类型.
        不支持resize操作.
  003 map类型.是键-值对的集合,通常可理解为关俩数组.可使用键作为下标来获取一个值.
        #include <map>
        using std::map;
      键类型的约束:键类型必须有一个相关的比较函数,默认情况下为 < 操作符进行比较. 键类型必须是严格弱排序的.
      定义map对象
        map<k, v> m;
        map<k, v> m(m2);
        map<k, v> m(b, e);

        map<string, int> word_count;
      map定义的类型
        map<k, v>::key_type
        map<k, v>::mapped_type
        map<k, v>::value_type    定义一个pair类型,第一个元素是const map<k, v>::key_type类型.
      对map迭代器的解引用,将产生pair类型的对象.
        map<string, int>::iterator map_it = word_count.begin();
        cout << map_it->first;
        cout << map_it->second;
        // map_it->first = "new key";   // error, key类型是const的,不可以更改,只能采用删除和添加操作.
        ++map_it->second;
  004 在map对象中添加元素.
      使用下标,注意map于vector的区别,map下标操作返回的类型与迭代器解引用返回的类型不同.
        map<string, int> word_count;
        word_count["Anna"] = 1;
      使用下标访问不存在的元素,将导致在map容器中添加一个新的元素,他的键为该下标值.使用这个特性使程序更加简练.
        map <string, int> word_count;
        string word;
        while(cin > word){
          ++word_count[word];
        }
  005 在map中插入元素.
        m.insert(e);        如果键e.first不再m中,则将e插入m中,如果m已经存在,保持m不变.
                            返回一个pari类型对象,包含一个指向键值为e.first元素的map迭代器,和一个bool类型对象,表示插入是否成功.
        m.insert(begin,end) 返回void类型.
        m.insert(iter, e)   如果键e.first不在m中,以iter为起点创建新元素的插入位置.返回以一个迭代器,指向m中具有给定键值的元素.
      用insert代替下标添加元素.
        word_count.insert(map<string, int>::value_type("Anna", 1));
      简单一点的方法.
        word_count.insert(make_pair("Anna", 1));
      或者.
        typedef map<string, int>::value_type valType;
        word_count.insert(valType("Anna", 1));
      检查insert操作的反回值.
        map<string, int> word_count;
        string word;
        while(cin>>word){
          pair<map<string, int>::iterator, bool> ret = word_count.insert(make_pair(word,1));
          if(!ret.second){
            ++ret.first->second;
          }
        }
  006 查找并读取map中的元素.
        m.count(k)        返回map中k出现的次数
        m.find(k)         如果m容器中存在键值为k的元素,返回指向该元素的迭代器,不存在则"返回超出末端迭代起".
      可以使用count检查map对象中是否存在某个键值.
        int occurs = 0;
        if(word_count.count("foobar")){  // 第一次查找
          occurs = word_count["foobar"]; // 第二次查找
        }
      读取元素而不插入元素.
        int occurs = 0;
        map<string, int>::iterator it = word_count.find("foobar");
        if (it != word_count.end()){
          occurs = it->second;
        }
  007 从map对象中删除元素.
        m.erase(k)      删除键值为k的元素,返回删除元素的个数.
        m.erase(p)      从m中删除p所指向的元素,p必须是m中确实存在的元素,而且不能等于m.end(),返回void.
        m.erase(b, e)   返回void.

        string removal_word("foobar");
        if (word_count.erase(removal_word)){
          cout << "ok: " << removal_word << " removed" << endl;
        }else{
          cout << "opps: " << removal_word << " not found" << endl;
        }
  008 map对象的遍历.
        map<string, int>::const_iterator map_it = word_count.begin();
        while(map_it != word_count.end()){
          cout << map_it->first << " occurs " << map_it->second << " times" << endl;
          ++map_it;
        }
  009 单词转换程序.将单词转换文件的内容存储在一个map容器中,将被替换的单词作为键,而用作替换的单词则作为其相应的值.
         //  10009.cpp
        #include  < iostream >
        #include 
< string >
        #include 
< map >
        #include 
< utility >
        #include 
< fstream >
        #include 
< sstream >
        #include 
< stdexcept >

        
using  std::map;
        
using  std:: string ;
        
using  std::pair;
        
using  std::cout;
        
using  std::endl;
        
using  std::ifstream;
        
using  std::istringstream;
        
using  std::runtime_error;

        
//  in作为文件指针,file存放文件名称,代开输入文件
        ifstream &  open_file(ifstream &   in const   string   & file) {
          
// 清空文件指针的状态
          in.close();
          
in.clear();
          
// open函数输入参数为字符串字面值
          in.open(file.c_str());
          
return in;
        }


        
//  单词转换
         int  main( int  argc,  char   ** argv) {
        map
<stringstring> trans_map;  // 存放译码
        string key, value;              // 生成译码容器的辅助变量
          
// 判断输入参数是否符合规则
          if(argc != 3)
            cout 
<< argv[0<< "<trans map filename> <input filename>" << endl;
        
// 定义map_file指针并打开之,读入生成对应的翻译表
        ifstream map_file;
          
if(!open_file(map_file, argv[1]))
            
throw runtime_error("no transormation file");
          
while(map_file >> key >> value)
            trans_map.insert(make_pair(key, value));
          map_file.close();
        
// 定义input文件指针,并打开输入文件
        ifstream input;
          
if(!open_file(input, argv[2]))
            
throw runtime_error("no input file");

        
// 每次从文件中读入一行
        string line;
          
while(getline(input, line)){
          
// 一次处理一行内的一个单词
          istringstream stream(line);
          
string word;
          
bool firstword = true;
            
while(stream >> word){
              
// 查找译码,有译码输出译码,没有译码输出原文
              map<stringstring>::const_iterator map_it = trans_map.find(word);
              
if(map_it != trans_map.end())
                word 
= map_it->second;
              
// 第一个单词前不输出空格
              if(firstword)
                firstword 
= false;
              
else
                cout 
<< " ";
              cout 
<< word;
            }

            cout 
<< endl;
          }

          
return 0;
        }

        transmap.txt文件的内容
          'em    them
          cuz    because
          gratz  grateful
          i      I
          nah    no
          pos    supposed
          sez    said
          tanx   thanks
          wuz    was
        src.txt文件的内容
          nah i sez tanx cuz i wuz pos to
          not cuz i wuz gratz
        // 编译及运行结果
        heipi@Linux:~/Documents/CPP> g++ -o o 10009.cpp
        heipi@Linux:~/Documents/CPP> ./o transmap.txt src.txt
        no I said thanks because I was supposed to
        not because I was grateful
        heipi@Linux:~/Documents/CPP>
   010 set类型容器只是单纯的键的集合.set容器中存储的键也必须是唯一的,而且不能修改.
      set容器中,value_type不是pair类型,而是与key_type相同的类型.set没有定义mapped_type类型,也不支持下标操作.
      定义set
        set<int> iset;
      添加元素
        iset.insert(1);
        int ia[] = {0, 2, 3, 4, 5};
        iset.insert(ia, ia + 5);    // 同map的insert函数一样,返回一个pair类型,second元素为bool类型
      从set中获取元素(实质是判断元素是否在set中)
        iset.find(1);    // 返回指向元素1的const_iterator,也就是说不能直接修改元素的值,只能删除,添加
        iset.find(-1);   // 返回iset.end()
        iset.count(1);   // 返回1,表示set里有这个元素
        iset.count(-1);  // 返回0,表示set里没有这个元素
      单词排除集算法
        void restricted_wc(ifstream &remove_file, map<string, int> &word_count){
        set<string> excluded;
        string remove_word;
          // 从remove_file文读取排除的单词,创建排除集合
          while(remove_file >> remove_word){
            excluded.insert(remove_word);
          }
        string word;
          // 对于每个输入单词,统计不再排除集合中单词的个数
          while(cin >> word){
            if(!excluded.count(word))
              ++word_cound[word];
          }
        }
  011 multiset和multimap类型允许一个键对应多个实例.multiset和multimap支持大部分set和map的操作.multimap不支持下标操作.
      添加元素.
        multimap<string, string> authors;
        authors.insert(make_pir(string("Barth, John"), string("Sot-weed Factor")));
        authors.insert(make_pir(string("Barth, John"), string("Lost in the funhouse")));
      删除元素,返回删除元素的个数.
        multimap<string, string>::size_type cnt = authors.erase(string(Barth, John"));
      查找元素,有三种办法.首先要知道的是在multimap和multiset容器中,如果键对应多个实例,则这些实例在容器总将相邻存放.
      使用count可以计算出某键出现的次数,用find返回迭代器指向相邻存放元素的第一个位置.
      // 方案一
        typedef multimap<string, string>::size_type sz_authors;
        string search_item("Barth, John");
        // 统计含有该键值元素的个数
        sz_authors sz = authors.count(search_item);
        multimap<string, string>::iterator it = authors.find(search_item);
        // 输出所有元素
        for(sz_authors cnt = 0; cnt != sz; +=cnt)
          cout << iter->second << endl;
      两个专用的操作
        m.lower_bound(k)    // 返回迭代器,指向键值不小于K的第一个元素,如果该键不再m中,返回该键应该被插入的第一个位置
        m.upper_bound(k)    // 返回迭代器,指向键值大于K的第一个元素
        m.equal_range(k)    // 返回pair对象,first元素是m.lower_bound(k),second元素是m.upper_bound(k)
      // 方案二
        typdef multimap<string, string>::iterator authors_it;
        authors_it beg = authors.lower_bound(search_item);
        authors_it end = authors.upper_bound(search_item);
        // 如果返回的范围不是个空集,就说明有符合这个键值的元素
        while(beg != end){
          cout << beg->second << endl;
          ++beg;
        }
      // 方案三
        pair<authors_it, authors_it> pos = authors.equal_range(search_item);
        while(pos.first != pos.second){
          cout << pos.first->second << endl;
          ++pos.first;
        }
  012 容器的综合应用,文本查询程序.
      功能描述:程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词.查询的结果是该单词出现的次数,并列出每次出现所在的行.
             如果某单词在同一行中多次出现,程序将只显式改行一次.行好按升序显式.
      需求分解:
        1.允许用户指明要处理的文件名字.
        2.必须将没一行分解为各个单词,并记录每个单词所在的所有行,输出行号时,保证以升序输出.
        3.对特定单词的查询将返回该单词的所哟行的行号.
        4.输出某单词所在的行文本时,程序必须能根据给定的行号从文件中获取相应的行.
      定义数据结构.
        1.使用一个vector<string>类型的对象存储整个输入文件的副本.输入文件的每一行是该vector对象的一个元素.
        2.将每个单词所在的行号存在一个set容器中,这样可以确保每行只有一个条目,而且行号将自动按升序排列.
        3.使用一个map容器,将每个单词与一个set容器对象关联起来.
        综合起来,我们需要定义一个TextQuery类,它含有两个数据成员,存储输入文件的vector对象,以及一个map容器对象.
      操作接口.
        1.read_file成员函数,形参是一个ifstream&类型的对象.该函数每次从文件读入一行,保存在vector<string>中.
          读入完毕后,创建关联每个单词及其所在行号的map容器.这是一个内部接口,不对外开放.定义两个内部接口实现以上功能.
          store_file函数读入文件,将内容存入vector容器;build_map函数分解每一行,创建map容器.
        3.run_query成员函数,形参为一个string类型的对象,返回一个set对象,包含该string对象的多有行的行号.
        3.text_line成员函数,形参为一个行号,返回输入文本中该行号对应的文本行.
      程序代码.
        // TextQuery.h
#ifndef TEXTQUERY_H
#define  TEXTQUERY_H

#include 
< fstream >
#include 
< string >
#include 
< vector >
#include 
< map >
#include 
< set >

class  TextQuery {
  
public:
    
// 定义公共的变量类型
    typedef std::vector<std::string>::size_type line_no;
    
// 读入文件,将内容存入vector容器;创建map容器
    void read_file(std::ifstream& is){
      store_file(
is);
      build_map();
    }

    
// 返回一个set对象,包含该string对象的多有行的行号.
    std::set<line_no> run_query(const std::string &const;
    
// 返回输入文本中该行号对应的文本行.
    std::string text_line(line_no) const;
  
private:
    
// 按行存放文件
    std::vector<std::string> lines_of_text;
    
// 单词和单词所在行号的集合的容器
    std::map<std::string, std::set<line_no> >word_map;
    
void store_file(std::ifstream&);  // 将文件存入lines_of_text容器中
    void build_map();                 // 生成<单词, 所在行集合>容器
}
;
#endif

        // TextQuery.cpp
#include  < string >
#include 
< fstream >
#include 
< sstream >
#include 
< stdexcept >
#include 
< set >
#include 
< map >
#include 
< vector >
#include 
" TextQuery.h "

using  std:: string ;
using  std::ifstream;
using  std::istringstream;
using  std::out_of_range;
using  std::map;
using  std:: set ;
using  std::vector;

//  读入需要查询的文件
void  TextQuery::store_file(ifstream &   is ) {
  
string textline;
  
while(getline(is, textline))
    lines_of_text.push_back(textline);
}


//  创建map容器
void  TextQuery::build_map() {
  
for(line_no line_num = 0; line_num != lines_of_text.size(); ++line_num){
    istringstream line(lines_of_text[line_num]);
    
string word;
    
while(line >> word)
      word_map[word].insert(line_num);
  }

}


//  返回一个set对象,包含该string对象的多有行的行号.
set < TextQuery::line_no >  TextQuery::run_query( const   string   & query_word)  const {
  map
<stringset<line_no> >::const_iterator loc = word_map.find(query_word);
  
if(loc == word_map.end())
    
return set<line_no>();
  
else
    
return loc->second;
}


//  返回输入文本中该行号对应的文本行.
string  TextQuery::text_line(line_no line)  const {
  
if(line < lines_of_text.size())
    
return lines_of_text[line];
  
throw out_of_range("line number out of range");
}


        // 10012.cpp
#include  < iostream >
#include 
< string >
#include 
< fstream >
#include 
< set >
#include 
" TextQuery.h "

using  std::cin;
using  std::cout;
using  std::cerr;
using  std::endl;
using  std:: string ;
using  std::ifstream;
using  std:: set ;

//  创建复数形式
string  make_plural(size_t ctr,  const   string   & word,  const   string   & ending) {
  
return (ctr == 1? word : word + ending;
}


//  in作为文件指针,file存放文件名称,代开输入文件
ifstream &  open_file(ifstream &   in const   string   & file) {
  
// 清空文件指针的状态
  in.close();
  
in.clear();
  
// open函数输入参数为字符串字面值
  in.open(file.c_str());
  
return in;
}


//  输出
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 
<< " " << sought << " occurs "
       
<< size << " " << make_plural(size, "time""s"<< endl;

  line_nums::const_iterator it 
= locs.begin();
  
for( ; it != locs.end(); ++it){
    cout 
<< " (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;
  }


  
// 将文件读入内存并创建map表,创建结束后关闭文件指针
  TextQuery tq;
  tq.read_file(infile);
  infile.close();
  infile.clear();

  
// 查询
  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 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值