針對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();
- 對於map
針對在map中遇到什麼問題使用count,在什麼情況下使用find?
- 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
}
//其實代碼風格也沒有多好,如果仔細看的話。就先這樣吧。