সি ++ অনুসারে বাছাই এবং সূচকের ট্র্যাক রাখা


216

সি ++ এবং আশাকরি স্ট্যান্ডার্ড লাইব্রেরিটি ব্যবহার করে, আমি নমুনার ক্রমটিকে আরোহণের ক্রমে সাজানোর জন্য চাই তবে নতুন স্যাম্পলগুলির মূল সূচিগুলিও মনে রাখতে চাই।

উদাহরণস্বরূপ, আমার কাছে একটি সেট, বা ভেক্টর, বা নমুনার ম্যাট্রিক্স রয়েছে 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 পুনরায় অর্ডার করতে পারেন sort


4
এই উত্তরটি পছন্দ করুন your যদি আপনার সংকলক ল্যাম্বডাস সমর্থন করে না, আপনি একটি ক্লাস ব্যবহার করতে পারেন: টেম্পলেট <টাইপনেম টি> শ্রেণি তুলনা ইন্ডিজস বাই বাই আনোয়ারভেক্টরভ্যালিয়াস {স্টাড :: ভেক্টর <টি> * _ভ্যালু; সর্বজনীন: তুলনাশাসন বাইআনোথর ভেক্টরভ্যালু (স্ট্যান্ড :: ভেক্টর <টি> * মান): _মূল্য (মান)}} পাবলিক: বুল অপারেটর () কনস্ট ইন্ট ও এ, কনস্ট ইন্টি এবং বি) কনস্ট {রিটার্ন ( _ভ্যালু) [ক]> ( _মূল্য) [ খ]; }};
Yoav

2
আমি এই উত্তরটিও ভালবাসি, জোড়াগুলির ভেক্টর তৈরি করতে আসল ভেক্টরটি অনুলিপি করার দরকার নেই।
হেডমাইসহোল্ডার

29
হাতের কারুকর্মের চেয়ে for (size_t i = 0; i != idx.size(); ++i) idx[i] = i;আমি মানটিকে পছন্দ করিstd::iota( idx.begin(), idx.end(), 0 );
উইক

6
#include <numeric>iota () এর জন্য ব্যবহার করুন
kartikag01

6
iotaপুরো সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে স্বল্পতম স্পষ্টর নামযুক্ত অ্যালগরিদম।
শেঠ জনসন

87

আপনি কেবল ints এর পরিবর্তে std :: জোড়া বাছাই করতে পারেন - প্রথম intটি মূল ডেটা, দ্বিতীয় intটি মূল সূচক। তারপরে একটি তুলনামূলক সরবরাহ করুন যা কেবল প্রথম ইনটকে বাছাই করে। উদাহরণ:

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

স্ট্যান্ডার্ডের ফলাফল: ভি_প্রাইমে সাজানো, সেই তুলকটি ব্যবহার করে, হওয়া উচিত:

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

আপনি ভেক্টর হাঁটার মাধ্যমে সূচিগুলি ছাঁটাই করতে পারেন, প্রতিটি স্ট্যান্ড :: জোড় থেকে সেকেন্ডটি ধরে ফেলুন।


1
আমি ঠিক পাশাপাশি এটি করব। মৌলিক বাছাই ফাংশন পুরানো বনাম নতুন অবস্থানগুলি ট্র্যাক করে না কারণ এটি অতিরিক্ত অপ্রয়োজনীয় ওভারহেড যুক্ত করে।
the_mandrill

8
এই ফাংশনটির অপূর্ণতা হ'ল এটি আপনাকে সমস্ত মানের জন্য মেমরি পুনর্বিবেচনা করতে হবে।
Yoav

1
এটি স্পষ্টতই একটি কার্যক্ষম ব্যবস্থা, তবে এটির একটি খারাপ দিক রয়েছে যা আপনাকে আপনার মূল ধারকটিকে "সংখ্যার ধারক" থেকে "জোড়ের ধারক" হিসাবে পরিবর্তন করতে হবে।
রুসলান

18

ধরা যাক প্রদত্ত ভেক্টর

A=[2,4,3]

একটি নতুন ভেক্টর তৈরি করুন

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

ভি বাছাই করুন এবং ভ এর উপাদানগুলির তুলনা করার পরিবর্তে বাছাই করার সময়, এ এর ​​সাথে সম্পর্কিত উপাদানগুলির তুলনা করুন

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

সাজানো সূচকগুলি পাওয়ার জন্য কোনও সূচক ধারক ব্যতীত স্টাড :: সাজানোর ব্যবহার একই হয়। পরীক্ষামূলক:

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 :: সাজান হিসাবে

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 = valuei' এ

a[i].second = idx প্রাথমিক অ্যারে।


আপনার কোডের বিবরণ যুক্ত করার বিষয়ে বিবেচনা করুন যাতে ব্যবহারকারীরা এই পোস্টটিতে যান এটি বুঝতে পারে যে এটি কীভাবে কাজ করে।
ব্যস্তিপ্রোগ্রামার

আমি আসলে এই সমাধানটি সবচেয়ে ভাল পছন্দ করি - আমার ভেক্টর 4 বা তার বেশি আকারের এবং আমি সি ++ 11 এর আগে আটকেছি এবং ল্যাম্বডাস ব্যবহার করতে পারি না। ধন্যবাদ আদিত্য আসওয়াল।
স্টেফানমগ

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

@ লুকাস উইকিল্যান্ড্ট দ্বারা সুন্দর সমাধান! যদিও আমার ক্ষেত্রে আমার আরও সাধারণ কিছু প্রয়োজন ছিল তাই আমি এটিকে কিছুটা সংশোধন করেছি:

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@ অলরিচ এ্যাকহার্ট দ্বারা প্রস্তাবিত হিসাবে ব্যবহার বিবেচনা করুন । কোডটি আরও সহজতর করা যেতে পারে।

প্রদত্ত

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একটি থেকে 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

এই ধরণের প্রশ্নের জন্য অরিগিনাল অ্যারের ডেটা একটি নতুন ডেটাতে সংরক্ষণ করুন এবং তারপরে বাইনারি অনুসন্ধান করা সল্ট করা অ্যারের প্রথম উপাদানটিকে নকল করা অ্যারেতে অনুসন্ধান করুন এবং সেই সূচকটি কোনও ভেক্টর বা অ্যারেতে সংরক্ষণ করা উচিত।

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

অনেক উপায় আছে। একটি বরং সহজ সমাধান হ'ল 2 ডি ভেক্টর ব্যবহার করা।

#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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.