C ++ अनुक्रमित और अनुक्रमित का ट्रैक रखने


216

C ++ का उपयोग करना, और उम्मीद है कि मानक पुस्तकालय, मैं नमूने के अनुक्रम को आरोही क्रम में क्रमबद्ध करना चाहता हूं, लेकिन मैं नए नमूनों के मूल अनुक्रमों को भी याद रखना चाहता हूं।

उदाहरण के लिए, मेरे पास एक सेट, या वेक्टर, या नमूनों का मैट्रिक्स है A : [5, 2, 1, 4, 3]। मैं इन्हें छांटना चाहता हूं B : [1,2,3,4,5], लेकिन मैं मूल्यों के मूल अनुक्रमों को भी याद रखना चाहता हूं, इसलिए मुझे एक और सेट मिल सकता है, जो होगा: C : [2, 1, 4, 3, 0 ]- जो मूल में 'बी' में प्रत्येक तत्व के सूचकांक से मेल खाता है। ए'।

उदाहरण के लिए, मतलाब में आप यह कर सकते हैं:

 [a,b]=sort([5, 8, 7])
 a = 5 7 8
 b = 1 3 2

क्या कोई ऐसा करने का अच्छा तरीका देख सकता है?

जवाबों:


298

C++11 लंबोदर का उपयोग करना :

#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;
}

अब आप इसमें दिए गए इंडेक्स वेक्टर को पुनरावृत्तियों में उपयोग कर सकते हैं जैसे कि

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

आप एक अतिरिक्त वेक्टर का उपयोग करके अपने मूल सूचकांक वेक्टर, सॉर्ट फ़ंक्शन, तुलनित्र, या सॉर्ट v_indexes फ़ंक्शन में स्वचालित रूप से पुनः आपूर्ति करने का विकल्प चुन सकते हैं।


4
इस उत्तर से प्यार करें। यदि आपका कंपाइलर लैम्ब्डा का समर्थन नहीं करता है, तो आप एक वर्ग का उपयोग कर सकते हैं: टेम्पलेट <टाइपनेम टी> क्लास तुलनाइंडिसबीऑनोथेवियरवील्यूस {std :: वेक्टर <T> * _values; सार्वजनिक: CompareIndicesByAnotherVectorValues (std :: वेक्टर <टी> * मान): _values (मान) {} सार्वजनिक: bool ऑपरेटर () (स्थिरांक पूर्णांक और एक, स्थिरांक पूर्णांक और ख) स्थिरांक {वापसी ( _values) [एक]> ( _values) [ ख]; }};
योआव

2
मुझे यह उत्तर बहुत पसंद है, जोड़े के वेक्टर बनाने के लिए मूल वेक्टर को कॉपी करने की कोई आवश्यकता नहीं है।
हेडमशोल्डर

29
के बजाय हाथ से तैयार for (size_t i = 0; i != idx.size(); ++i) idx[i] = i;मैं मानक पसंद करते हैंstd::iota( idx.begin(), idx.end(), 0 );
Wyck

6
उपयोग #include <numeric>जरा के लिए ()
kartikag01

6
iotaपूरे C ++ मानक पुस्तकालय में कम से कम स्पष्ट रूप से नामित एल्गोरिथ्म है।
सेठ जॉनसन

87

आप केवल ints के बजाय std :: pair को सॉर्ट कर सकते हैं - पहला इंट मूल डेटा है, दूसरा इंट मूल इंडेक्स है। फिर एक तुलनित्र की आपूर्ति करें जो केवल पहले इंट पर सॉर्ट करता है। उदाहरण:

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

एक तुलनित्र का उपयोग करके नई समस्या उदाहरण को सॉर्ट करें:

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

Std का परिणाम :: v_prime पर क्रमबद्ध, उस तुलनित्र का उपयोग करना चाहिए:

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

आप वेक्टर पर चलते हुए सूचकांकों को छील सकते हैं, प्रत्येक एसटीडी जोड़ी से .second को पकड़ सकते हैं।


1
यह ठीक है कि मैं इसे कैसे करूंगा। मूल प्रकार फ़ंक्शन पुराने बनाम नए पदों को ट्रैक नहीं करता है क्योंकि यह अतिरिक्त अनावश्यक ओवरहेड जोड़ देगा।
the_mandrill

8
इस फ़ंक्शन के साथ दोष यह है कि इसके लिए आपको सभी मूल्यों के लिए मेमोरी को पुनः लोड करना होगा।
योव

1
यह स्पष्ट रूप से एक व्यावहारिक दृष्टिकोण है, लेकिन इसका नकारात्मक पक्ष यह है कि आपको अपने मूल कंटेनर को "कंटेनर के नंबर" से "जोड़े के कंटेनर" में बदलना होगा।
रुस्लान

18

मान लीजिए कि वेक्टर है

A=[2,4,3]

एक नया वेक्टर बनाएं

V=[0,1,2] // indicating positions

V को क्रमबद्ध करें और V के तत्वों की तुलना करने के बजाय छँटाई करें, A के संगत तत्वों की तुलना करें

 //Assume A is a given vector with N elements
 vector<int> V(N);
 int x=0;
 std::iota(V.begin(),V.end(),x++); //Initializing
 sort( V.begin(),V.end(), [&](int i,int j){return A[i]<A[j];} );

अपने उत्तर से प्यार करो। तुम भीstd::iota()map
निम्रोद मोराग

हाँ हम इसका उपयोग कर सकते हैं! सुझाव के लिए धन्यवाद
रहस्यवादी

12

मैंने इंडेक्स सॉर्ट का सामान्य संस्करण लिखा।

template <class RAIter, class Compare>
void argsort(RAIter iterBegin, RAIter iterEnd, Compare comp, 
    std::vector<size_t>& indexes) {

    std::vector< std::pair<size_t,RAIter> > pv ;
    pv.reserve(iterEnd - iterBegin) ;

    RAIter iter ;
    size_t k ;
    for (iter = iterBegin, k = 0 ; iter != iterEnd ; iter++, k++) {
        pv.push_back( std::pair<int,RAIter>(k,iter) ) ;
    }

    std::sort(pv.begin(), pv.end(), 
        [&comp](const std::pair<size_t,RAIter>& a, const std::pair<size_t,RAIter>& b) -> bool 
        { return comp(*a.second, *b.second) ; }) ;

    indexes.resize(pv.size()) ;
    std::transform(pv.begin(), pv.end(), indexes.begin(), 
        [](const std::pair<size_t,RAIter>& a) -> size_t { return a.first ; }) ;
}

उपयोग std के समान है :: सॉर्ट किए गए इंडेक्स प्राप्त करने के लिए इंडेक्स कंटेनर को छोड़कर। परिक्षण:

int a[] = { 3, 1, 0, 4 } ;
std::vector<size_t> indexes ;
argsort(a, a + sizeof(a) / sizeof(a[0]), std::less<int>(), indexes) ;
for (size_t i : indexes) printf("%d\n", int(i)) ;

आपको सी ++ 0x समर्थन के बिना संकलक के लिए 2 1 0 3. मिलना चाहिए, लांबा अभिव्यक्ति को वर्ग टेम्पलेट के रूप में बदलें:

template <class RAIter, class Compare> 
class PairComp {
public:
  Compare comp ;
  PairComp(Compare comp_) : comp(comp_) {}
  bool operator() (const std::pair<size_t,RAIter>& a, 
    const std::pair<size_t,RAIter>& b) const { return comp(*a.second, *b.second) ; }        
} ;

और फिर से लिखें :: जैसा क्रम

std::sort(pv.begin(), pv.end(), PairComp(comp)()) ;

हाय हिक्की! हम इस टेम्प्लेट फ़ंक्शन को कैसे त्वरित करते हैं? इसके दो टेम्पलेट टाइपनेम हैं और उनमें से एक इट्रेटर है जो इस स्थिति को बहुत कम कर देता है। क्या आप सहायता कर सकते हैं?
स्कॉट यांग

12
vector<pair<int,int> >a;

for (i = 0 ;i < n ; i++) {
    // filling the original array
    cin >> k;
    a.push_back (make_pair (k,i)); // k = value, i = original index
}

sort (a.begin(),a.end());

for (i = 0 ; i < n ; i++){
    cout << a[i].first << " " << a[i].second << "\n";
}

अब aहमारे दोनों मान और उनके संबंधित सूचकांकों को हल में शामिल किया गया है।

a[i].first = valueपर i'वें।

a[i].second = idx प्रारंभिक सरणी में।


अपने कोड के विवरण को जोड़ने पर विचार करें ताकि इस पोस्ट पर जाने वाले उपयोगकर्ता समझ सकें कि यह कैसे काम करता है।
बिजीप्रोग्राम

मुझे वास्तव में यह समाधान सबसे अच्छा लगता है - मेरा वेक्टर आकार 4 या तो का है और मैं C ++ 11 से पहले फंस गया हूं और लंबोदा का उपयोग नहीं कर सकता। धन्यवाद आदित्य असवाल
Stephanmg

6

मैं इस सवाल पर आया था, और लगा कि पुनरावृत्तियों को सीधे मानों को छांटने और सूचकांकों पर नज़र रखने का एक तरीका होगा; pairमान (इंडेक्स) के अतिरिक्त कंटेनर को परिभाषित करने की कोई आवश्यकता नहीं है , जो कि बड़ी वस्तुओं के मान जाने पर सहायक होता है; पुनरावृत्तियों मूल्य और सूचकांक दोनों के लिए पहुँच प्रदान करता है:

/*
 * 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 ) );
}

उपयोग उदाहरण के लिए:

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 > ( ) );

अब, उदाहरण के लिए, क्रमबद्ध वेक्टर में 5 वें सबसे छोटे तत्व का मूल्य होगा **idx[ 5 ]और मूल वेक्टर में इसका सूचकांक distance( A.begin( ), *idx[ 5 ] )या बस होगा *idx[ 5 ] - A.begin( )


3

मानचित्र का उपयोग करके इसे हल करने का एक और तरीका है:

vector<double> v = {...}; // input data
map<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
    m[*it] = it - v.begin();

हालांकि यह गैर-अद्वितीय तत्वों को मिटा देगा। यदि यह स्वीकार्य नहीं है, तो एक मल्टीमैप का उपयोग करें:

vector<double> v = {...}; // input data
multimap<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
    m.insert(make_pair(*it, it - v.begin()));

सूचकांकों के उत्पादन के लिए, नक्शे या मल्टीमैप पर पुनरावृति:

for (auto it = m.begin(); it != m.end(); ++it)
    cout << it->second << endl;

3

@Lukasz Wiklendt द्वारा सुंदर समाधान! हालाँकि मेरे मामले में मुझे कुछ अधिक सामान्य चाहिए था इसलिए मैंने इसे थोड़ा संशोधित किया:

template <class RAIter, class Compare>
vector<size_t> argSort(RAIter first, RAIter last, Compare comp) {

  vector<size_t> idx(last-first);
  iota(idx.begin(), idx.end(), 0);

  auto idxComp = [&first,comp](size_t i1, size_t i2) {
      return comp(first[i1], first[i2]);
  };

  sort(idx.begin(), idx.end(), idxComp);

  return idx;
}

उदाहरण: लंबाई द्वारा तार के एक वेक्टर को छांटने वाले सूचकांक ढूंढें, पहले तत्व को छोड़कर जो एक डमी है।

vector<string> test = {"dummy", "a", "abc", "ab"};

auto comp = [](const string &a, const string& b) {
    return a.length() > b.length();
};

const auto& beginIt = test.begin() + 1;
vector<size_t> ind = argSort(beginIt, test.end(), comp);

for(auto i : ind)
    cout << beginIt[i] << endl;

प्रिंट:

abc
ab
a

3

std::multimap@Ulrich Eckhardt द्वारा सुझाए अनुसार उपयोग करने पर विचार करें । बस कोड को और भी सरल बनाया जा सकता है।

दिया हुआ

std::vector<int> a = {5, 2, 1, 4, 3};  // a: 5 2 1 4 3

सम्मिलन के मध्य समय में सॉर्ट करने के लिए

std::multimap<int, std::size_t> mm;
for (std::size_t i = 0; i != a.size(); ++i)
    mm.insert({a[i], i});

मूल्यों और मूल सूचकांकों को पुनः प्राप्त करने के लिए

std::vector<int> b;
std::vector<std::size_t> c;
for (const auto & kv : mm) {
    b.push_back(kv.first);             // b: 1 2 3 4 5
    c.push_back(kv.second);            // c: 2 1 4 3 0
}

मूल वैक्टर में समान मूल्यों की अनुमति देने के std::multimapलिए a से पसंद करने का कारण है std::map। इसके अलावा कृपया ध्यान दें कि, के लिए विपरीत std::map, operator[]के लिए निर्धारित नहीं है std::multimap


2

std::pairसमारोह में एक जोड़ी बनाएं तो जोड़ी बनाएं :

सामान्य संस्करण:

template< class RandomAccessIterator,class Compare >
auto sort2(RandomAccessIterator begin,RandomAccessIterator end,Compare cmp) ->
   std::vector<std::pair<std::uint32_t,RandomAccessIterator>>
{
    using valueType=typename std::iterator_traits<RandomAccessIterator>::value_type;
    using Pair=std::pair<std::uint32_t,RandomAccessIterator>;

    std::vector<Pair> index_pair;
    index_pair.reserve(std::distance(begin,end));

    for(uint32_t idx=0;begin!=end;++begin,++idx){
        index_pair.push_back(Pair(idx,begin));
    }

    std::sort( index_pair.begin(),index_pair.end(),[&](const Pair& lhs,const Pair& rhs){
          return cmp(*lhs.second,*rhs.second);
    });

    return index_pair;
}

ideone


1

क्या वेक्टर में आइटम अद्वितीय हैं? यदि हां, तो वेक्टर को कॉपी करें, एसटीएल सॉर्ट के साथ एक कॉपी को सॉर्ट करें फिर आप पा सकते हैं कि मूल वेक्टर में प्रत्येक आइटम किस इंडेक्स का था।

यदि वेक्टर को डुप्लिकेट आइटम को संभालने के लिए माना जाता है, तो मुझे लगता है कि आप अपनी खुद की दिनचर्या को लागू करने के लिए बेहतर हैं।


1

खैर, मेरा समाधान अवशेष तकनीक का उपयोग करता है। हम ऊपरी 2 बाइट्स और तत्वों के सूचकांकों में छंटनी के तहत मान रख सकते हैं - निचले 2 बाइट्स में:

int myints[] = {32,71,12,45,26,80,53,33};

for (int i = 0; i < 8; i++)
   myints[i] = myints[i]*(1 << 16) + i;

फिर सरणी myintsको हमेशा की तरह क्रमबद्ध करें :

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

उसके बाद आप अवशेषों के माध्यम से तत्वों के सूचकांकों तक पहुंच सकते हैं। निम्न कोड आरोही क्रम में क्रमबद्ध मानों के सूचकांकों को प्रिंट करता है:

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

बेशक, यह तकनीक केवल मूल सरणी में अपेक्षाकृत छोटे मूल्यों myints(यानी जो ऊपरी 2 बाइट्स में फिट हो सकती है int) के लिए काम करती है। लेकिन इसके समान मूल्यों को अलग करने का अतिरिक्त लाभ है myints: उनके सूचकांक सही क्रम में मुद्रित होंगे।


1

यदि यह संभव है, तो आप खोज फ़ंक्शन का उपयोग करके स्थिति सरणी का निर्माण कर सकते हैं, और फिर सरणी को सॉर्ट कर सकते हैं।

या हो सकता है कि आप एक मानचित्र का उपयोग कर सकते हैं जहां कुंजी तत्व होगा, और आगामी सरणियों में इसकी स्थिति की सूची का मान होगा (ए, बी और सी)

यह उन सरणियों के बाद के उपयोगों पर निर्भर करता है।


0

इस प्रकार के प्रश्न के लिए orignal 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]));`

यहां बाइनरीसर्च एक फ़ंक्शन है जो सरणी, सरणी का आकार, आइटम खोजता है और खोजे गए आइटम की स्थिति को लौटाएगा


-1

बहुत से रास्ते हैं। एक सरल समाधान एक 2D वेक्टर का उपयोग करना है।

#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;
}

यहाँ उत्पादन है:

   Index   Value
   3       1
   4       3
   1       4
   0       5
   2       7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.