C++标准模板库编程实战 第七章 更多算法

7.1 检查元素的属性

当我们想知道序列元素是否由某种特性或有多少符合标准时可以使用以下算法:

如果想知道具体的--序列中哪个元素匹配,使用第六章的find()。

1.检查序列中元素是否可以使谓词返回true。

all_of(),序列中所有元素返回true,就返回true.

std::cout << "There are "
 << (std::any_of(std::begin(ages), std::end(ages),
 [min_age](int age) { return age < min_age; }) ? "some": "no")
 << " people under " << min_age << std::endl

any_of(),序列中任意一个返回true,就返回true

none_of(),没有元素能使谓词返回true,就返回true。

std::vector<int> ages {22, 19, 46, 75, 54, 19, 27, 66, 61, 33, 22, 19};
int min_age{18};
std::cout << "There are "
 << (std::none_of(std::begin(ages), std::end(ages),
 [min_age](int age) { return age < min_age; }) ? "no": "some")
 << " people under " << min_age << std::endl;

2.count() count_if() 前两个参数范围内,有多少个满足指定的第三个参数条件的元素。

count返回等于第三个参数的元素个数,count_if()返回使第三个谓词返回true的元素个数。

std::vector<int> ages {22, 19, 46, 75, 54, 19, 27, 66, 61, 33, 22, 19};
int the_age{19};
std::cout << "There are "
 << std::count(std::begin(ages), std::end(ages), the_age)
 << " people aged " << the_age << std::endl;
int max_age{60};
std::cout << "There are "
 << std::count_if(std::begin(ages), std::end(ages),
 [max_age](int age) { return age > max_age; })
 << " people aged over " << max_age << std::endl;

7.2 序列的比较

有四个版本的equal(),其中两个用==,两个用自定义比较函数。

第一个版本接受三个参数,前两个是第一个序列的开始和结束迭代器,第三个参数是第二个序列的开始迭代器。如果第二个序列的长度小于第一个序列,结果是未定义的。

第二个版本结束四个参数,头两个和第一个版本一样,后两个确定第二个序列的范围,如果两个序列长度不一样,结果总是返回false。

推荐使用第二个版本,不会产生未定义结果。

#include <iostream> // For standard streams
#include <vector> // For vector container
#include <algorithm> // For equal() algorithm
#include <iterator> // For stream iterators
#include <string> // For string class
using std::string;
int main()
{
 std::vector<string> words1 {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
 std::vector<string> words2 {"two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};
 auto iter1 = std::begin(words1);
 auto end_iter1 = std::end(words1);
 auto iter2 = std::begin(words2);
 auto end_iter2 = std::end(words2);
 std::cout << "Container - words1: ";
 std::copy(iter1, end_iter1, std::ostream_iterator<string>{std::cout, " "});
 std::cout << "\nContainer - words2: ";
 std::copy(iter2, end_iter2, std::ostream_iterator<string>{std::cout, " "});
 std::cout << std::endl;
 std::cout << "\n1. Compare from words1[1] to end with words2: ";
 std::cout << std::boolalpha << std::equal(iter1 + 1, end_iter1, iter2) << std::endl;
 std::cout << "2. Compare from words2[0] to second-to-last with words1: ";
 std::cout << std::boolalpha << std::equal(iter2, end_iter2 - 1, iter1) << std::endl;
 std::cout << "3. Compare from words1[1] to words1[5] with words2: ";
 std::cout << std::boolalpha << std::equal(iter1 + 1, iter1 + 6, iter2) << std::endl;
 std::cout << "4. Compare first 6 from words1 with first 6 in words2: ";
 std::cout << std::boolalpha << std::equal(iter1, iter1 + 6, iter2, iter2 + 6) << std::endl;
 std::cout << "5. Compare all words1 with words2: ";
 std::cout << std::boolalpha << std::equal(iter1, end_iter1, iter2) << std::endl;
 std::cout << "6. Compare all of words1 with all of words2: ";
 std::cout << std::boolalpha << std::equal(iter1, end_iter1, iter2, end_iter2) << std::endl;
 std::cout << "7. Compare from words1[1] to end with words2 from first to second-to-last: ";
 std::cout << std::boolalpha
 << std::equal(iter1 + 1, end_iter1, iter2, end_iter2 - 1) << std::endl;
}

尽管可以用equal()比较两个同类型的容器的全部内容,但最好还是使用容器的成员函数operator==()。

7.2.1 查找序列的不同之处

equal()算法可以告诉我们两个序列是否匹配,

mismatch()算法也可以,而且如果不匹配,返回的pair对象包含两个迭代器:first是第一个序列的迭代器,second是第二个序列的迭代器,当序列不匹配时,这一对迭代器指向第一对不匹配的元素。这个pair<iter1+n,iter2+n>.

#include <iostream> // For standard streams
#include <vector> // For vector container
#include <algorithm> // For equal() algorithm
#include <string> // For string class
#include <iterator> // For stream iterators
using std::string;
using word_iter = std::vector<string>::iterator;
int main()
{
 std::vector<string> words1 {"one", "two", "three", "four", 
"five", "six", "seven", "eight", "nine"};
 std::vector<string> words2 {"two", "three", "four", "five", 
"six", "eleven", "eight", "nine", "ten"};
 auto iter1 = std::begin(words1);
 auto end_iter1 = std::end(words1);
 auto iter2 = std::begin(words2);
 auto end_iter2 = std::end(words2);
 // Lambda expression to output mismatch() result
 auto print_match = [](const std::pair<word_iter, word_iter>& pr, const word_iter& end_iter)
 {
 if(pr.first != end_iter)
 std::cout << "\nFirst pair of words that differ are "
 << *pr.first << " and " << *pr.second << std::endl;
 else
 std::cout << "\nRanges are identical." << std::endl;
 };
 std::cout << "Container - words1: ";
 std::copy(iter1, end_iter1, std::ostream_iterator<string>{std::cout, " "});
 std::cout << "\nContainer - words2: ";
 std::copy(iter2, end_iter2, std::ostream_iterator<string>{std::cout, " "});
 std::cout << std::endl;
 std::cout << "\nCompare from words1[1] to end with words2:";
 print_match(std::mismatch(iter1 + 1, end_iter1, iter2), end_iter1);
 std::cout << "\nCompare from words2[0] to second-to-last with words1:";
 print_match(std::mismatch(iter2, end_iter2 - 1, iter1), end_iter2 - 1);
 std::cout << "\nCompare from words1[1] to words1[5] with words2:";
 print_match(std::mismatch(iter1 + 1, iter1 + 6, iter2), iter1 + 6);
 std::cout << "\nCompare first 6 from words1 with first 6 in words2:";
 print_match(std::mismatch(iter1, iter1 + 6, iter2, iter2 + 6), iter1 + 6);
 std::cout << "\nCompare all words1 with words2:";
 print_match(std::mismatch(iter1, end_iter1, iter2), end_iter1);
 std::cout << "\nCompare all of words2 with all of words1:";
 print_match(std::mismatch(iter2, end_iter2, iter1, end_iter1), end_iter2);
 std::cout << "\nCompare from words1[1] to end with words2[0] to second-to-last:";
 print_match(std::mismatch(iter1 + 1, end_iter1, iter2, end_iter2 - 1), end_iter1);
}
7.2.2 按字典序比较序列

lexicographical_compare()

std::vector<string> phrase1 {"the", "tigers", "of", "wrath"};
std::vector<string> phrase2 {"the", "horses", "of", "instruction"};
auto less = std::lexicographical_compare(std::begin(phrase1), std::end(phrase1),
 std::begin(phrase2), std::end(phrase2));
std::copy(std::begin(phrase1), std::end(phrase1), std::ostream_iterator<string>{std::cout, " "});
std::cout << (less ? "are" : "are not") << " less than ";
std::copy(std::begin(phrase2), std::end(phrase2), std::ostream_iterator<string>{std::cout, " "});
std::cout << std::endl;

7.2.3 序列的排列

next_permutation()生成一个序列的重排列,是所有可能的字典序的下一个排列,默认使用<运算符。

在下一个排列大于上一个排列时返回true,如果上一个排列是序列中最大的,它返回false。

std::vector<int> range {1,2,3,4};
do
{
 std::copy(std::begin(range), std::end(range), std::ostream_iterator<int> {std::cout, " "});
 std::cout << std::endl;
} while(std::next_permutation(std::begin(range), std::end(range)));

使用next_permutation可以得到序列的全排列。

std::vector<string> words {"one","two", "three", "four", "five", "six", "seven", "eight"};
while(std::next_permutation(std::begin(words), std::end(words))) // Change to minimum
;
do
{
 std::copy(std::begin(words), std::end(words), std::ostream_iterator<string> {std::cout, " "});
 std::cout << std::endl;
} while(std::next_permutation(std::begin(words), std::end(words)));

当序列中每个元素都小于或等于它后面的元素时,它就是元素序列的最小排列。

所以可以用min_element()返回指向序列中最小元素的迭代器,然后用iter_swap()算法,交换两个迭代器,从而生成最小排列,然后可以作为next_permutation的起始点生成全排列:

std::vector<string> words {"one","two", "three", "four", "five", "six", "seven", "eight"};
for (auto iter = std::begin(words); iter != std::end(words)-1 ;++iter)
 std::iter_swap(iter, std::min_element(iter, std::end(words)));

开始生成全排列之前,可以先生成元素容器的副本,避免到达最小排列的全部开销:

std::vector<string> words {"one","two", "three", "four", "five", "six", "seven", "eight"};
auto words_copy = words; // Copy the original
do
{
 std::copy(std::begin(words), std::end(words), std::ostream_iterator<string> {std::cout, " "});
 std::cout << std::endl;
 std::next_permutation(std::begin(words), std::end(words));
} while(words != words_copy); // Continue until back to the original

2.prev_permutation()与next_permutation()相反。

3.is_permutation()检查一个序列是不是另一个序列的排列。

std::vector<double> data1 {44.5, 22.0, 15.6, 1.5};
std::vector<double> data2 {22.5, 44.5, 1.5, 15.6};
std::vector<double> data3 {1.5, 44.5, 15.6, 22.0};
auto test = [](const auto& d1, const auto& d2)
 {
 std::copy(std::begin(d1), std::end(d1), std::ostream_iterator<double> {std::cout, " "});
 std::cout << (is_permutation(std::begin(d1), std::end(d1), std::begin(d2), std::end(d2)) ?
 "is": "is not")
 << " a permutation of ";
 std::copy(std::begin(d2), std::end(d2), std::ostream_iterator<double> {std::cout, " "});
 std::cout << std::endl;
 };
test(data1, data2);
test(data1, data3);
test(data3, data2);

4.也可以用shuffle()算法生成序列的随机排列。

7.3 复制序列

copy()

7.3.1 复制一定数量的元素

copy_n() 复制指定个数的元素到目的容器。第一个参数是源输入迭代器,第二个参数是需要复制的元素个数,第三个参数指向目的容器的第一个位置的迭代器。

std::vector<string> names {"Al", "Beth", "Carol", "Dan", "Eve",
 "Fred", "George", "Harry", "Iain", "Joe"};
std::unordered_set<string> more_names {"Janet", "John"};
std::copy_n(std::begin(names) + 1, 3, std::inserter(more_names, std::begin(more_names)));
std::copy_n(std::begin(more_names), more_names.size()-1,
 std::ostream_iterator<string> {std::cout, " "});

如果被复制元素个数超过了实际元素的个数,程序会奔溃。如果元素个数为0或负数,copy_n()算法什么也不做。

7.3.2 条件复制

copy_if()算法可以复制使谓词返回true的元素,可以看作是一个过滤器。

前两个参数定义源序列,第三个参数是指向目的序列的第一个位置的输出迭代器,第四个参数是谓词。返回一个输出迭代器,指向最后一个被复制元素的下一个位置。:

std::vector<string> names {"Al", "Beth", "Carol", "Dan", "Eve",
 "Fred", "George", "Harry", "Iain", "Joe"};
std::unordered_set<string> more_names {"Jean", "John"};
size_t max_length{4};
std::copy_if(std::begin(names), std::end(names), std::inserter(more_names, std::begin(more_names)),
[max_length](const string& s){ return s.length() <= max_length; });

7.3.3 反向复制

copy_backward() 前两个迭代器参数指定源序列,第三个参数是目的序列的结束迭代器。

三个参数必须是可以自增或自减的双向迭代器。意味着这个算法只能应用到序列容器的序列上。

返回一个指向最后一个被复制元素的迭代器,在目的序列的新位置,它是一个开始迭代器。

优势:在序列重叠时,更好用:

 std::deque<string> song{"jingle", "bells", "jingle", "all", "the", "way"};
 song.resize(song.size()+2); // Add 2 elements
 std::copy_backward(std::begin(song), std::begin(song)+6, std::end(song));
 std::copy(std::begin(song), std::end(song), std::ostream_iterator<string>{std::cout, " "});
 std::cout << std::endl;

7.4 复制和反向元素顺序

reverse_copy() 反向复制,如果序列是重叠的,函数行为是未定义的。

#include <iostream> // For standard streams
#include <iterator> // For stream iterators and begin() and end()
#include <algorithm> // For reverse_copy() and copy_if()
#include <cctype> // For toupper() and isalpha()
#include <string>
using std::string;
int main()
{
 while(true)
 {
 string sentence;
 std::cout << "Enter a sentence or Ctrl+Z to end: ";
 std::getline(std::cin, sentence);
 if(std::cin.eof()) break;
 // Copy as long as the characters are alphabetic & convert to upper case
 string only_letters;
 std::copy_if(std::begin(sentence), std::end(sentence), std::back_inserter(only_letters),
 [](char ch) { return std::isalpha(ch); });
 std::for_each(std::begin(only_letters), std::end(only_letters), [](char& ch) 
{ ch = toupper(ch); });
// Make a reversed copy
 string reversed;
 std::reverse_copy(std::begin(only_letters), std::end(only_letters), 
std::back_inserter(reversed));
 std::cout << '"' << sentence << '"'
 << (only_letters == reversed ? " is" : " is not") << " a palindrome." << std::endl;
 }
}

7.5 复制一个删除相邻重复元素的序列

unique_copy()将一个序列复制到另一个序列中,同时会移除连续的重复元素。

string text {"Have you seen how green the trees seem?"};
string result{};
std::unique_copy(std::begin(text), std::end(text), std::back_inserter(result));
std::cout << result << std::endl;

也可以提供比较的函数对象。

string text {"There's no air in spaaaaaace!"};
string result {};
std::unique_copy(std::begin(text), std::end(text), std::back_inserter(result),
 [](char ch1, char ch2) { return ch1 == ' ' && ch1 == ch2; });
 std::cout << result << std::endl;

7.6 从序列中移除相邻的重复元素

unique() 也可以自定义比较函数对象。

7.7 旋转序列

1.rotate()

返回一个迭代器,指向原始的第一个元素所在的新位置。

std::vector<string> words {"one", "two", "three", "four", "five", "six", "seven", "eight"};
auto iter = std::rotate(std::begin(words), std::begin(words)+3, std::end(words));
std::copy(std::begin(words), std::end(words), std::ostream_iterator<string> {std::cout, " "});
std::cout << std::endl << "First element before rotation: " << *iter << std::endl;

也可以部队全部元素进行旋转:

std::vector<string> words {"one", "two", "three", "four", "five",
 "six", "seven", "eight", "nine", "ten"};
auto start = std::find(std::begin(words), std::end(words), "two");
auto end_iter = std::find(std::begin(words), std::end(words), "eight");
auto iter = std::rotate(start, std::find(std::begin(words), std::end(words), "five"), end_iter);
std::copy(std::begin(words), std::end(words), std::ostream_iterator<string> {std::cout, " "});
std::cout << std::endl << "First element before rotation: " << *iter << std::endl;

2.rotate_copy()

第四个参数是一个输出迭代器。返回一个目的序列的输出迭代器,指向最后一个被复制元素的下一个位置。:

std::vector<string> words {"one", "two", "three", "four", "five",
 "six", "seven", "eight", "nine", "ten"};
auto start = std::find(std::begin(words), std::end(words), "two");
auto end_iter = std::find(std::begin(words), std::end(words), "eight");
std::vector<string> words_copy;
std::rotate_copy(start, std::find(std::begin(words), std::end(words), "five"), end_iter,
 std::back_inserter(words_copy));
std::copy(std::begin(words_copy), std::end(words_copy), 
std::ostream_iterator<string> {std::cout, " "});
std::cout << std::endl;

7.8 移动序列

1.move()返回的迭代器指向最后一个被移动到目的序列的元素的下一个位置。

如果源序列可以被替换或破坏,就可以选择使用move,否则使用copy().:

如果移动操作的目的地址位于源序列之内,move就不能正常工作。

2.move_backward()可以

std::deque<int> data {1, 2, 3, 4, 5, 6, 7, 8};
std::move_backward(std::begin(data), std::end(data) - 2, std::end(data));
data[0] = data[1] = 0; // Reset moved elements
std::copy(std::begin(data), std::end(data), std::ostream_iterator<int> {std::cout, " "});
std::cout << std::endl; // 0, 0, 1, 2, 3, 4, 5, 6

3. swap_ranges()

交换两个序列:

using Name = std::pair<string, string>; // First and second name
std::vector<Name> people {Name{"Al", "Bedo"}, Name{"Ann", "Ounce"}, Name{"Jo", "King"}};
std::list<Name> folks {Name{"Stan", "Down"}, Name{"Dan", "Druff"}, Name{"Bea", "Gone"}};
std::swap_ranges(std::begin(people), std::begin(people) + 2, ++std::begin(folks));
std::for_each(std::begin(people), std::end(people),
 [](const Name& name)
{std::cout << '"' << name.first << " " << name.second << "\" ";});
std::cout << std::endl; // "Dan Druff" "Bea Gone" "Jo King"
std::for_each(std::begin(folks), std::end(folks),
 [](const Name& name)
{std::cout << '"' << name.first << " " << name.second << "\" "; });
 std::cout << std::endl; // "Stan Down" "Al Bedo" "Ann Ounce"

此代码没有给pair对象重载operator<<()函数,因此不能用copy(),用for_each()。

使用swap()交换两个对象。

7.9 从序列中移除元素

remove() 从前两个参数指定的序列中移除和第三个参数相等的对象。

std::deque<double> samples {1.5, 2.6, 0.0, 3.1, 0.0, 0.0, 4.1, 0.0, 6.7, 0.0};
samples.erase(std::remove(std::begin(samples), std::end(samples), 0.0), std::end(samples));
std::copy(std::begin(samples), std::end(samples), std::ostream_iterator<double> {std::cout, " "});
std::cout << std::endl; // 1.5 2.6 3.1 4.1 6.7

remove_copy()将前两个参数指定的序列复制到第三个参数指定的目的序列,并忽略和第四个参数相等的元素。

想保留元素序列并生成一个移除选定元素之后的副本。

std::deque<double> samples {1.5, 2.6, 0.0, 3.1, 0.0, 0.0, 4.1, 0.0, 6.7, 0.0};
std::vector<double> edited_samples;
std::remove_copy(std::begin(samples), std::end(samples), std::back_inserter(edited_samples), 0.0);

remove_if()移除是第三个参数谓词为true的元素。

using Name = std::pair<string, string>; // First and second name
std::set<Name> blacklist {Name {"Al", "Bedo"}, Name {"Ann", "Ounce"}, Name {"Jo", "King"}};
std::deque<Name> candidates {Name {"Stan", "Down"}, Name {"Al", "Bedo"}, Name {"Dan", "Druff"},
 Name {"Di", "Gress"}, Name {"Ann", "Ounce"}, Name {"Bea", "Gone"}};
candidates.erase(std::remove_if(std::begin(candidates), std::end(candidates),
 [&blacklist](const Name& name) { return blacklist.count(name); }),
 std::end(candidates));
std::for_each(std::begin(candidates), std::end(candidates), [](const Name& name)
 {std::cout << '"' << name.first << " " << name.second << "\" "; });
 std::cout << std::endl; // "Stan Down" "Dan Druff" "Di Gress" "Bea Gone"

remove_copy_if()将能够使第四个参数谓词返回true的元素复制到第三个参数指定的目的序列中。

remove_copy_if()之于remove_copy(),就像 remove_if()之于remove()。

std::set<Name> blacklist {Name {"Al", "Bedo"}, Name {"Ann", "Ounce"}, Name {"Jo", "King"}};
std::deque<Name> candidates {Name {"Stan", "Down"}, Name {"Al", "Bedo"}, Name {"Dan", "Druff"},
 Name {"Di", "Gress"}, Name {"Ann", "Ounce"}, Name {"Bea", "Gone"}};
std::deque<Name> validated;
std::remove_copy_if(std::begin(candidates), std::end(candidates), std::back_inserter(validated),
 [&blacklist](const Name& name) { return blacklist.count(name); });

7.10 设置和修改序列中的元素。

7.10.1 用函数生成元素的值

generate()只是赋值和for_each(),对元素进行引用,所以想干啥就干啥。

generate_n() 第二个参数表示参与运算的元素个数。

string chars (30, ' '); // 30 space characters
char ch {'a'};
int incr {};
std::generate_n(std::begin(chars), chars.size()/2,[ch, &incr]
 {
 incr += 3;
 return ch + (incr % 26);
 });
7.10.2 转换序列

transform()将函数应用到序列上,并将函数返回值保存到另一个容器中。

有一个版本和for_each()相似,可以将一个一元函数应用到元素序列上改变他们的值,区别在于:

for_each()使用的函数返回类型必须是void,而且可以通过函数的引用参数改变输入序列的值。

transform()的二元函数必须返回一个值。for_each()总是应用到输入序列上transform()不保证:

std::vector<double> deg_C {21.0, 30.5, 0.0, 3.2, 100.0};
std::vector<double> deg_F(deg_C.size());
std::transform(std::begin(deg_C), std::end(deg_C), std::begin(deg_F),
 [](double temp){ return 32.0 + 9.0* temp/5.0; }); // Result 69.8 86.9 32 37.76 212

将结果保存到空的容器中:

std::vector<double> deg_F; // Empty container
std::transform(std::begin(deg_C), std::end(deg_C), std::back_inserter(deg_F),
 [](double temp){ return 32.0 + 9.0* temp/5.0; }); // Result 69.8 86.9 32 37.76 212

第三个参数可以是指向输入序列的迭代器:

std::vector<double> temps {21.0, 30.5, 0.0, 3.2, 100.0}; // In Centigrade
std::transform(std::begin(temps), std::end(temps), std::begin(temps),
 [](double temp) 
{ return 32.0 + 9.0* temp / 5.0; }); // Result 69.8 86.9 32 37.76 212

目的序列和输入序列可以类型不同:

std::vector<string> words {"one", "two", "three", "four", "five"};
std::vector<size_t> hash_values;
std::transform(std::begin(words), std::end(words), std::back_inserter(hash_values),
 std::hash<string>()); // string hashing function
std::copy(std::begin(hash_values), std::end(hash_values),
 std::ostream_iterator<size_t> {std::cout, " "});
std::cout << std::endl;

可以将tansform()所运用的函数为序列调用一个算法:

std::deque<string> names {"Stan Laurel", "Oliver Hardy", "Harold Lloyd"};
std::transform(std::begin(names), std::end(names), std::begin(names),
 [](string& s) { std::transform(std::begin(s), std::end(s),std::begin(s), ::toupper);
 return s;
 });
 std::copy(std::begin(names), std::end(names), std::ostream_iterator<string> {std::cout, " "});
 std::cout << std::endl

二元函数版本的transform():

前两个参数是第一个序列,第三个参数是第二个序列的开始迭代器,所以第二个序列长度要大于等于第一个序列。

第四个参数是输出迭代器,用来保存结果。

第五个参数是一个函数对象。

7.10.3 替换序列中的元素

replace()用新的值替换和给定值相匹配的元素。

std::deque<int> data {10, -5, 12, -6, 10, 8, -7, 10, 11};
std::replace(std::begin(data), std::end(data), 10, 99); // Result: 99 -5 12 -6 99 8 -7 99 11

replace_if()将使谓词为true替换为新的值:

string password {"This is a good choice!"};
std::replace_if(std::begin(password), std::end(password),
 [](char ch){return std::isspace(ch);}, '_'); // Result: This_is_a_good_choice!

replace_copy()算法和replace()做的事一样,但结果会被保存到另一个序列中,而不改变原始序列。

std::vector<string> words {"one", "none", "two", "three", "none", "four"};
std::vector<string> new_words;
std::replace_copy(std::begin(words), std::end(words), std::back_inserter(new_words),
 string{"none"}, string{"0"}); // Result: "one", "0", "two", "three", "0", "four"

replace_copy_if():

std::deque<int> data {10, -5, 12, -6, 10, 8, -7, 10, 11};
std::vector<int> data_copy;
std::replace_copy_if(std::begin(data), std::end(data),
 std::back_inserter(data_copy),
 [](int value) {return value == 10;}, 99); // Result: 99 -5 12 -6 99 8 -7 99 11

课后练习

pe7_1:

#include<iostream>
#include<deque>
#include<tuple>
#include<algorithm>
#include<string>
#include<random>
using  namespace std;
enum class MONTH  {January, February, March ,April, May, June, July, August, September, October, November, December};
static string mmm[12] = { "January", "February", "March" ,"April", "May", "June", "July", "August", "September", "October", "November", "December" };

int generate_rand(const int& min, const int& max );
bool com_tuple(const tuple<string, int, int>& aa, const tuple<string, int, int>& bb);
int main() {
	deque<tuple<string, int, int>> que;
	tuple<string, int, int> combine;
	string month;
	int day, year;

	for (int i = 0; i < 100; i++)
	{
		year = generate_rand(2021, 2025);
		month = mmm[generate_rand(0, 11)];
		day = generate_rand(1, 30);
		que.push_back(tuple(month, day, year));
	}
	/*while (true)
	{
		if ((cin >> month >> day >> year).eof()) {
			cin.clear();
			break;
		}
		que.push_back(tuple( month,day,year ));
	}*/
	cout << "show all: " << endl;
	for (auto value : que) {
		cout << get<2>(value)<<" " << get<0>(value)<<" " << get<1>(value) << endl;
	}
	cout << "show count: " << endl;
	for (int i = 0; i < 12; i++) {
		auto temp = mmm[i];
		auto feb = count_if(begin(que), end(que), [&temp](tuple<string, int, int> tt) {return get<0>(tt) == temp; });
		cout << "the numbers of " << temp << " is: " << feb << endl;
	}
	sort(begin(que), end(que),com_tuple);
	cout << "show sort: " << endl;
	for (auto value : que) {
		cout << get<2>(value) << " " << get<0>(value) << " " << get<1>(value) << endl;
	}
	return 0;
}
int generate_rand(const int& min, const int& max) {
	std::random_device rd;
	std::mt19937 gen(rd());

	std::uniform_int_distribution<> dis(min, max);

	return dis(gen);
}
bool com_tuple(const tuple<string, int, int>& aa, const tuple<string, int, int>& bb) {
	if (get<2>(aa) != get<2>(bb)) {
		//先判断年
		return get<2>(aa) < get<2>(bb);
	}
	else if (get<0>(aa) != get<0>(bb)) {
		//判断月
		return get<0>(aa) < get<0>(bb);
	}
	else 
		return get<1>(aa) < get<1>(bb);
	
}

pe7_2:

#include<iostream>
#include<tuple>
#include<map>
#include<vector>
#include<algorithm>
#include <cmath>

using namespace std;
//pair<int, float> make_unifeet(int& feet=0, float& inches=0.0);报错:非常量引用的初始值必须为左值
pair<int, float> make_unifeet(int feet = 0, float inches = 0.0);
int main() {
	int feet;
	float inches;
	vector<pair<int, float>> height;
	while (true) {
		if ((cin>>feet>>inches).eof()) {
			cin.clear();
			break;
		}
		height.push_back(make_unifeet(feet, inches));
	}
	vector<tuple<int, float, float >> after_trans(height.size());//不初始化大小报错:Expression:cannot seek value-initialized vector iterator
	transform(begin(height), end(height), begin(after_trans), [](pair<int, float> pp) { 
		float cm = static_cast<float>( (12 * pp.first + pp.second)*2.54);
		int m;
		float mm;
		if (cm >= 100) {
			m = static_cast<int>(cm / 100);
			cm = static_cast<float>(fmod(cm, 100));
			mm = std::modf(cm, &cm);//取整数部分到cm,返回小数部分到mm.
		}
		else {
			m = 0;
			mm = std::modf(cm, &cm);//取整数部分到cm,返回小数部分到mm.
		}
		return tuple<int, float, float >(m, cm, mm);
		});
	vector< pair<pair<int, float>, tuple<int, float, float > > > result(height.size());
	transform(begin(height), end(height), begin(after_trans), begin(result), [](pair<int, float> pp, tuple<int, float, float >tt) {return make_pair(pp, tt); });
	for_each(begin(result), end(result), [&result](pair<pair<int, float>, tuple<int, float, float > > pp) {
		cout << "英制:" << pp.first.first<<"英尺"<<pp.first.second << "英寸" <<endl<< "公制:" 
			<<get<0>(pp.second)<< "米" << get<1>(pp.second) << "厘米"<< get<2>(pp.second) << "毫米" << endl;
		});
	return 0;
}
pair<int, float> make_unifeet(int feet , float inches) {
	//1 英寸 = 2.54 厘米(cm)= 25.4 毫米(mm)[4]
	//在英制,12英寸为1英尺,36英寸为1码
	if (inches > 12) {
		feet = static_cast<int>(feet + inches / 12);
		//inches = inches % 12;报错 %必须是整形;
		inches = static_cast<float>(fmod(inches, 12.0));

		return make_pair(feet, inches);
	}
	else return make_pair(feet, inches);
		
}

pe7_3:

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
using namespace std;
int main() {
	string word;
	vector<string> words;
	string aword;
	while (true)
	{
		if ((cin >> word).eof()) {
			cin.clear();
			break;
		}
		//for_each(begin(word), end(word), [&words](char c) {if (isalpha(c)) ; });
		aword.clear();
		for (auto value : word) {
			if (isalnum(value)) aword.push_back(value);
		}
		if(!aword.empty())	words.push_back(aword);
	}
	cout << "show all: " << endl;
	for (auto value : words) {
		cout << value << " ";
	}
	set<string> single_words;
	//copy(begin(words), end(words), back_inserter(single_words));//报错因为set没有push_back
	copy(begin(words), end(words), inserter(single_words,begin(single_words)));
	int number = 0;
	for (auto value : single_words) {
		if (count(begin(words), end(words), value) > 1) {
			cout << "the number of " << value << " is: " << count(begin(words), end(words), value) << endl;
			number++;
		}
	}
	cout << "重复单词个数为:" << number << endl;

	vector<string> less_5(words.size());
	//transform(begin(words), end(words), begin(less_5), [&words](string s) {		if (s.length() < 5)return s;});//异常退出,因为大于等于5的字符串没处理。
	copy_if(begin(words), end(words), begin(less_5), [&words](string s) {return s.length() < 5; });
	cout << "少于5个字符:" << endl;
	for (auto value : less_5) {
		cout << value << " ";
	}

	return 0;
}

pe7_4:

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
using namespace std;
int main() {
	string word;
	vector<string> words;
	string aword;
	while (true)
	{
		if ((cin >> word).eof()) {
			cin.clear();
			break;
		}
		//for_each(begin(word), end(word), [&words](char c) {if (isalpha(c)) ; });
		aword.clear();
		for (auto value : word) {
			if (isalnum(value)) aword.push_back(value);
		}
		if (!aword.empty())	words.push_back(aword);
	}
	cout << "show all: " << endl;
	for (auto value : words) {
		cout << value << " ";
	}
	vector<string> words_copy = words;
	long number = 0;
	do {
		copy(begin(words), end(words), ostream_iterator<string>(cout, " "));
		cout << endl;
		next_permutation(begin(words), end(words));
		number++;
	} while (words != words_copy);
	cout << "总共有:" << number << " 个排列。" << endl;

	return 0;
}

pe7_5:

#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int main() {
	string firstname;
	string lastname;
	vector<pair<string, string>> names;
	while (true)
	{
		if ((cin >> firstname >> lastname).eof()) {
			cin.clear();
			break;
		}
		//names.push_back(make_pair(firstname, lastname));
		names.emplace_back(firstname, lastname);
	}
	vector<pair<string, string>> same_first;
	set<char> set_same;
	for (auto value : names) {
		set_same.insert(value.first[0]);
	}
	cout << "共同首字母:" << endl;
	for_each(begin(names), end(names), [&same_first,&set_same](pair<string,string> pp) {
		if (find(begin(set_same), end(set_same), pp.first[0]) != end(set_same)) {
			same_first.emplace_back(pp);
			//cout << pp.first << " " << pp.second << endl;
		}
			
	});
	sort(begin(same_first), end(same_first), [](const pair<string, string>& left, const pair<string, string>& right) {
			return left.first < right.first; });
	for (auto value : same_first) {
		cout << value.first << " " << value.second << endl;
	}

	vector<pair<char, string>> char_name;
	for (auto value : names) {
		char_name.emplace_back(value.first[0], value.second);
	}
	sort(begin(char_name), end(char_name), [](const pair<char, string>& left, const pair<char, string>& right)
		{	return left.second.length() < right.second.length(); });
	cout << "新形势名字:" << endl;
	for (auto value : char_name) {
		cout << value.first << " " << value.second << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值