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
}

//其實代碼風格也沒有多好,如果仔細看的話。就先這樣吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章