C++ 使用索引向量对向量重新排序
我想使用另一个向量来指定顺序,对向量中的项目重新排序:C++ 使用索引向量对向量重新排序,c++,algorithm,vector,stl,C++,Algorithm,Vector,Stl,我想使用另一个向量来指定顺序,对向量中的项目重新排序: char A[] = { 'a', 'b', 'c' }; size_t ORDER[] = { 1, 0, 2 }; vector<char> vA(A, A + sizeof(A) / sizeof(*A)); vector<size_t> vOrder(ORDER, ORDER + sizeof(ORDER) / sizeof(*ORDER)); reorder_naive(vA, vOrder); //
char A[] = { 'a', 'b', 'c' };
size_t ORDER[] = { 1, 0, 2 };
vector<char> vA(A, A + sizeof(A) / sizeof(*A));
vector<size_t> vOrder(ORDER, ORDER + sizeof(ORDER) / sizeof(*ORDER));
reorder_naive(vA, vOrder);
// A is now { 'b', 'a', 'c' }
chara[]={'A','b','c'};
大小顺序[]={1,0,2};
向量vA(A,A+sizeof(A)/sizeof(*A));
向量涡(阶数,阶数+sizeof(阶数)/sizeof(*阶数));
重新排序(vA,vOrder);
//A现在是{'b','A','c'}
以下是需要复制向量的低效实现:
void reorder_naive(vector<char>& vA, const vector<size_t>& vOrder)
{
assert(vA.size() == vOrder.size());
vector vCopy = vA; // Can we avoid this?
for(int i = 0; i < vOrder.size(); ++i)
vA[i] = vCopy[ vOrder[i] ];
}
void-reorder\u-naive(向量&vA,常量向量&vOrder)
{
断言(vA.size()==vOrder.size());
向量vCopy=vA;//我们能避免这种情况吗?
对于(int i=0;i
有没有一种更有效的方法,例如,使用swap()?我想,您可以递归地执行此操作-类似这样的操作(未选中,但它给出了想法):
//递归函数
模板
无效重新排序(int-oldPosition、vector和vA、,
常量向量和向量(新订单、向量和向量)
{
//记录当前处于该位置的值,
//以及我们要转移到的位置。
//但先别动它,否则我们会覆盖下一个
//位置。相反,我们首先移动下一个位置的内容。
//为了防止循环,我们查看vecVisited,并将其设置为true
//一旦我们参观了一个职位。
T oldVal=vA[oldPosition];
int newPos=vecNewOrder[oldPosition];
如果(已访问[oldPosition])
{
//我们遇到了一个循环。设置它并返回。
vA[新位置]=旧值;
返回;
}
//防止循环:
vecVisited[oldPosition]=真;
//递归地重新排序序列中的下一项。
重新订购(newPos、vA、vecNewOrder、vecVisited);
//在我们设定了这个新值之后,
vA[新位置]=旧值;
}
//“主要”功能
模板
无效重新排序(向量和vA、常量向量和新订单)
{
//用假值初始化向量
向量向量向量(vA.size(),false);
对于(int x=0;x
当然,你确实有额外的开销。有人对这种方法有什么想法吗?您的代码被破坏了。您不能分配给
vA
,您需要使用模板参数
vector<char> REORDER(const vector<char>& vA, const vector<size_t>& vOrder)
{
assert(vA.size() == vOrder.size());
vector<char> vCopy(vA.size());
for(int i = 0; i < vOrder.size(); ++i)
vCopy[i] = vA[ vOrder[i] ];
return vA;
}
向量重新排序(常量向量和vA、常量向量和vOrder)
{
断言(vA.size()==vOrder.size());
向量vCopy(vA.size());
对于(int i=0;i
上面的方法效率略高。如果可以修改顺序数组,那么对顺序向量进行排序并在每次排序操作中交换相应的值向量元素的实现就可以做到这一点,我认为。迭代向量就是O(n)操作。这很难克服。这应该避免复制向量:
void REORDER(vector<char>& vA, const vector<size_t>& vOrder)
{
assert(vA.size() == vOrder.size());
for(int i = 0; i < vOrder.size(); ++i)
if (i < vOrder[i])
swap(vA[i], vA[vOrder[i]]);
}
void重新排序(向量&vA,常量向量&vOrder)
{
断言(vA.size()==vOrder.size());
对于(int i=0;i
永远不要过早优化。测量并确定需要优化的位置和内容。在许多性能不成问题的地方,您可能会以难以维护且容易出现错误的复杂代码结束
话虽如此,不要过早悲观。在不更改代码的情况下,您可以删除一半副本:
template <typename T>
void reorder( std::vector<T> & data, std::vector<std::size_t> const & order )
{
std::vector<T> tmp; // create an empty vector
tmp.reserve( data.size() ); // ensure memory and avoid moves in the vector
for ( std::size_t i = 0; i < order.size(); ++i ) {
tmp.push_back( data[order[i]] );
}
data.swap( tmp ); // swap vector contents
}
模板
无效重新排序(标准::向量和数据,标准::向量常量和顺序)
{
std::vector tmp;//创建一个空向量
tmp.reserve(data.size());//确保内存并避免向量中的移动
对于(std::size_t i=0;i
这段代码创建并清空(足够大)向量,在该向量中按顺序执行单个副本。最后,交换有序向量和原始向量。这将减少拷贝数,但仍需要额外的内存
如果您想在适当的位置执行移动,一个简单的算法可以是:
template <typename T>
void reorder( std::vector<T> & data, std::vector<std::size_t> const & order )
{
for ( std::size_t i = 0; i < order.size(); ++i ) {
std::size_t original = order[i];
while ( i < original ) {
original = order[original];
}
std::swap( data[i], data[original] );
}
}
模板
无效重新排序(标准::向量和数据,标准::向量常量和顺序)
{
对于(std::size_t i=0;i
应检查并调试此代码。简单地说,每个步骤中的算法将元素定位在第i个位置。首先,我们确定该位置的原始元素现在在数据向量中的位置。如果算法已经触及原始位置(在第i个位置之前),则原始元素被交换到顺序[原始]位置。再说一次,那个元素可能已经被移动了
该算法的整数运算数大约为O(N^2),因此与初始O(N)算法相比,理论上性能时间较差。但是,如果N^2交换操作(最坏情况)的成本低于N复制操作,或者您确实受到内存占用的限制,则它可以进行补偿。向量的就地重新排序
警告:排序索引的语义含义不明确。这两个问题在这里都有答案
将向量元素移动到索引的位置
交互式版本
请注意,您可以保存一个测试,因为如果n-1个元素已就位,则最后第n个元素肯定已就位
出口vA和vOrder已正确订购
该算法最多执行n-1次交换,因为每次交换都会将元素移动到其最终位置。我们必须在vOrder上做最多2N个测试
从索引位置绘制向量元素
以交互方式尝试
这个算法是b
template <typename T>
void reorder( std::vector<T> & data, std::vector<std::size_t> const & order )
{
for ( std::size_t i = 0; i < order.size(); ++i ) {
std::size_t original = order[i];
while ( i < original ) {
original = order[original];
}
std::swap( data[i], data[original] );
}
}
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
void REORDER(vector<double>& vA, vector<size_t>& vOrder)
{
assert(vA.size() == vOrder.size());
// for all elements to put in place
for( int i = 0; i < vA.size() - 1; ++i )
{
// while the element i is not yet in place
while( i != vOrder[i] )
{
// swap it with the element at its final place
int alt = vOrder[i];
swap( vA[i], vA[alt] );
swap( vOrder[i], vOrder[alt] );
}
}
}
int main()
{
std::vector<double> vec {7, 5, 9, 6};
std::vector<size_t> inds {1, 3, 0, 2};
REORDER(vec, inds);
for (size_t vv = 0; vv < vec.size(); ++vv)
{
std::cout << vec[vv] << std::endl;
}
return 0;
}
9
7
6
5
#include <iostream>
#include <vector>
#include <assert.h>
template<typename T>
void reorder(std::vector<T>& vec, std::vector<size_t> vOrder)
{
assert(vec.size() == vOrder.size());
for( size_t vv = 0; vv < vec.size() - 1; ++vv )
{
if (vOrder[vv] == vv)
{
continue;
}
size_t oo;
for(oo = vv + 1; oo < vOrder.size(); ++oo)
{
if (vOrder[oo] == vv)
{
break;
}
}
std::swap( vec[vv], vec[vOrder[vv]] );
std::swap( vOrder[vv], vOrder[oo] );
}
}
int main()
{
std::vector<double> vec {7, 5, 9, 6};
std::vector<size_t> inds {1, 3, 0, 2};
reorder(vec, inds);
for (size_t vv = 0; vv < vec.size(); ++vv)
{
std::cout << vec[vv] << std::endl;
}
return 0;
}
5
6
7
9
template< class T >
void reorder(vector<T> &v, vector<size_t> const &order ) {
for ( int s = 1, d; s < order.size(); ++ s ) {
for ( d = order[s]; d < s; d = order[d] ) ;
if ( d == s ) while ( d = order[d], d != s ) swap( v[s], v[d] );
}
}
template< typename order_iterator, typename value_iterator >
void reorder( order_iterator order_begin, order_iterator order_end, value_iterator v ) {
typedef typename std::iterator_traits< value_iterator >::value_type value_t;
typedef typename std::iterator_traits< order_iterator >::value_type index_t;
typedef typename std::iterator_traits< order_iterator >::difference_type diff_t;
diff_t remaining = order_end - 1 - order_begin;
for ( index_t s = index_t(), d; remaining > 0; ++ s ) {
for ( d = order_begin[s]; d > s; d = order_begin[d] ) ;
if ( d == s ) {
-- remaining;
value_t temp = v[s];
while ( d = order_begin[d], d != s ) {
swap( temp, v[d] );
-- remaining;
}
v[s] = temp;
}
}
}
template< typename order_iterator, typename value_iterator >
void reorder_destructive( order_iterator order_begin, order_iterator order_end, value_iterator v ) {
typedef typename std::iterator_traits< value_iterator >::value_type value_t;
typedef typename std::iterator_traits< order_iterator >::value_type index_t;
typedef typename std::iterator_traits< order_iterator >::difference_type diff_t;
diff_t remaining = order_end - 1 - order_begin;
for ( index_t s = index_t(); remaining > 0; ++ s ) {
index_t d = order_begin[s];
if ( d == (diff_t) -1 ) continue;
-- remaining;
value_t temp = v[s];
for ( index_t d2; d != s; d = d2 ) {
swap( temp, v[d] );
swap( order_begin[d], d2 = (diff_t) -1 );
-- remaining;
}
v[s] = temp;
}
}
template <typename T>
void reorder( std::vector<T> & data, std::vector<std::size_t> & order )
{
std::size_t i,j,k;
for(i = 0; i < order.size() - 1; ++i) {
j = order[i];
if(j != i) {
for(k = i + 1; order[k] != i; ++k);
std::swap(order[i],order[k]);
std::swap(data[i],data[j]);
}
}
}
template <typename T>
void reorder( std::vector<T> & data, std::vector<std::size_t> const & order )
{
std::vector<T> tmp; // create an empty vector
tmp.reserve( data.size() ); // ensure memory and avoid moves in the vector
for ( std::size_t i = 0; i < order.size(); ++i ) {
tmp.push_back( data[order[i]] );
}
data.swap( tmp ); // swap vector contents
}
template <class T>
void reorder(vector<T>& vA, vector<size_t>& vOrder)
{
assert(vA.size() == vOrder.size());
// for all elements to put in place
for( size_t i = 0; i < vA.size(); ++i )
{
// while vOrder[i] is not yet in place
// every swap places at least one element in it's proper place
while( vOrder[i] != vOrder[vOrder[i]] )
{
swap( vA[vOrder[i]], vA[vOrder[vOrder[i]]] );
swap( vOrder[i], vOrder[vOrder[i]] );
}
}
}
void reorder(int *A, int *I, int n)
{
int i, j, k;
int tA;
/* reorder A according to I */
/* every move puts an element into place */
/* time complexity is O(n) */
for(i = 0; i < n; i++){
if(i != I[i]){
tA = A[i];
j = i;
while(i != (k = I[j])){
A[j] = A[k];
I[j] = j;
j = k;
}
A[j] = tA;
I[j] = j;
}
}
}
vector<int> new_inds(arma_inds.size());
for (int i = 0; i < new_inds.size(); i++) new_inds[arma_inds[i]] = i;
void permute(vector<T>& values, const vector<size_t>& indices)
{
vector<T> out;
out.reserve(indices.size());
for(size_t index: indices)
{
assert(0 <= index && index < values.size());
out.push_back(std::move(values[index]));
}
values = std::move(out);
}
std::vector<int32_t> dense_vec = {1, 2, 3};
std::vector<int32_t> order = {1, 0, 2};
int32_t max_val = *std::max_element(dense_vec.begin(), dense_vec.end());
std::vector<int32_t> sparse_vec(max_val + 1);
int32_t i = 0;
for(int32_t j: dense_vec)
{
sparse_vec[j] = order[i];
i++;
}
std::sort(dense_vec.begin(), dense_vec.end(),
[&sparse_vec](int32_t i1, int32_t i2) {return sparse_vec[i1] < sparse_vec[i2];});