স্টাড :: ভেক্টর কীভাবে পরিবর্তন করবেন?


99

আমি std::vectorসি ++ এ এলোমেলো করার জন্য একটি জেনেরিক, পুনরায় ব্যবহারযোগ্য উপায়ের সন্ধান করছি। আমি বর্তমানে এটি এটি করি তবে আমি মনে করি এটি খুব কার্যকরী নয় কারণ এটির একটি মধ্যবর্তী অ্যারে প্রয়োজন এবং এটি আইটেমের ধরণটি জানতে হবে (এই উদাহরণে ডেককার্ড):

srand(time(NULL));

cards_.clear();

while (temp.size() > 0) {
    int idx = rand() % temp.size();
    DeckCard* card = temp[idx];
    cards_.push_back(card);
    temp.erase(temp.begin() + idx);
}

না ফিশার-ইয়েটস দেখুন ....
মিচ গম

4
ব্যবহার না করার চেষ্টা করুন rand(), আরও ভাল আরএনজি এপিআই উপলব্ধ (বুস্ট.র্যান্ডম বা 0 এক্স <random>)।
ক্যাট প্লাস প্লাস

উত্তর:


208

সি ++ 11 থেকে আপনার পছন্দ করা উচিত:

#include <algorithm>
#include <random>

auto rng = std::default_random_engine {};
std::shuffle(std::begin(cards_), std::end(cards_), rng);

Live example on Coliru

rngআপনি std::shuffleযদি প্রতিবার বিভিন্ন ক্রিয়াকলাপ উত্পন্ন করার উদ্দেশ্যে থাকেন তবে একাধিক কলগুলিতে একই উদাহরণ পুনরায় ব্যবহার করতে ভুলবেন না !

তদুপরি, আপনি যদি চান যে আপনার প্রোগ্রামটি প্রতিবার সঞ্চালনের সময় বিভিন্ন ধরণের শ্যাফলগুলি তৈরি করতে চান, আপনি এর আউটপুট দিয়ে এলোমেলো ইঞ্জিনের নির্মাতাকে বীজ করতে পারেন std::random_device:

auto rd = std::random_device {}; 
auto rng = std::default_random_engine { rd() };
std::shuffle(std::begin(cards_), std::end(cards_), rng);

সি ++ 98 এর জন্য আপনি ব্যবহার করতে পারেন:

#include <algorithm>

std::random_shuffle(cards_.begin(), cards_.end());

8
তৃতীয় আর্গুমেন্ট হিসাবে আপনি একটি কাস্টম এলোমেলো নম্বর জেনারেটর প্লাগ করতে পারেন std::random_shuffle
আলেকজান্দ্রি সি

20
+1 - নোট করুন যে এটি প্রোগ্রামের প্রতিটি রান একটি অভিন্ন ফলাফল উত্পাদন করতে পারে। আপনি std::random_shuffleযদি কোনও সমস্যা হয় তবে অতিরিক্ত যুক্তি হিসাবে আপনি একটি কাস্টম এলোমেলো সংখ্যা জেনারেটর (যা কোনও বাহ্যিক উত্স থেকে উত্পন্ন করা যেতে পারে) যুক্ত করতে পারেন।
মানকারসে

4
@ গব00 এস: এটি প্রোগ্রামের প্রতিটি ঘটনার জন্য একই ফলাফল উত্পন্ন করবে, প্রতিটি কল নয় random_shuffle। এই আচরণটি স্বাভাবিক এবং উদ্দেশ্যযুক্ত।
ব্যবহারকারী 703016

4
@ টমজাটো#include <algorithm>
ব্যবহারকারী 703016

4
@ পার্ক ইউং-বায়ে ধন্যবাদ, আমি সবেমাত্র খুঁজে পেয়েছি । এসও উত্তরগুলিতে কোনও তথ্য অন্তর্ভুক্ত না করে এটি সত্যিই অসুবিধে হয় কারণ সেগুলি গুগল অনুসন্ধান ফলাফলের শীর্ষে রয়েছে।
টোমা জাটো - মনিকা

11

http://www.cplsplus.com/references/algorithm/shuffle/

// shuffle algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::shuffle
#include <vector>       // std::vector
#include <random>       // std::default_random_engine
#include <chrono>       // std::chrono::system_clock

int main () 
{
    // obtain a time-based seed:
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::default_random_engine e(seed);

    while(true)
    {
      std::vector<int> foo{1,2,3,4,5};

      std::shuffle(foo.begin(), foo.end(), e);

      std::cout << "shuffled elements:";
      for (int& x: foo) std::cout << ' ' << x;
      std::cout << '\n';
    }

    return 0;
}

একটি খারাপ উদাহরণ cplusplus.com/references/algorithm/shuffle থেকে অনুলিপি করা হয়েছে । আপনি কীভাবে অন্য কোনও কল এলোমেলো করবেন?
चमत्कार 173

@ चमत्कार 173 উদাহরণ উন্নত হয়েছে
মেহমেট ফাইড

4
কেবলমাত্র ব্যবহারের পরিবর্তে বীজের জন্য সিস্টেম ঘড়ির অদ্ভুত ব্যবহার কেন std::random_device?
চক ওয়ালবর্ন

6

@ সিকাডা যা বলেছিল তা ছাড়াও আপনার প্রথমে বীজ বোধ করা উচিত,

srand(unsigned(time(NULL)));
std::random_shuffle(cards_.begin(), cards_.end());

প্রতি ফ্রেডলারসনের মন্তব্য:

র্যান্ডম_স্যাফেল () এর এই সংস্করণটির জন্য এলোমেলোতার উত্সটি বাস্তবায়ন সংজ্ঞায়িত করা হয়েছে, সুতরাং এটি র্যান্ড () ব্যবহার করতে পারে না। তাহলে srand () এর কোনও প্রভাব নেই।

তাই ওয়াইএমএমভি।


11
প্রকৃতপক্ষে, এই সংস্করণটির জন্য এলোমেলোতার উত্সটি random_shuffle()বাস্তবায়ন হিসাবে সংজ্ঞায়িত করা হয়েছে, সুতরাং এটি মোটেও ব্যবহার করতে পারে না rand()। তারপরে srand()কোনও প্রভাব পড়বে না। আমি এর আগে দৌড়েছি।
ফ্রেড লারসন

@ ফ্রেড: ধন্যবাদ ফ্রেড। সেটা জানি না. আমি সব সময় srand ব্যবহার করতে অভ্যস্ত ছিল।

6
আপনার সম্ভবত এই উত্তরটি মুছে ফেলা উচিত কারণ এটি ভুল এবং - আরও খারাপ - এটি সঠিক হিসাবে দেখা যায় এবং কিছু বাস্তবায়নে সত্যই সত্য, তবে সমস্তটি নয়, এই পরামর্শটি অত্যন্ত বিপজ্জনক করে তোলে।
থমাস বনিনি

4
@ ফ্রেড উপরে বর্ণিত হিসাবে random_shuffleএলোমেলো সংখ্যা উত্পন্ন করতে ব্যবহারগুলি বাস্তবায়ন সংজ্ঞায়িত করা হয়। এর অর্থ হল যে আপনার প্রয়োগের ক্ষেত্রে এটি ব্যবহার করে rand()(এবং সুতরাং শ্রেন্ড () কাজ করে) তবে আমার উপর এটি সম্পূর্ণ আলাদা কিছু ব্যবহার করতে পারে, যার অর্থ আমার প্রয়োগের ক্ষেত্রেও আমি যতবার প্রোগ্রাম চালিয়ে যাচ্ছি প্রতিবার আমি একই ফলাফল পাব।
থমাস বনিনি

4
@ কোড: যেমনটি আমরা আলোচনা করেছি এটি সমস্ত প্রয়োগে কার্যকর হয় না। আপনি নিজের নম্বর প্রজন্মের সরবরাহ করতে পারবেন এই বিষয়টি আপনার উত্তরে উল্লেখ করা হয়নি এবং কোনও ক্ষেত্রেই এই আলোচনার সাথে সম্পর্কিত নয়। আমার মনে হচ্ছে আমরা চেনাশোনাগুলিতে যাচ্ছি: এস
টমাস বনিনি

2

আপনি যদি বুস্ট ব্যবহার করে থাকেন তবে আপনি এই শ্রেণিটি ব্যবহার করতে পারেন ( debug_modeসেট আপ করা হয়েছে false, যদি আপনি চান যে এলোমেলোকরণের পূর্বাভাসের মধ্যে এটি নির্ধারণ করা যেতে পারে যে আপনি নির্ধারণ করতে পারেন true):

#include <iostream>
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <algorithm> // std::random_shuffle

using namespace std;
using namespace boost;

class Randomizer {
private:
    static const bool debug_mode = false;
    random::mt19937 rng_;

    // The private constructor so that the user can not directly instantiate
    Randomizer() {
        if(debug_mode==true){
            this->rng_ = random::mt19937();
        }else{
            this->rng_ = random::mt19937(current_time_nanoseconds());
        }
    };

    int current_time_nanoseconds(){
        struct timespec tm;
        clock_gettime(CLOCK_REALTIME, &tm);
        return tm.tv_nsec;
    }

    // C++ 03
    // ========
    // Dont forget to declare these two. You want to make sure they
    // are unacceptable otherwise you may accidentally get copies of
    // your singleton appearing.
    Randomizer(Randomizer const&);     // Don't Implement
    void operator=(Randomizer const&); // Don't implement

public:
    static Randomizer& get_instance(){
        // The only instance of the class is created at the first call get_instance ()
        // and will be destroyed only when the program exits
        static Randomizer instance;
        return instance;
    }

    template<typename RandomAccessIterator>
    void random_shuffle(RandomAccessIterator first, RandomAccessIterator last){
        boost::variate_generator<boost::mt19937&, boost::uniform_int<> > random_number_shuffler(rng_, boost::uniform_int<>());
        std::random_shuffle(first, last, random_number_shuffler);
    }

    int rand(unsigned int floor, unsigned int ceil){
        random::uniform_int_distribution<> rand_ = random::uniform_int_distribution<> (floor,ceil);
        return (rand_(rng_));
    }
};

আপনি এই কোড দিয়ে এটি পরীক্ষা করতে পারেন তার চেয়ে:

#include "Randomizer.h"
#include <iostream>
using namespace std;

int main (int argc, char* argv[]) {
    vector<int> v;
    v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);
    v.push_back(6);v.push_back(7);v.push_back(8);v.push_back(9);v.push_back(10);

    Randomizer::get_instance().random_shuffle(v.begin(), v.end());
    for(unsigned int i=0; i<v.size(); i++){
        cout << v[i] << ", ";
    }
    return 0;
}

আপনি কেন জেনারেটরের পরিবর্তে সময় বজায় রাখছেন std::random_device?
চক ওয়ালবর্ন

1

এটি এমনকি সহজ হতে পারে, বপন সম্পূর্ণভাবে এড়ানো যায়:

#include <algorithm>
#include <random>

// Given some container `container`...
std::shuffle(container.begin(), container.end(), std::random_device());

প্রোগ্রামটি চালিত হওয়ার পরে এটি একটি নতুন শ্যাফেল তৈরি করবে। কোডটির সরলতার কারণে আমি এই পদ্ধতিকেও পছন্দ করি।

এটি কাজ করে কারণ আমাদের যা প্রয়োজন তা std::shuffleহ'ল একটি UniformRandomBitGenerator, যার প্রয়োজনীয়তা std::random_deviceপূরণ করে।

দ্রষ্টব্য: যদি বারবার random_deviceপরিবর্তন হয় তবে স্থানীয় ভেরিয়েবলের মধ্যে সঞ্চয় করা ভাল :

std::random_device rd;
std::shuffle(container.begin(), container.end(), rd);

4
এটি কী যুক্ত করে যা 8 বছর আগে থেকে ইতিমধ্যে গৃহীত উত্তরের অংশ ছিল না?
ক্রিসএমএম

4
আপনাকে যা করতে হবে তা সন্ধানের উত্তরটি পড়তে হবে ... উপরে আরও বেশি কিছু বলা যায় না যা উপরে ইতিমধ্যে খুব পরিষ্কারভাবে ব্যাখ্যা করা হয়নি।
অ্যাপলিগুলি মনিকা

4
গৃহীত উত্তর ইতিমধ্যে random_device
রদবদল

4
পুরানো স্বীকৃত উত্তরটি আরও গভীরতার হতে পারে। যাইহোক, এটি খুব স্পষ্টতই সিঙ্গেল-পয়েন্ট পয়েন্ট এবং শট উত্তর যা আমি আশা করতে পারি যখন খুব বেশি অ্যাডোও ছাড়াই এমন সাধারণ প্রশ্নের জন্য গুগল করা হয়। +1
ইচ্ছুও

4
এটা ভুল । পিআরএনজিগুলি বীজ করার জন্য random_deviceকেবল একবার কল করার জন্য ডিজাইন করা হয়েছে , বারবার কল করা যাবেনা (যা অন্তর্নিহিত এনট্রপিকে দ্রুত নিঃশেষিত করতে পারে এবং এটি একটি উপ-অনুকূল প্রজন্মের পরিকল্পনায় স্যুইচ করতে পারে)
এলএফ

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