- Mastering the C++17 STL
- Arthur O'Dwyer
- 327字
- 2021-07-08 10:20:24
Rotation and permutation
Remember our code from Swapping, reversing, and partitioning to reverse the order of words in a sentence? When the "sentence" contains only two words, there is another way to look at the reversal: you could consider it a cyclic rotation of the elements in the underlying range. std::rotate(a,mid,b) rotates the elements of the range [a,b) so that the element formerly addressed by mid is now at a (and returns an iterator pointing to the element whose value was formerly at a):
template<class FwdIt>
FwdIt rotate(FwdIt a, FwdIt mid, FwdIt b)
{
auto result = a + (b - mid);
// First, reverse the whole range.
std::reverse(a, b);
// Next, un-reverse each individual segment.
std::reverse(a, result);
std::reverse(result, b);
return result;
}
void test()
{
std::vector<int> v = {1, 2, 3, 4, 5, 6};
auto five = std::find(v.begin(), v.end(), 5);
auto one = std::rotate(v.begin(), five, v.end());
assert((v == std::vector{5, 6, 1, 2, 3, 4}));
assert(*one == 1);
}
Another miscellaneous but sometimes useful permutative algorithm is std::next_permutation(a,b). Calling this function in a loop runs through all the possible permutations of n elements, which might be useful if you're trying to brute-force a solution to a (small) instance of the Traveling Salesman Problem:
std::vector<int> p = {10, 20, 30};
std::vector<std::vector<int>> results;
// Collect the permutations of these three elements.
for (int i=0; i < 6; ++i) {
results.push_back(p);
std::next_permutation(p.begin(), p.end());
}
assert((results == std::vector<std::vector<int>>{
{10, 20, 30},
{10, 30, 20},
{20, 10, 30},
{20, 30, 10},
{30, 10, 20},
{30, 20, 10},
}));
Notice that next_permutation uses the idea of a "less-than relationship" to determine that one permutation is lexicographically "less than" another; for example, {20, 10, 30} is "less than" {20, 30, 10} because 10 is less than 30. Therefore, next_permutation also has a comparator-based version: std::next_permutation(a,b,cmp). There are also std::prev_permutation(a,b) and std::prev_permutation(a,b,cmp), which count lexicographically "downward" instead of "upward."
By the way, to compare two sequences lexicographically in this way, you could use std::mismatch from section Read-only range algorithms, or you could just use the standard-provided std::lexicographical_compare(a,b,c,d).
- Microsoft Application Virtualization Cookbook
- 樂高機器人設計技巧:EV3結構設計與編程指導
- CouchDB and PHP Web Development Beginner’s Guide
- Learning DHTMLX Suite UI
- Learning JavaScript Data Structures and Algorithms
- Scala程序員面試算法寶典
- Learning Concurrent Programming in Scala
- 大數據分析與應用實戰:統計機器學習之數據導向編程
- 微服務架構深度解析:原理、實踐與進階
- 從零開始:UI圖標設計與制作(第3版)
- Akka入門與實踐
- Visual Basic語言程序設計基礎(第3版)
- 絕密原型檔案:看看專業產品經理的原型是什么樣
- Building Web and Mobile ArcGIS Server Applications with JavaScript(Second Edition)
- 威脅建模:設計和交付更安全的軟件