【发布时间】:2015-11-08 08:13:26
【问题描述】:
功能
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred)
是根据排序标准comp对容器c进行排序,但满足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。
【问题讨论】:
-
你的“更好的主意”会很好用,O(N logN)。
-
O(N logN) for
std::sort本身,但是删除元素然后将它们放回原来的位置所花费的时间增加了很多,不是吗? -
如果您使用
vector之类的东西,但不自己处理插入/删除元素,插入/删除的复杂性已摊销到O(N),所以没关系。 -
其实没有,抱歉。如果你想在原地做,你需要复制一些东西,例如如果您不创建原始数组的副本。如果您逐个进行删除,则每次插入/删除将为
O(N),因此总复杂度为 O(N^2)。我建议你为那些没有通过谓词的人创建一个新数组,如果运行性能是你的首要任务,内存复杂度是O(N)而不是O(1)。 -
有时应该问“为什么?”
标签: c++ sorting templates lambda