C++primer_关联容器之map

针对C++primer中关联容器11.9的问题

先来一道程序看看吧。程序如下如题目要求是定义一个map,将单词与一个行号的list关联,list中保存单词出现的行号、现在继续

//定义一个map,将单词与一个行号的list关联,list中保存单词出现的行号
//map<string,list<int>>word_lineno
#include <iostream>
#include<fstream>
#include<sstream>
#include <map>
#include<list>
#include <string>
#include <algorithm>
using namespace std;
string &tran(string &s)
{
    for (int p = 0; p < s.size(); ++p)
    {
        if (s[p] >= 'A'&&s[p] <= 'Z')
        {
            s[p] -= ('A' - 'a');
        }
        else if (s[p] == ',' || s[p] == '.')
        {
            s.erase(p, 1);
        }
    }
    return s;
}
int main(int argc, char **argv)
{
    map<string, list<int>>word_lineno;
    string line;
    string word;
    int leneno = 0;
    while (getline(cin, line))
    {
        leneno++;
        while (cin>>word)
        {
            tran(word);
            word_lineno[word].push_back(leneno);
        }
        cin.clear();
    }
    for (const auto &w:word_lineno)
    {
        cout << w.first <<"所在行:";
        for (auto v:w.second)
        {
            cout << v << " ";
        }
        cout << endl;
    }
    system("pause");
    return 0;
} 

这里写图片描述
其中本来答案中需要in文件流绑定,我却用了两个cin来控制文件输入单词以及行号控制。在这里需要注意的是cin的状态,在我们按下一次CTRL+Z后cin状态已经为false了也就是说,在后面再有cin>>word这个语句是无效的,在这样的情况下,需要对cin的状态进行恢复,也就是代码中的cin.clear();

  1. 对于map

针对在map中遇到什么问题使用count,在什么情况下使用find?

  1. find是查找关键字在容器中出现的位置,而count还会统计关键字出现的次数,因此:
    • 当我们需要知道(允许重复关键字出现的情况)容器中有多少元素的关键字相同时,我们使用count;
    • 但是当我们只关心这个关键字是否存在于这个容器内,那么,只需要find就足够了。
    • 总之,对于不允许重复关键字的容器,count和find能达到同样的效果;
    • 最后,说一下find和下标操作的区别,就是当给定关键字不在容器内时,下标操作会插入一个关键字并将他的值定为0,所以在这种情况下,我们应该使用find进行查找。

2.如果给定的关键字不在容器内,upper_bound、lower_bound、equal_range分别会返回什么.

  • lower_bound返回第一个具有给定关键字的元素,upper_bound则返回第一个具有给定关键字的元素之后的位置,就是这两个迭代器构成包含所有给定关键字元素的范围。若是给定关键字不在容器内,两个操作显然应该构成一个空范围,他们返回相当的迭代器,指出关键字的正确插入位置,–还不影响关键字的排序。如果给定关键字比所有关键字都大,那么他插在原先end尾后区域。
  • equal_range返回的是一个pair,他的first成员相当于lower_bound返回的迭代器,second成员相当于upper_bound返回的迭代器。因此若是给定关键字不在容器内,first和second都指向关键字的正确插入位置,两个迭代器构成一个空范围。
编程练习,编写程序,定义一个作者及其相关作品的multimap,使用find在容器内查找一个元素并用erase删除他,确保就算容器内没有这个元素也能运行成功。
#include <iostream>
#include<fstream>
#include<string>
#include<vector>
#include <algorithm>
#include<utility>
#include<map>

using namespace std;
void remove_author(multimap<string, string>&book, const string &author)//删除某个作者及其所映射的书,可以理解成某个作者犯事了,然后被要求,这个作者的书必须的下架。就是这么个意思
{
    auto pos = book.equal_range(author);
    if (pos.first == pos.second)
    {
        cout << "并没有" << "这个作者" << endl;
    }
    else
        book.erase(pos.first, pos.second);
}
void print_books(multimap<string, string>&book)
{
    cout << "当前数目有:" << endl;
    for (auto v:book)
    {
        cout << v.first << ",《" << v.second << "》" << endl;
    }
    cout << endl;
}
int main(int argc, char **argv)
{
    /*vector<pair<string, int>>data;//pair的vector
    string words;
    int v;
    while (cin>>words&&cin>>v)//在这里明显cin不可以用。需要读取文件,或许本来就应该按照文件流的方式读取,
    {
        data.push_back(pair<string, int>(words, v));

    }
    for (auto v:data)
    {
        cout << v.first <<"  "<< v.second << endl;
    }
*/

    multimap<string, string>books;
    books.insert({ "Barth,Jhon", "Sot-Weed Factor" });
    books.insert({ "金庸", "笑傲江湖" });
    books.insert({ "忘语", "凡人修仙传" });
    print_books(books);
    remove_author(books,"忘语");
    print_books(books);
    system("pause");
    return 0;
}

运行结果如下:

这里写图片描述
1. 这里做的操作就是插入三本书,输出,删除一本书,在输出的效果。
2. 在这里还可以使用find和lower_bound、upper_bound也可以实现目标,但是相对而言没有上文简单


单词计数程序

#include <map>
using std::map;

#include <string>
using std::string;

#include <utility>
using std::pair;

#include <cstddef>
using std::size_t;

#include <iostream>
using std::cin; using std::cout; using std::endl;

int main() 
{
    // count the number of times each word occurs in the input
    map<string, size_t> word_count; // empty map from string to size_t
    string word;
    while (cin >> word)
      ++word_count[word];

    for (const auto &w : word_count)
        cout <<  w.first << " occurs " << w.second << " times" << endl;

    // get an iterator positioned on the first element
    auto map_it = word_count.cbegin();
    // compare the current iterator to the off-the-end iterator
    while (map_it != word_count.cend()) {
        // dereference the iterator to print the element key--value pairs
        cout << map_it->first << " occurs " 
             << map_it->second << " times" << endl;
        ++map_it;  // increment the iterator to denote the next element
    }

    return 0;
}

上述代码是C++primer最后一题的标准答案,由此可以看出人家总体的风格较好,比我这个菜鸟水平好多了,考虑的也很周全。


单词转换函数

#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
#include <sstream>

using std::map; using std::string; using std::vector;
using std::ifstream; using std::cout; using std::endl;
using std::getline; 
using std::runtime_error; using std::istringstream;

map<string, string> buildMap(ifstream &map_file)
{
    map<string, string> trans_map;   // holds the transformations
    string key;    // a word to transform
    string value;  // phrase to use instead
    // read the first word into key and the rest of the line into value
    while (map_file >> key && getline(map_file, value))
        if (value.size() > 1) // check that there is a transformation
            trans_map[key] = value.substr(1); // skip leading space 
        else
            throw runtime_error("no rule for " + key);
    return trans_map;
}

const string &
transform(const string &s, const map<string, string> &m)
{
    // the actual map work; this part is the heart of the program
    auto map_it = m.find(s);
    // if this word is in the transformation map
    if (map_it != m.cend()) 
        return map_it->second; // use the replacement word
    else
        return s;              // otherwise return the original unchanged
}

// first argument is the transformations file; 
// second is file to transform
void word_transform(ifstream &map_file, ifstream &input)
{
    auto trans_map = buildMap(map_file); // store the transformations

    // for debugging purposes print the map after its built
    cout << "Here is our transformation map: \n\n";
    for (auto entry : trans_map)
        cout << "key: "   << entry.first
             << "\tvalue: " << entry.second << endl;
    cout << "\n\n";

    // do the transformation of the given text 
    string text;                    // hold each line from the input
    while (getline(input, text)) {  // read a line of input
        istringstream stream(text); // read each word 
        string word;
        bool firstword = true;      // controls whether a space is printed 
        while (stream >> word) {
           if (firstword)
               firstword = false;
           else
               cout << " ";  // print a space between words
           // transform returns its first argument or its transformation 
           cout << transform(word, trans_map); // print the output 
        }
        cout << endl;        // done with this line of input
    }
}

int main(int argc, char **argv)
{
    // open and check both files
    if (argc != 3)
        throw runtime_error("wrong number of arguments");

    ifstream map_file(argv[1]); // open transformation file 
    if (!map_file)              // check that open succeeded
        throw runtime_error("no transformation file");

    ifstream input(argv[2]);    // open file of text to transform
    if (!input)                 // check that open succeeded
        throw runtime_error("no input file");

    word_transform(map_file, input);

    return 0;  // exiting main will automatically close the files
}

//其实代码风格也没有多好,如果仔细看的话。就先这样吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值