C++ sorting and keeping track of indexes

后端 未结 15 2010
甜味超标
甜味超标 2020-11-22 10:01

Using C++, and hopefully the standard library, I want to sort a sequence of samples in ascending order, but I also want to remember the original indexes of the new samples.<

相关标签:
15条回答
  • 2020-11-22 10:01

    Well, my solution uses residue technique. We can place the values under sorting in the upper 2 bytes and the indices of the elements - in the lower 2 bytes:

    int myints[] = {32,71,12,45,26,80,53,33};
    
    for (int i = 0; i < 8; i++)
       myints[i] = myints[i]*(1 << 16) + i;
    

    Then sort the array myints as usual:

    std::vector<int> myvector(myints, myints+8);
    sort(myvector.begin(), myvector.begin()+8, std::less<int>());
    

    After that you can access the elements' indices via residuum. The following code prints the indices of the values sorted in the ascending order:

    for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
       std::cout << ' ' << (*it)%(1 << 16);
    

    Of course, this technique works only for the relatively small values in the original array myints (i.e. those which can fit into upper 2 bytes of int). But it has additional benefit of distinguishing identical values of myints: their indices will be printed in the right order.

    0 讨论(0)
  • 2020-11-22 10:07

    There are many ways. A rather simple solution is to use a 2D vector.

    #include <algorithm>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
     vector<vector<double>> val_and_id;
     val_and_id.resize(5);
     for (int i = 0; i < 5; i++) {
       val_and_id[i].resize(2); // one to store value, the other for index.
     }
     // Store value in dimension 1, and index in the other:
     // say values are 5,4,7,1,3.
     val_and_id[0][0] = 5.0;
     val_and_id[1][0] = 4.0;
     val_and_id[2][0] = 7.0;
     val_and_id[3][0] = 1.0;
     val_and_id[4][0] = 3.0;
    
     val_and_id[0][1] = 0.0;
     val_and_id[1][1] = 1.0;
     val_and_id[2][1] = 2.0;
     val_and_id[3][1] = 3.0;
     val_and_id[4][1] = 4.0;
    
     sort(val_and_id.begin(), val_and_id.end());
     // display them:
     cout << "Index \t" << "Value \n";
     for (int i = 0; i < 5; i++) {
      cout << val_and_id[i][1] << "\t" << val_and_id[i][0] << "\n";
     }
     return 0;
    }
    

    Here is the output:

       Index   Value
       3       1
       4       3
       1       4
       0       5
       2       7
    
    0 讨论(0)
  • 2020-11-22 10:09

    Using C++ 11 lambdas:

    #include <iostream>
    #include <vector>
    #include <numeric>      // std::iota
    #include <algorithm>    // std::sort, std::stable_sort
    
    using namespace std;
    
    template <typename T>
    vector<size_t> sort_indexes(const vector<T> &v) {
    
      // initialize original index locations
      vector<size_t> idx(v.size());
      iota(idx.begin(), idx.end(), 0);
    
      // sort indexes based on comparing values in v
      // using std::stable_sort instead of std::sort
      // to avoid unnecessary index re-orderings
      // when v contains elements of equal values 
      stable_sort(idx.begin(), idx.end(),
           [&v](size_t i1, size_t i2) {return v[i1] < v[i2];});
    
      return idx;
    }
    

    Now you can use the returned index vector in iterations such as

    for (auto i: sort_indexes(v)) {
      cout << v[i] << endl;
    }
    

    You can also choose to supply your original index vector, sort function, comparator, or automatically reorder v in the sort_indexes function using an extra vector.

    0 讨论(0)
  • 2020-11-22 10:09

    I came across this question, and figured out sorting the iterators directly would be a way to sort the values and keep track of indices; There is no need to define an extra container of pairs of ( value, index ) which is helpful when the values are large objects; The iterators provides the access to both the value and the index:

    /*
     * a function object that allows to compare
     * the iterators by the value they point to
     */
    template < class RAIter, class Compare >
    class IterSortComp
    {
        public:
            IterSortComp ( Compare comp ): m_comp ( comp ) { }
            inline bool operator( ) ( const RAIter & i, const RAIter & j ) const
            {
                return m_comp ( * i, * j );
            }
        private:
            const Compare m_comp;
    };
    
    template <class INIter, class RAIter, class Compare>
    void itersort ( INIter first, INIter last, std::vector < RAIter > & idx, Compare comp )
    { 
        idx.resize ( std::distance ( first, last ) );
        for ( typename std::vector < RAIter >::iterator j = idx.begin( ); first != last; ++ j, ++ first )
            * j = first;
    
        std::sort ( idx.begin( ), idx.end( ), IterSortComp< RAIter, Compare > ( comp ) );
    }
    

    as for the usage example:

    std::vector < int > A ( n );
    
    // populate A with some random values
    std::generate ( A.begin( ), A.end( ), rand );
    
    std::vector < std::vector < int >::const_iterator > idx;
    itersort ( A.begin( ), A.end( ), idx, std::less < int > ( ) );
    

    now, for example, the 5th smallest element in the sorted vector would have value **idx[ 5 ] and its index in the original vector would be distance( A.begin( ), *idx[ 5 ] ) or simply *idx[ 5 ] - A.begin( ).

    0 讨论(0)
  • 2020-11-22 10:12

    You could sort std::pair instead of just ints - first int is original data, second int is original index. Then supply a comparator that only sorts on the first int. Example:

    Your problem instance: v = [5 7 8]
    New problem instance: v_prime = [<5,0>, <8,1>, <7,2>]
    

    Sort the new problem instance using a comparator like:

    typedef std::pair<int,int> mypair;
    bool comparator ( const mypair& l, const mypair& r)
       { return l.first < r.first; }
    // forgetting the syntax here but intent is clear enough
    

    The result of std::sort on v_prime, using that comparator, should be:

    v_prime = [<5,0>, <7,2>, <8,1>]
    

    You can peel out the indices by walking the vector, grabbing .second from each std::pair.

    0 讨论(0)
  • 2020-11-22 10:12

    For this type of question Store the orignal array data into a new data and then binary search the first element of the sorted array into the duplicated array and that indice should be stored into a vector or array.

    input array=>a
    duplicate array=>b
    vector=>c(Stores the indices(position) of the orignal array
    Syntax:
    for(i=0;i<n;i++)
    c.push_back(binarysearch(b,n,a[i]));`
    

    Here binarysearch is a function which takes the array,size of array,searching item and would return the position of the searched item

    0 讨论(0)
提交回复
热议问题