如何解决如何有效地在原位置换数组使用std :: swap 编辑
如何就地应用排列?我的排列有效地是size_t[]
,其中perm[i]
代表输入索引i
的目标索引。
如果我有输入和输出数组,我知道如何应用排列:
struct Permutation {
std::vector<size_t> perm;
template <typename T>
void apply(const T in[],T out[]) const
{
for (size_t i = 0; i < size(); ++i) {
out[i] = std::move(in[perm[i]]);
}
}
}
但是,我只想用一个数组来完成此操作,类似于std::sort
的工作原理,所以只使用std::swap
。到目前为止,我的想法是:
struct Permutation {
std::vector<size_t> perm;
template <typename T>
void apply(T data[]) const
{
for (size_t i = 0; i < size(); ++i) {
std::swap(data[i],data[perm[i]]);
}
}
}
但这是行不通的。例如:
Permutation perm = {2,1,0};
char data[] {'a','b','c'};
perm.apply(data);
// because I swap indices 0 and 2 twice,I end up with the input array
data == {'a','c'};
那么我该如何正确置换阵列?只要分配额外的内存就可以,只要在构造Permutation
的预计算步骤中发生这种情况即可。我希望就地置换能够快速发生,并且从外观上来说,要求完全不分配 no 额外的内存会导致一些性能上的牺牲。
我具体指的是Algorithm to apply permutation in constant memory space,其中提供的所有全部要么通过使用负整数空间来作弊,以避免分配,要么输入“讨厌的”嵌套循环来浪费时间O(n²)的复杂度。
编辑
在建议std::next_permutation
之前,请注意。我并没有尝试生成所有可能的排列,而我可以使用std::next_permutation
来进行排列。相反,我试图将单个特定排列应用于数组。
解决方法
找到周期并置换每个周期的提示对我有用。总结一下我的方法,我在构造函数中找到了所有循环的开始索引。
然后,在apply()
中,我通过重复使用std::swap
来置换每个循环。
struct Permutation {
private:
/// The single vector which stores both the permutation
/// AND the indices of the cycles starts.
std::vector<size_t> perm;
/// The size of the permutation / index of first cycle index.
size_t permSize;
public:
Permutation(std::vector<size_t> table)
: perm{std::move(table)},permSize{perm.size()} {
findCycles();
}
template <typename T>
void apply(T data[]) const {
for (size_t cycle = permSize; cycle < perm.size(); ++cycle) {
const size_t start = perm[cycle];
for (size_t prev = start,next = perm[prev];
next != start;
prev = next,next = perm[next]) {
std::swap(data[prev],data[next]);
}
}
}
size_t size() const {
return permSize;
}
private:
void findCycles();
}
findCycles()
也很容易实现,但是需要临时分配位向量。
void Permutation::findCycles() {
std::vector<bool> visited(size());
for (size_t i = 0; i < size(); ++i) {
if (visited[i]) {
continue;
}
for (size_t j = i; not visited[j]; ) {
visited[j] = true;
j = perm[j];
}
perm.push_back(i);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。