功能
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred)
是根据排序标准c
对容器comp
进行排序,但满足pred
的那些元素在排序后应保持固定在原始位置(即不受排序影响)。
我试图采用快速排序来适应这种情况,但却无法想到它。最后,我决定调整原油选择排序以完成工作:
#include <iostream>
#include <vector>
std::vector<int> numbers = {5,7,1,8,9,3,20,2,11};
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred) { // O(n^2), but want O(nlogn) on average (like quick sort or merge sort)
const std::size_t N = c.size();
std::size_t i, j, minIndex;
for (i = 0; i < N-1; i++) {
if (pred(c[i]))
continue; // c[i] shall not swap with any element.
minIndex = i;
for (j = i + 1; j < N; j++) {
if (pred(c[j]))
continue; // c[j] shall not swap with any element.
if (comp(c[j], c[minIndex]))
minIndex = j;
}
if (minIndex != i)
std::swap(c[i], c[minIndex]);
}
}
int main() {
sortButKeepSomeFixed (numbers,
std::greater<int>(), // Ordering condition.
[](int x) {return x % 2 == 0;}); // Those that shall remain fixed.
for (int x : numbers) std::cout << x << ' '; // 11 9 7 8 5 3 20 2 1
}
但时间复杂度是O(N ^ 2)(我认为)。有人可以在这里改进时间复杂度,平均可能是O(NlogN)吗?换句话说,找到一个整体更好的算法,使用递归或类似的东西?
或许更好的想法是取出满足pred
的元素,对std::sort
留下的内容进行排序,然后将提取的元素放回原来的位置?那会更有效率,还是会让情况变得更糟?
更新:
这是基于Beta的建议(对不能通过pred
的迭代器进行排序)。但是,虽然传递pred
的元素确实保持固定,但最后的排序不正确。
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred) {
std::vector<typename Container::iterator> iterators;
for (typename Container::iterator it = c.begin(); it != c.end(); ++it) {
if (!pred(*it))
iterators.emplace_back(it);
}
std::vector<typename Container::iterator> originalIterators = iterators;
std::sort(iterators.begin(), iterators.end(),
[comp](const typename Container::iterator& x, const typename Container::iterator& y)
{return comp(*x, *y);});
for (int i = 0; i < originalIterators.size(); i++)
*originalIterators[i] = *iterators[i];
}
错误输出为11 9 9 8 11 3 20 2 9
时应为11 9 7 8 5 3 20 2 1
。
答案 0 :(得分:0)
基于Beta的使用迭代器进行排序的想法,虽然我不确定时间复杂度是多少。它也不适用于所有容器,例如std :: set,std :: map。
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred) {
std::vector<typename Container::value_type> toSort;
std::vector<typename Container::iterator> iterators;
for (typename Container::iterator it = c.begin(); it != c.end(); ++it) {
if (!pred(*it)) {
toSort.emplace_back(*it);
iterators.emplace_back(it);
}
}
std::sort(toSort.begin(), toSort.end(), comp);
for (std::size_t i = 0; i < toSort.size(); i++)
*iterators[i] = toSort[i];
}
std::vector<int> vector = {5,7,1,8,9,3,20,2,11};
std::array<int, 9> array = {5,7,1,8,9,3,20,2,11};
std::list<int> list = {5,7,1,8,9,3,20,2,11};
std::set<int> set = {5,7,1,8,9,3,20,2,11};
std::map<double, int> map = { {1.5,5}, {1.2,7}, {3.5,1}, {0.5,8}, {5.2,9}, {7.5,3}, {0.1,20}, {1.8,2}, {2.4,11} };
template <typename Container>
void test (Container& container) {
sortButKeepSomeFixed (container,
std::greater<int>(), // Ordering condition.
[](int x) {return x % 2 == 0;}); // Those that shall remain fixed.
for (int x : container) std::cout << x << ' ';
std::cout << '\n';
}
int main() {
test(vector); // 11 9 7 8 5 3 20 2 1
test(array); // 11 9 7 8 5 3 20 2 1
test(list); // 11 9 7 8 5 3 20 2 1
test(set); // Does not compile.
sortButKeepSomeFixed (map,
[](const std::pair<double, int>& x, const std::pair<double, int>& y) {return x.second > y.second;},
[](const std::pair<double, int>& x) {return x.second % 2 == 0;});
for (const std::pair<double, int>& x : map)
std::cout << "(" << x.first << "," << x.second << ") "; // Does not compile.
}
设置和映射的错误是&#34;分配只读位置&#34;。 任何人都知道如何概括它以使用集合和地图?
更新:所以我建议使用set,maps等...,只需删除那些满足pred
的元素,并创建一个新的set / map / ...并将Compare
作为key_compare类型。如下。但这只是为了设定。如何将其推广到具有key_compare类型的其他容器?
template <typename Container, typename Comparator, typename Predicate>
std::set<typename Container::value_type, Comparator, typename Container::allocator_type>
sortButRemoveSomeElements (Container& c, const Comparator&, const Predicate& pred) {
std::set<typename Container::value_type, Comparator, typename Container::allocator_type> set;
std::vector<typename Container::value_type> keep;
for (typename Container::iterator it = c.begin(); it != c.end(); ++it) {
if (!pred(*it))
keep.emplace_back(*it);
}
for (typename Container::value_type x : keep)
set.emplace(x); // Sorted by Comparator automatically due to std::set's insertion property.
return set;
}
测试:
struct GreaterThan { bool operator()(int x, int y) const {return x > y;} };
std::set<int, GreaterThan> newSet = sortButRemoveSomeElements (set,
GreaterThan{}, // Ordering condition.
[](int x) {return x % 2 == 0;}); // Those that shall be removed.
for (int x : newSet) std::cout << x << ' '; // 11 9 7 5 3 1