当我试图写出一个新算法来重新排序std :: vector中的元素时,我遇到了这个问题。基本的想法是我有std :: list指向std :: vector的列表,其方式是*list.begin() == vector[0]
,*(++list.begin()) == vector[1]
等等。
但是,对列表元素位置的任何修改都会破坏映射。 (包括附加指针)当映射被破坏时,列表的元素可以是随机顺序,但它们仍指向向量上的正确元素。任务是重新排序向量中的元素以纠正映射。
最简单的方法(我现在怎么做):
遗憾的是,只有当我需要更多的矢量容量时,该方法才有用。当保持元素的当前向量具有足够的容量来存储所有传入元素时,效率很低。列表中的附加指针将指向不同的向量的storgate。简单的方法适用于此,因为它只从指针读取。
所以我想使用恒定的内存量来重新排序矢量“就地”。任何未指向当前向量的storgate的指针都会移动到指向当前向量的storgate。元素是简单的结构。 (POD中) 我有空的时候会尝试发布示例代码..
我该怎么做才能做到这一点?我已经完成了基本的想法,但我不确定是否有可能以恒定的内存量进行重新排序。
答案 0 :(得分:2)
首先,为什么你有一个指针列表?您也可以将索引保存到矢量中,您可以将其计算为std::distance(&v[0], *list_iter)
。所以,让我们首先建立一个索引向量,但你可以很容易地适应它直接使用你的列表:
std::vector<T> v; // your data
std::list<T*> perm_list; // your given permutation list
std::vector<size_t> perms;
perms.reserve(v.size());
for (std::list<T*>::const_iterator it = perm_list.begin(), end = perm_list.end(); it != end; ++it)
{
perms.push_back(std::distance(&v[0], *it));
}
(可能有一种方法可以使用std::transform
和std::bind
或lambdas在一行中执行此操作。)
现在要做的工作。我们只是使用置换的循环分解,并在我们进行时修改perms
向量:
std::set<size_t> done;
for (size_t i = 0; i < perms.size(); while(done.count(++i)) {})
{
T tmp1 = v[i];
for (size_t j = perms[i]; j != i; j = perms[j])
{
T tmp2 = v[j];
v[j] = tmp1;
tmp1 = tmp2;
done.insert(j);
}
v[i] = tmp1;
}
我正在使用辅助集done
来跟踪哪些索引已被置换。在C ++ 0x中,您可以在任何地方添加std::move
以使其与可移动容器一起使用。