Sort and keep track of elements

♀尐吖头ヾ 提交于 2020-01-04 02:55:13

问题


Just to know, I'm talking C++ now.

Suppose I have an array A = {4, 1, 5, 2, 3} and sort it in A_sorted = {1, 2, 3, 4, 5}. I would like to keep the following information: where is now element e (from array A) in the sorted array A_sorted? e.g.: element with index 2 in A (5) has now index 4 in A_sorted.

The question is more like: can one use STL to achieve this?


回答1:


There's no off-the-shelf functionality to achieve this, but there are work-arounds. You can, for example, keep an array of user-defined structs that also contain the original position:

A = { {4,0}, {1,1}, {5,2}, {2,3}, {3,4}}

And then sort this using a custom comparator function that sorts by the value and not the original index.

A_sorted = {{1,1}, {2,3}, {3,4}, {4,0}, {5,2}}



回答2:


Try this out: If you want to convert to vector:

 int A[] = {4, 1, 5, 2, 3};
 int A_sorted [] = {1, 2, 3, 4, 5};
 std::vector<int> v(A_sorted, A_sorted + 5);  

  for (int i=0; i<5; i++)
  {          
    std::vector<int>::iterator low = lower_bound (v.begin(), v.end(), A[i]);   
    std::cout << "Element: " << A[i] << " is at: " << distance(v.begin(), low)  << std::endl;
  }

If you want to work on raw array:

 int A[] = {4, 1, 5, 2, 3};
 int A_sorted [] = {1, 2, 3, 4, 5};

  for (int i=0; i<5; i++)
  {      
    int* low = std::lower_bound (&A_sorted[0], &A_sorted[5], A[i]);   
    cout << "Element: " << A[i] << " is at: " << distance(&A_sorted[0], low)  << endl;
  }



回答3:


If you cannot modify what's stored in A, you could create an index array and sort it with a special predicate:

int A[] = {4, 1, 5, 2, 3};

size_t indices[] = {0, 1, 2, 3, 4};

bool sortBefore(size_t i, size_t j) {
  return A[i] < A[j];
}

std::sort(indices, indices + 5, sortBefore);

Then, either access sorted_A[i] as A[indices[i]], or re-arrange A according to indices. New position of i-th element of A is std::find(indices, indices+5, i) - indices.




回答4:


template<class T>
struct ValueWithIndex
{
    T Value;
    int index;
};
template<class T>
bool operator < (const ValueWithIndex<T>& v1, const ValueWithIndex<T>& v2)
{
    return v1.value < v2.value;
}
template<class T> ValueWithIndex<T>
MakeValueWithIndex(const T& value, int index)
{
    ValueWithIndex<T> ret;
    ret.value = value;
    ret.index = index;
    return ret; 
}

Now sort your container of ValueWithIndex. The information about original indexes will not be lost.

int main()
{
    std::vector<ValueWithIndex<int>> v;
    for(int i = 0; i < n; ++i)
    {
       int value; 
       std::cin >> value;
       v.push_back(MakeValueWithIndex(value, i)); 
    } 

    std::sort(v.begin(), v.end());
}



回答5:


Ok, an index normally tells you what the nth sorted element of a vector is. But this is going to do the reverse, thus it will tell you that the nth element in your vector is the mth in sorted order.

This is being done by creating a vector of indices on your non-sorted vector. You can still create a sorted copy or an index, of course.

We start off with a predicate for which a < b if v[a] < v[b]

template< typename T >
class PredByIndex
{
private:
     std::vector< T > const & theColl;
public:
     PredByIndex( std::vector<T> const& coll ) : theColl( coll )
     {
     }

     bool operator()( size_t i, size_t j ) const
     {
        return theColl[i] < theColl[j];
     }
};

template< typename T >
void makeOrdered( std::vector< T > const& input, std::vector< size_t > & order )
{
    order.clear();
    size_t len = input.size();
    order.reserve( len );
    for( size_t i = 0; i < len; ++i )
    {
        order.push_back( i );
    }
    PredByIndex<T> pred( input );
    std::sort( order.begin(), order.end(), pred );
}

And now "order" will have the ordinal position in the ordered collection.

Of course in C++11 the predicate could be written as a lambda expression rather than having to create the class PredByIndex.

We are not done yet though. We now have an index, not a "find me in the sorted vector". However we can transpose our index as follows:

void transpose_index( std::vector< size_t > const & index, 
                       std::vector< size_t > & trans )
{
   // for this to work, index must contain each value from 0 to N-1 exactly once.
   size_t size = index.size();
   trans.resize( index.size() );
   for( size_t i = 0; i < size; ++i )
   {
       assert( index[i] < size );
       // for further assert, you could initialize all values of trans to size
       // then as we go along, ensure they still hold that value before
       // assigning
       trans[ index[i] ] = i;
   }

}

Now our transposed index gives you what you want, and the transpose itself is O(N)

In a slightly different example of data, if the inputs are [ 5, 3, 11, 7, 2 ]

The "sorted" order is [ 2, 3, 5, 7, 11 ]

The "index" order is [4, 1, 0, 3, 2] i.e. element 4 is the smallest, then element 1 etc.

The "transpose" order, as we fill it in

 [ _, _, _, _, _ ]
 [ _, _, _, _, 0 ]
 [ _, 1, _, _, 0 ]
 [ 2, 1, _, _, 0 ]
 [ 2, 1, _, 3, 0 ]
 [ 2, 1, 4, 3, 0 ]

This looks like what we want. Our original data 5 is position 2, 3 is position 1, 11 is position 4 etc in the sorted data.




回答6:


You can use find to search for the element:

int *p1 = std::find(&A[0], &A[5], 5);
int *p2 = std::find(&A_sorted[0], &A_sorted[5], 5);

and use the distance to show the index:

int i1 = p1 - A;
int i2 = p2 - A_sorted;

i1 and i2 now show the index in the corresponding array.



来源:https://stackoverflow.com/questions/13248149/sort-and-keep-track-of-elements

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!