文章目录
- c++style 迭代
- vector
- map
- 迭代器
- 流迭代器(按空格读取文件的数据)
- 迭代器种类
- STL算法
- vector求和(accumulate)
- vector求乘积以及取vector的一半
- 二分lower_bound()
- 对每一个元素做重复操作输出到另一个串
- std::rotate将vector前半部分的内容,插到后面。做调换。
- Back Insert
- Lambda Functions
- Lambda Capture
- stl算法小技巧
- std::greater
- std::distance
- std::advance迭代一个list
- unordered_map
- map
容器分为顺序容器(没排序,按顺序放的)还有Ordered Containers
c++style 迭代
#include <array>
#include <iostream>
int main() {
// C-style. Don't do this
// int ages[3] = { 18, 19, 20 };
// for (int i = 0; i < 3; ++i) {
// std::cout << ages[i] << "\n";
// }
// C++ style. This can be used like any other C++ container.
// It has iterators, safe accesses, and it doesn't act like a pointer.
std::array<int, 3> ages{ 18, 19, 20 };
for (unsigned int i = 0; i < ages.size(); ++i) {
std::cout << ages[i] << "\n";
}
for (auto it = ages.begin(); it != ages.end(); ++it) {
std::cout << *it << "\n";
}
for (const auto& age : ages) {
std::cout << age << "\n";
}
}
vector
定义一个vector,
#include <iostream>
#include <vector>
// Begin with numbers 1, 2, 3 in the list already
int main() {
// In C++17 we can omit the int if the compiler can determine the type.
std::vector<int> numbers {1, 2, 3};
int input;
while (std::cin >> input) {
numbers.push_back(input);
}
std::cout << "1st element: " << numbers.at(0) << "\n"; // slower, safer
std::cout << "2nd element: " << numbers[1] << "\n"; // faster, less safe
std::cout << "Max size before realloc: " << numbers.capacity() << "\n";
for (int n : numbers) {
std::cout << n << "\n";
}
}
map
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, double> m;
// The insert function takes in a key-value pair.
std::pair<std::string, double> p1{"bat", 14.75};
m.insert(p1);
// The compiler will automatically construct values as
// required when it knows the required type.
m.insert({"cat", 10.157});
// This is the preferred way of using a map
m.emplace("cat", 10.157);
// This is very dangerous, and one of the most common causes of mistakes in C++.
std::cout << m["bat"] << '\n';
auto it = m.find("bat"); // Iterator to bat if present, otherwise m.end()
// This is a great example of when to use auto, but we want to show you what type it is.
for (const std::pair<const std::string, double>& kv : m) {
std::cout << kv.first << ' ' << kv.second << '\n';
}
}
迭代器
- Iterator is an abstract notion of a pointer
- Iterators are types that abstract container data as a sequence of objects (i.e. linear)
- Iterators will allow us to connect a wide range of containers with a wide range of algorithms via a common interface
vec.cbegin()
, vec.cend()
, vec.crbegin()
, vec.crend()
流迭代器(按空格读取文件的数据)
#include <fstream>
#include <iostream>
#include <iterator>
int main() {
std::ifstream in("data.in");
std::istream_iterator<int>begin(in);
std::istream_iterator<int> end;
std::cout << *begin++ << "\n"; // read the first int
++begin; // skip the 2nd int
std::cout << *begin++ << "\n"; // read the third int
while (begin != end) {
std::cout << *begin++ << "\n"; // read and print the rest
}
}
迭代器种类
五种迭代器
STL算法
vector求和(accumulate)
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> nums{1,2,3,4,5};
int sum = std::accumulate(nums.begin(), nums.end(), 0);
std::cout << sum << "\n";
}
vector求乘积以及取vector的一半
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> v{1,2,3,4,5};
int sum = std::accumulate(v.begin(), v.end(), 0);
// What is the type of std::multiplies<int>()
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
auto midpoint = v.begin() + (v.size() / 2);
// This looks a lot harder to read. Why might it be better?
auto midpoint11 = std::next(v.begin(), std::distance(v.begin(), v.end()) / 2);
int sum2 = std::accumulate(v.begin(), midpoint, 0);
std::cout << sum << "\n";
}
二分lower_bound()
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
int main() {
// Lower bound does a binary search, and returns the first value >= the argument.
std::vector<int> sortedVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::lower_bound(sortedVec.begin(), sortedVec.end(), 5);
std::list<int> sortedLinkedList{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::lower_bound(sortedLinkedList.begin(), sortedLinkedList.end(), 5);
}
对每一个元素做重复操作输出到另一个串
#include <iostream>
#include <vector>
char to_upper(unsigned char value) {
return static_cast<char>(std::toupper(static_cast<unsigned char>(value)));
}
int main() {
std::string s = "hello world";
// Algorithms like transform, which have output iterators,
// use the other iterator as an output.
auto upper = std::string(s.size(), '\0');
std::transform(s.begin(), s.end(), upper.begin(), to_upper);
}
std::rotate将vector前半部分的内容,插到后面。做调换。
Back Insert
#include <iostream>
#include <vector>
char to_upper(char value) {
return static_cast<char>(std::toupper(static_cast<unsigned char>(value)));
}
int main() {
std::string s = "hello world";
// std::for_each modifies each element
std::for_each(s.begin(), s.end(), toupper);
std::string upper;
// std::transform adds to third iterator.
std::transform(s.begin(), s.end(), std::back_inserter(upper), to_upper);
}
Lambda Functions
Lambda Capture
中括号里的就是capture,可以使用域内的变量
#include <iostream>
#include <vector>
void add_n(std::vector<int>& v, int n) {
std::for_each(v.begin(), v.end(), [n] (int& val) { val = val + n; });
}
int main() {
std::vector<int> v{1,2,3};
add_n(v, 3);
}
stl算法小技巧
std::greater
c++14的greater std::sort(numbers, std::greater{});
std::distance
std::advance迭代一个list
#include <iostream>
#include <iterator>
#include <list>
#include <vector>
int main() {
// Manually iterating through a list (forward iteration)
std::list<int> studentMarks1;
studentMarks1.push_back(63);
studentMarks1.push_back(67);
studentMarks1.push_back(69);
studentMarks1.push_back(74);
studentMarks1.push_back(82);
int medianIndex = (studentMarks1.size() / 2);
auto it = studentMarks1.begin();
std::advance(it, medianIndex);
std::cout << "Median: " << *it << "\n";
}
unordered_map
emplace find result->first
#include <unordered_map>
#include "is_permutation.hpp"
// Similarly to `all_unique`, the idea behind this tute question is to get you to play with
// `std::unordered_map` in case you decide it's necessary for Word Ladder. There are other, even
// solutions out there, so if you discovered one --- which is great! --- please spend some time
// tinkering with `std::unordered_map` to get a better handle on its usage.
auto count_letters(std::string const& x) -> std::unordered_map<char, int> {
auto dictionary = std::unordered_map<char, int>();
for (auto const letter : x) {
// `std::unordered_map::find` looks for a key, and returns an iterator to the key/value pair
// entry in the map. It's different to `ranges::find` --- and better suited --- since it is
// specialised for hash-table lookups, whereas `ranges::find` is suited for linear searches.
// With a few exceptions, if there's a member function for a container and a `ranges::`
// function with the same name, the member function is usually better-suted than the
// `ranges::` function.
//
// At this point in the course, the exceptions include: `ranges::begin`, `ranges::end`, and
// `ranges::swap`, all of which can be used *interchangably* with the member counterpart.
// We'll expand on this a lot more in Week 7 (iterator week).
auto result = dictionary.find(letter);
// Since `dictionary.find` might have returned the sentinel value to indicate 'not found', we
// need to check whether or not we actually found something before using it. If we try to use
// something that doesn't exist, we've got a logic error. Exercise: try removing the whole
// if-statement (lines 28-33) and see what happens in both Debug and Release modes. You'll
// find that the program is wrong in both cases, but what happens might be different.
if (result == dictionary.cend()) {
// If there wasn't an entry, then we'd better add it, then move on to the next character in
// the string.
dictionary.emplace(letter, 1);
continue;
}
// Here we increment the value part of our key/value pair. We're not allowed to modify the key
// (Exercise: what happens if you change `second` to `first` and actually try modifying it?).
// `result->second` is a shorthand way of saying `(*exercise).second`. We will cover how this
// works partly in Week 3 and then follow up on it in Week 7 (iterator week).
++result->second;
}
return dictionary;
}
auto is_permutation(std::string const& x, std::string const& y) -> bool {
return count_letters(x) == count_letters(y);
}
map
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, double> m;
// The insert function takes in a key-value pair.
std::pair<std::string, double> p1{"bat", 14.75};
m.insert(p1);
// The compiler will automatically construct values as
// required when it knows the required type.
m.insert({"cat", 10.157});
// This is the preferred way of using a map
m.emplace("cat", 10.157);
// This is very dangerous, and one of the most common causes of mistakes in C++.
std::cout << m["bat"] << '\n';
auto it = m.find("bat"); // Iterator to bat if present, otherwise m.end()
// This is a great example of when to use auto, but we want to show you what type it is.
for (const std::pair<const std::string, double>& kv : m) {
std::cout << kv.first << ' ' << kv.second << '\n';
}
}