কোনও নকল ছাড়াই এলোমেলো সংখ্যা তৈরি করা


89

এই ক্ষেত্রে, MAX মাত্র 5, তাই আমি নকলগুলি একে একে পরীক্ষা করতে পারতাম, তবে কীভাবে আমি এটি সহজ উপায়ে করতে পারি? উদাহরণস্বরূপ, যদি MAX এর 20 এর মান থাকে? ধন্যবাদ

int MAX = 5;

for (i = 1 , i <= MAX; i++)
{
        drawNum[1] = (int)(Math.random()*MAX)+1;

        while (drawNum[2] == drawNum[1])
        {
             drawNum[2] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
        {
             drawNum[3] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
        {
             drawNum[4] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[5] == drawNum[1]) ||
               (drawNum[5] == drawNum[2]) ||
               (drawNum[5] == drawNum[3]) ||
               (drawNum[5] == drawNum[4]) )
        {
             drawNum[5] = (int)(Math.random()*MAX)+1;
        }

}

4
অনেক (সিউডো) এলোমেলো সংখ্যা জেনারেটর তাদের পূর্ণ "চক্র" এর জন্য পুনরাবৃত্তি করে না। অবশ্যই সমস্যাটি হ'ল তাদের পূর্ণ "চক্র" বিলিয়ন বা ট্রিলিয়ন কোটি মূল্যবোধ এবং তারা যে মূল্যবোধ উত্পন্ন করে সেগুলি বিলিয়ন বা ট্রিলিয়ন কোটি মূল্যবোধের যে কোনও একটি হতে পারে। আপনি তত্ত্বের ভিত্তিতে একটি এলোমেলো সংখ্যার জেনারেটর তৈরি করতে পারেন যার 5 বা 10 বা যা কিছু "চক্র" ছিল, তবে এটি সম্ভবত এটির চেয়ে বেশি সমস্যা trouble
হট লিকস

4
এছাড়াও একটি এলোমেলো সংখ্যা জেনারেটর যা পুনরাবৃত্তি করে না এটি এমনকি "কম" এলোমেলো: যদি MAX = 5 হয় এবং আপনি 3 নম্বর পড়েন তবে আপনি 50% সম্ভাব্যতার সাথে পরবর্তীটি অনুমান করতে পারবেন, যদি আপনি 4 নম্বর পড়েন তবে আপনি পরবর্তী 100% এর জন্য জানেন অবশ্যই!
আইকজা



উত্তর:


151

সহজ উপায়টি হ'ল সম্ভাব্য সংখ্যার একটি তালিকা তৈরি করা (1..20 বা যাই হোক না কেন) এবং তারপরে এগুলি পরিবর্তন করা Collections.shuffle । তারপরে আপনার পছন্দ মতো অনেকগুলি উপাদান গ্রহণ করুন। আপনার পরিসরটি আপনার প্রয়োজনীয় উপাদানগুলির সংখ্যার সমান হলে এটি দুর্দান্ত (উদাহরণস্বরূপ কার্ডের ডেকে সাফ করার জন্য)।

এটি খুব ভাল কাজ করে না যদি আপনি চান (বলুন) ১০.১০,০০০ পরিসরে ১০ টি এলোমেলো উপাদান - আপনি অযথা অনেক কাজ করে শেষ করতে চান। এই মুহুর্তে, আপনি এখন পর্যন্ত উত্পন্ন যে মানগুলির সেট রেখেছেন সম্ভবত এটি আরও ভাল এবং পরবর্তীটি ইতিমধ্যে উপস্থিত না হওয়া পর্যন্ত কেবল একটি লুপে সংখ্যা উত্পন্ন করা চালিয়ে যান:

if (max < numbersNeeded)
{
    throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
    Integer next = rng.nextInt(max) + 1;
    // As we're adding to a set, this will automatically do a containment check
    generated.add(next);
}

সেট পছন্দটি সম্পর্কে সতর্ক থাকুন - আমি খুব ইচ্ছাকৃতভাবে ব্যবহার করেছি LinkedHashSet বজায় রাখার কারণে , যা আমরা এখানে যত্নশীল care

তবুও অন্য একটি বিকল্প সর্বদা অগ্রগতি করা, প্রতিবারের পরিসর কমিয়ে এবং বিদ্যমান মানগুলির জন্য ক্ষতিপূরণ দেওয়ার মাধ্যমে। উদাহরণস্বরূপ, ধরুন আপনি 0..9 পরিসরে 3 টি মান চান। প্রথম পুনরাবৃত্তির সময় আপনি 0..9 ব্যাপ্তির মধ্যে যে কোনও সংখ্যা তৈরি করতে চান - আসুন আমরা বলি যে আপনি একটি 4 তৈরি করেন।

দ্বিতীয় পুনরাবৃত্তিতে আপনি তারপরে 0..8 ব্যাপ্তিতে একটি সংখ্যা তৈরি করতে চান। উত্পন্ন সংখ্যাটি যদি 4 টিরও কম হয় তবে আপনি এটিকে ঠিক তেমন রাখবেন ... অন্যথায় আপনি এটিতে একটি যুক্ত করুন। মনে হয় আপনি ৪.৯ ছাড়াই ফলাফলের পরিসীমা পেয়েছেন। ধরুন আমরা সেইভাবে 7 পেয়েছি।

তৃতীয় পুনরাবৃত্তিতে আপনি 0..7 পরিসীমাটিতে একটি সংখ্যা তৈরি করতে চান। উত্পন্ন সংখ্যাটি যদি 4 এর চেয়ে কম হয় তবে আপনি এটি ঠিক রাখবেন keep যদি এটি 4 বা 5 হয় তবে আপনি একটি যুক্ত করুন। যদি এটি 6 বা 7 হয় তবে আপনি দুটি যুক্ত করতে চান। 4 বা 6 ছাড়াই এইভাবে ফলাফলের পরিধি 0..9।


সম্ভাব্য মানগুলির একটি অ্যারে তৈরি করুন, এলোমেলোভাবে একটি (র্যান্ডম সংখ্যা মোড অ্যারের আকার) নির্বাচন করুন, নির্বাচিত নম্বর সরান (এবং সংরক্ষণ করুন), তারপরে পুনরাবৃত্তি করুন।
হট লিকস

অথবা একটি পূর্ণ চক্র সহ একটি এলোমেলো জেনারেটর ব্যবহার করুন (প্রাইমগুলির উপর ভিত্তি করে তারা ছোট ছোট প্রাইমগুলি ব্যবহার করতে পারে - ছোট ছোট চক্রের সাথে) এবং মানগুলি সীমার বাইরে রাখে।
পল ডি ভ্রিজে

"তবুও অন্য বিকল্প হ'ল সর্বদা অগ্রগতি" সমাধানের চেয়ে WAAAAY better প্রতিবিম্ব জন্য সম্পাদনা করুন। এবং এই দুর্দান্ত উত্তরের জন্য আপনাকে ধন্যবাদ।
ব্যবহারকারী 123321

4
@ মুসেলহিজিল: শিগগিরই কিছু সময় দেওয়ার চেষ্টা করবে। আমি "WAAAY আরও ভাল" সম্পর্কে নিশ্চিত নই - যদিও এটি আরও দক্ষ হবে তবুও এটি "স্পষ্টতই সঠিক" হতে চলেছে। বেশিরভাগ ক্ষেত্রে আমি পঠনযোগ্যতার স্বার্থে পারফরম্যান্স ত্যাগ করতে পেরে খুশি।
জন স্কিটি

@ দিপথী: প্রশ্ন অনুযায়ী সর্বোচ্চ ওপি যা কিছু চায়।
জন স্কিটি

19

আমি এটি কিভাবে করব তা এখানে

import java.util.ArrayList;
import java.util.Random;

public class Test {
    public static void main(String[] args) {
        int size = 20;

        ArrayList<Integer> list = new ArrayList<Integer>(size);
        for(int i = 1; i <= size; i++) {
            list.add(i);
        }

        Random rand = new Random();
        while(list.size() > 0) {
            int index = rand.nextInt(list.size());
            System.out.println("Selected: "+list.remove(index));
        }
    }
}

সম্মানিত মিঃ স্কীত যেমন উল্লেখ করেছেন: n
যদি আপনি পছন্দ করতে চান এমন এলোমেলোভাবে নির্বাচিত সংখ্যার সংখ্যা এবং N নির্বাচনের জন্য উপলব্ধ মোট সংখ্যার নমুনা স্থান:

  1. যদি এন << এন হয় তবে আপনার নির্বাচিত নম্বরগুলি কেবলমাত্র সংরক্ষণ করা উচিত এবং নির্বাচিত নম্বরটি এতে রয়েছে কিনা তা দেখতে একটি তালিকা পরীক্ষা করে দেখানো উচিত।
  2. যদি n ~ = N হয় তবে আপনার সম্ভবত আমার পদ্ধতিটি ব্যবহার করা উচিত, পুরো নমুনা স্পেসটি সম্বলিত একটি তালিকা তৈরি করে এবং সেগুলি বেছে নেওয়ার সাথে সাথে এটির থেকে নম্বরগুলি সরিয়ে।

তালিকাটি একটি লিঙ্কযুক্ত তালিকা হওয়া উচিত, অ্যারেলিস্ট থেকে এলোমেলো সূচকগুলি অপসারণ করা খুব অদক্ষ
রিকার্ডো ক্যাসাট্টা

@ রিকার্ডো ক্যাসাত্তা আপনার দৃ your়তার জন্য কোন উত্স আছে? আমি কল্পনাও করতে পারি না যে কোনও লিঙ্কযুক্ত তালিকাকে অনুসরণ করা খুব পারফর্মেন্ট হবে। আরও দেখুন: stackoverflow.com/a/6103075/79450
Catchwa

আমি এটি পরীক্ষা করেছি এবং আপনি ঠিক বলেছেন, আমার মন্তব্যটি মুছে ফেলা উচিত?
রিকার্ডো ক্যাসাটা

@ রিকার্ডো ক্যাসাট্টা অন্যরা আমাদের পিছনে পিছনে উপকার পেতে পারে
ক্যাচওয়া

13
//random numbers are 0,1,2,3 
ArrayList<Integer> numbers = new ArrayList<Integer>();   
Random randomGenerator = new Random();
while (numbers.size() < 4) {

    int random = randomGenerator .nextInt(4);
    if (!numbers.contains(random)) {
        numbers.add(random);
    }
}

এটির বিশাল সংখ্যার জন্য এটি ভয়াবহ অভিনয় করবে have অ্যারেলিস্ট.কন্টেনগুলি তালিকাটির মাধ্যমে পুনরাবৃত্তি করছে। পরিবর্তে অনেকগুলি ক্লিনার একটি সেট থাকা দরকার - এটিতে এটি রয়েছে কিনা তা খতিয়ে দেখার দরকার নেই, কেবল যুক্ত করুন এবং অভিনয় আরও ভাল হবে।
কেএফক্স

5

এলএফএসআর দিয়ে "এলোমেলো" অর্ডার করা নম্বরগুলি করার আরও একটি উপায় আছে, একবার দেখুন:

http://en.wikedia.org/wiki/Linear_feedback_shift_register

এই কৌশলটির সাহায্যে আপনি সূচী অনুসারে অর্ডার করা এলোমেলো সংখ্যা অর্জন করতে পারেন এবং মানগুলি নকল নয় তা নিশ্চিত করে।

তবে এগুলি সত্যিকারের এলোমেলো সংখ্যা নয় কারণ এলোমেলো প্রজন্ম নির্বিচারক।

কিন্তু আপনার ক্ষেত্রে নির্ভর করে আপনি যখন এলোমেলো ব্যবহারের সময় এলোমেলো সংখ্যা প্রজন্মের প্রসেসিংয়ের পরিমাণ হ্রাস করতে এই কৌশলটি ব্যবহার করতে পারেন।

এখানে জাভাতে একটি এলএফএসআর অ্যালগরিদম, (আমি এটি কোথাও নিয়ে গিয়েছিলাম যা আমি মনে করি না):

public final class LFSR {
    private static final int M = 15;

    // hard-coded for 15-bits
    private static final int[] TAPS = {14, 15};

    private final boolean[] bits = new boolean[M + 1];

    public LFSR() {
        this((int)System.currentTimeMillis());
    }

    public LFSR(int seed) {
        for(int i = 0; i < M; i++) {
            bits[i] = (((1 << i) & seed) >>> i) == 1;
        }
    }

    /* generate a random int uniformly on the interval [-2^31 + 1, 2^31 - 1] */
    public short nextShort() {
        //printBits();

        // calculate the integer value from the registers
        short next = 0;
        for(int i = 0; i < M; i++) {
            next |= (bits[i] ? 1 : 0) << i;
        }

        // allow for zero without allowing for -2^31
        if (next < 0) next++;

        // calculate the last register from all the preceding
        bits[M] = false;
        for(int i = 0; i < TAPS.length; i++) {
            bits[M] ^= bits[M - TAPS[i]];
        }

        // shift all the registers
        for(int i = 0; i < M; i++) {
            bits[i] = bits[i + 1];
        }

        return next;
    }

    /** returns random double uniformly over [0, 1) */
    public double nextDouble() {
        return ((nextShort() / (Integer.MAX_VALUE + 1.0)) + 1.0) / 2.0;
    }

    /** returns random boolean */
    public boolean nextBoolean() {
        return nextShort() >= 0;
    }

    public void printBits() {
        System.out.print(bits[M] ? 1 : 0);
        System.out.print(" -> ");
        for(int i = M - 1; i >= 0; i--) {
            System.out.print(bits[i] ? 1 : 0);
        }
        System.out.println();
    }


    public static void main(String[] args) {
        LFSR rng = new LFSR();
        Vector<Short> vec = new Vector<Short>();
        for(int i = 0; i <= 32766; i++) {
            short next = rng.nextShort();
            // just testing/asserting to make 
            // sure the number doesn't repeat on a given list
            if (vec.contains(next))
                throw new RuntimeException("Index repeat: " + i);
            vec.add(next);
            System.out.println(next);
        }
    }
}

4

আরেকটি পদ্ধতির সাহায্যে আপনি কত সংখ্যার সাথে চান sizeতা minএবং maxফিরে আসা সংখ্যার মান এবং মান নির্দিষ্ট করতে পারবেন

public static int getRandomInt(int min, int max) {
    Random random = new Random();

    return random.nextInt((max - min) + 1) + min;
}

public static ArrayList<Integer> getRandomNonRepeatingIntegers(int size, int min,
        int max) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();

    while (numbers.size() < size) {
        int random = getRandomInt(min, max);

        if (!numbers.contains(random)) {
            numbers.add(random);
        }
    }

    return numbers;
}

এটি 0 এবং 25 এর মধ্যে 7 নম্বর ফেরত ব্যবহার করতে।

    ArrayList<Integer> list = getRandomNonRepeatingIntegers(7, 0, 25);
    for (int i = 0; i < list.size(); i++) {
        System.out.println("" + list.get(i));
    }

4

এটি এতে অনেক সহজ হবে java-8:

Stream.generate(new Random()::ints)
            .distinct()
            .limit(16) // whatever limit you might need
            .toArray(Integer[]::new);

3

অ-পুনরাবৃত্তি র্যান্ডম সংখ্যার সবচেয়ে কার্যকর, মৌলিক উপায়টি এই সিউডো কোড দ্বারা ব্যাখ্যা করা হয়েছে। নেস্টেড লুপগুলি বা হ্যাশ লুকআপের দরকার নেই:

// get 5 unique random numbers, possible values 0 - 19
// (assume desired number of selections < number of choices)

const int POOL_SIZE = 20;
const int VAL_COUNT = 5;

declare Array mapping[POOL_SIZE];
declare Array results[VAL_COUNT];

declare i int;
declare r int;
declare max_rand int;

// create mapping array
for (i=0; i<POOL_SIZE; i++) {
   mapping[i] = i;
}

max_rand = POOL_SIZE-1;  // start loop searching for maximum value (19)

for (i=0; i<VAL_COUNT; i++) {
    r = Random(0, max_rand); // get random number
    results[i] = mapping[r]; // grab number from map array
    mapping[r] = max_rand;  // place item past range at selected location

    max_rand = max_rand - 1;  // reduce random scope by 1
}

মনে করুন প্রথম পুনরুক্তি শুরু করতে এলোমেলো সংখ্যা 3 তৈরি করেছে (0 - 19 থেকে)। এটি ফলাফল তৈরি করবে [0] = ম্যাপিং [3], অর্থাৎ মান 3। আমরা তারপরে ম্যাপিং নির্ধারণ করব [3] থেকে 19 এ।

পরবর্তী পুনরাবৃত্তিতে, এলোমেলো সংখ্যা 5 (0 - 18 থেকে)। এটি ফলাফল তৈরি করবে [1] = ম্যাপিং [5], অর্থাৎ 5 মান। আমরা তারপরে [5] থেকে 18 এ ম্যাপিং নির্ধারণ করব।

এখন ধরুন পরবর্তী পুনরাবৃত্তি আবার 3 টি বেছে নিয়েছে (0 - 17 থেকে)। ফলাফল [2] ম্যাপিংয়ের মান বরাদ্দ করা হবে [3], কিন্তু এখন, এই মানটি 3 নয়, তবে 19।

এটি একই সুরক্ষা সমস্ত সংখ্যার জন্য অব্যাহত রয়েছে, এমনকি যদি আপনি পরপর 5 বার একই নম্বর পান। উদাহরণস্বরূপ, যদি এলোমেলো সংখ্যার জেনারেটর আপনাকে পরপর পাঁচবার 0 বার দেয় তবে ফলাফলগুলি হবে: [0, 19, 18, 17, 16]।

আপনি কখনও একই নম্বর পাবেন না।


আমি সন্দেহ করি এটি এলোমেলো হিসাবে আপনি এটি শব্দ করেন। এটি কি স্ট্যান্ডার্ড এলোমেলো পরীক্ষায় পাস করে ?; এটি বর্ণালীর শেষের কাছাকাছি সংখ্যাকে কেন্দ্রীভূত বলে মনে হবে।
টুকুশি

এখানে একটি বেস কেস। পুলটি {এ, বি, সি} আমাদের 2 অ-পুনরাবৃত্তি উপাদান প্রয়োজন। অ্যালগরিদম অনুসরণ করে, এখানে আমরা সংমিশ্রণগুলি আঁকতে পারি এবং এর ফলাফলগুলি: 0,0: a, c 0,1: a, b 1,0: b, a 1,1: b, c 2,0: c, a 2, 1: সি, বি স্কোর: এ -4, বি -4, সি -4
ব্ল্যাকক্যাটভেব

3

একটি ক্রমের সমস্ত সূচক উত্পন্ন করা সাধারণত একটি খারাপ ধারণা, কারণ এতে অনেক সময় লাগতে পারে, বিশেষত যদি সংখ্যার অনুপাতটি MAXকম হয় (জটিলতা এর দ্বারা প্রাধান্য পায় O(MAX))। এটির সংখ্যার অনুপাত যদি MAXএকটির কাছে পৌঁছানো হয় তবে এটি আরও খারাপ হয় , তারপরে সমস্তের ক্রম থেকে নির্বাচিত সূচকগুলি অপসারণ করাও ব্যয়বহুল হয়ে যায় (আমরা কাছে যাই O(MAX^2/2))। তবে স্বল্প সংখ্যার জন্য, এটি সাধারণত ভালভাবে কাজ করে এবং বিশেষত ত্রুটি-প্রবণ নয়।

সংগ্রহ ব্যবহার করে উত্পন্ন সূচকগুলি ফিল্টার করাও একটি খারাপ ধারণা, কারণ সূচিগুলি অনুসারে সন্নিবেশ করানোর ক্ষেত্রে কিছুটা সময় ব্যয় করা হয়, এবং একই র্যান্ডম সংখ্যাটি কয়েকবার আঁকতে পারে বলে অগ্রগতি গ্যারান্টিযুক্ত হয় না (তবে যথেষ্ট পরিমাণে MAXএটি অসম্ভব) )। এটি জটিলতার কাছাকাছি হতে পারে
O(k n log^2(n)/2), সদৃশগুলি উপেক্ষা করে এবং সংগ্রহটি দক্ষ অনুসন্ধানের জন্য একটি গাছ ব্যবহার করে (তবে kগাছের নোডগুলিকে বরাদ্দ করার ক্ষেত্রে একটি ধ্রুবক ব্যয় এবং সম্ভবত পুনরায় ভারসাম্য বজায় রাখতে হবে) ) ধরে নেওয়া যায়।

আরেকটি বিকল্প হ'ল প্রথম থেকেই এলোমেলো মান উত্পন্ন করা, গ্যারান্টি দিয়ে অগ্রগতি হচ্ছে। এর অর্থ প্রথম রাউন্ডে, এলোমেলো সূচক [0, MAX]তৈরি হয়:

items i0 i1 i2 i3 i4 i5 i6 (total 7 items)
idx 0       ^^             (index 2)

দ্বিতীয় রাউন্ডে, শুধুমাত্র [0, MAX - 1]উত্পন্ন হয় (একটি আইটেম ইতিমধ্যে নির্বাচিত ছিল):

items i0 i1    i3 i4 i5 i6 (total 6 items)
idx 1          ^^          (index 2 out of these 6, but 3 out of the original 7)

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

সংক্ষিপ্ত ক্রমের জন্য, এটি বেশ দ্রুত O(n^2/2)অ্যালগরিদম:

void RandomUniqueSequence(std::vector<int> &rand_num,
    const size_t n_select_num, const size_t n_item_num)
{
    assert(n_select_num <= n_item_num);

    rand_num.clear(); // !!

    // b1: 3187.000 msec (the fastest)
    // b2: 3734.000 msec
    for(size_t i = 0; i < n_select_num; ++ i) {
        int n = n_Rand(n_item_num - i - 1);
        // get a random number

        size_t n_where = i;
        for(size_t j = 0; j < i; ++ j) {
            if(n + j < rand_num[j]) {
                n_where = j;
                break;
            }
        }
        // see where it should be inserted

        rand_num.insert(rand_num.begin() + n_where, 1, n + n_where);
        // insert it in the list, maintain a sorted sequence
    }
    // tier 1 - use comparison with offset instead of increment
}

কোথায় n_select_num আপনার 5 এবং n_number_numআপনার হয় MAXn_Rand(x)র্যান্ডম পূর্ণসংখ্যার ফেরৎ[0, x] (সহ)। সন্নিবেশ বিন্দুটি সন্ধান করতে বাইনারি অনুসন্ধান ব্যবহার করে প্রচুর আইটেম (যেমন 5 নয় তবে 500) বাছাই করা হলে এটি কিছুটা দ্রুত করা যায় made এটি করার জন্য, আমাদের প্রয়োজনীয়তাগুলি পূরণ করছি তা নিশ্চিত করতে হবে।

আমরা তুলনা n + j < rand_num[j]যা একই হিসাবে বাইনারি অনুসন্ধান করব
n < rand_num[j] - j। আমাদের এটি দেখাতে হবে যে rand_num[j] - jএখনও বাছাই করা ক্রমের জন্য বাছাই করা ক্রম rand_num[j]। এটি ভাগ্যক্রমে সহজেই প্রদর্শিত হয়, কারণ মূল দুটি উপাদানের মধ্যে সর্বনিম্ন দূরত্ব rand_numএক (উত্পন্ন সংখ্যাগুলি অনন্য, তাই সর্বদা কমপক্ষে 1 এর পার্থক্য থাকে)। একই সাথে, যদি আমরা সূচকগুলি বিয়োগ করিj সমস্ত উপাদান থেকে
rand_num[j] পার্থক্য হুবহু 1. বাইনারি অনুসন্ধান তাই ব্যবহার করা যেতে পারে, ফলনকারী O(n log(n))অ্যালগরিদম:

struct TNeedle { // in the comparison operator we need to make clear which argument is the needle and which is already in the list; we do that using the type system.
    int n;

    TNeedle(int _n)
        :n(_n)
    {}
};

class CCompareWithOffset { // custom comparison "n < rand_num[j] - j"
protected:
    std::vector<int>::iterator m_p_begin_it;

public:
    CCompareWithOffset(std::vector<int>::iterator p_begin_it)
        :m_p_begin_it(p_begin_it)
    {}

    bool operator ()(const int &r_value, TNeedle n) const
    {
        size_t n_index = &r_value - &*m_p_begin_it;
        // calculate index in the array

        return r_value < n.n + n_index; // or r_value - n_index < n.n
    }

    bool operator ()(TNeedle n, const int &r_value) const
    {
        size_t n_index = &r_value - &*m_p_begin_it;
        // calculate index in the array

        return n.n + n_index < r_value; // or n.n < r_value - n_index
    }
};

এবং পরিশেষে:

void RandomUniqueSequence(std::vector<int> &rand_num,
    const size_t n_select_num, const size_t n_item_num)
{
    assert(n_select_num <= n_item_num);

    rand_num.clear(); // !!

    // b1: 3578.000 msec
    // b2: 1703.000 msec (the fastest)
    for(size_t i = 0; i < n_select_num; ++ i) {
        int n = n_Rand(n_item_num - i - 1);
        // get a random number

        std::vector<int>::iterator p_where_it = std::upper_bound(rand_num.begin(), rand_num.end(),
            TNeedle(n), CCompareWithOffset(rand_num.begin()));
        // see where it should be inserted

        rand_num.insert(p_where_it, 1, n + p_where_it - rand_num.begin());
        // insert it in the list, maintain a sorted sequence
    }
    // tier 4 - use binary search
}

আমি তিনটি মানদণ্ডে এটি পরীক্ষা করেছি। প্রথমত, 7 টি আইটেমের মধ্যে 3 নম্বর বেছে নেওয়া হয়েছিল এবং চয়ন করা আইটেমগুলির একটি হিস্টোগ্রাম 10,000 টিরও বেশি রান সংগ্রহ করেছিল:

4265 4229 4351 4267 4267 4364 4257

এটি দেখায় যে items টি আইটেমের প্রত্যেকটি প্রায় একই সংখ্যক বার বেছে নেওয়া হয়েছিল এবং অ্যালগরিদমের কারণে কোনও আপাত পক্ষপাত নেই। সমস্ত ক্রমগুলিও নির্ভুলতার জন্য অনুসন্ধান করা হয়েছিল (সামগ্রীর স্বতন্ত্রতা)।

দ্বিতীয় মানদণ্ডে 5000 আইটেমের মধ্যে 7 নম্বর বেছে নেওয়া জড়িত। অ্যালগরিদমের বেশ কয়েকটি সংস্করণের সময় 10,000,000 রানেরও বেশি জমে ছিল। ফলাফল হিসাবে কোড মন্তব্য করা হয়b1 । অ্যালগরিদমের সাধারণ সংস্করণটি কিছুটা দ্রুত।

তৃতীয় মানদণ্ডে 5000 আইটেমের মধ্যে 700 নম্বর বেছে নেওয়া জড়িত। অ্যালগরিদমের বেশ কয়েকটি সংস্করণের সময় আবার জমা হয়েছিল, এবার 10,000 রানেরও বেশি। ফলাফল হিসাবে কোড মন্তব্য করা হয়b2 । অ্যালগরিদমের বাইনারি অনুসন্ধান সংস্করণটি এখন সাধারণের চেয়ে দ্বিগুণের বেশি গতিযুক্ত।

আমার মেশিনে সিসিএ 75 আইটেমের চেয়ে বেশি চয়ন করার জন্য দ্বিতীয় পদ্ধতিটি দ্রুত হতে শুরু করে (নোট করুন যে কোনও একটিতে অ্যালগোরিদমের জটিলতা আইটেমের সংখ্যার উপর নির্ভর করে না, MAX )।

এটি উল্লেখযোগ্য যে উপরের অ্যালগরিদমগুলি ক্রমবর্ধমান ক্রমে র্যান্ডম সংখ্যা উত্পন্ন করে। তবে আরও একটি অ্যারে যুক্ত করা সহজ হবে যাতে সংখ্যাটি তারা যেভাবে তৈরি করেছিল সেভাবে সংরক্ষণ করা হবে এবং পরিবর্তে এটিকে ফিরিয়ে দেওয়া হবে (নগদ অতিরিক্ত ব্যয়ে)O(n) ) । আউটপুট বদল করা প্রয়োজন হয় না: এটি অনেক ধীর হবে।

নোট করুন যে উত্সগুলি সি ++ এ রয়েছে, আমার মেশিনে জাভা নেই তবে ধারণাটি পরিষ্কার হওয়া উচিত।

সম্পাদনা :

চিত্তবিনোদন করার জন্য, আমি সেই পদ্ধতিকেও প্রয়োগ করেছি যা সমস্ত সূচকগুলির সাথে একটি তালিকা তৈরি করে
0 .. MAX, এলোমেলোভাবে তাদের চয়ন করে এবং স্বতন্ত্রতার গ্যারান্টি হিসাবে তালিকা থেকে তাদের সরিয়ে দেয়। যেহেতু আমি বেশ উচ্চ MAX(5000) বেছে নিয়েছি , অভিনয়টি বিপর্যয়কর:

// b1: 519515.000 msec
// b2: 20312.000 msec
std::vector<int> all_numbers(n_item_num);
std::iota(all_numbers.begin(), all_numbers.end(), 0);
// generate all the numbers

for(size_t i = 0; i < n_number_num; ++ i) {
    assert(all_numbers.size() == n_item_num - i);
    int n = n_Rand(n_item_num - i - 1);
    // get a random number

    rand_num.push_back(all_numbers[n]); // put it in the output list
    all_numbers.erase(all_numbers.begin() + n); // erase it from the input
}
// generate random numbers

আমি একটি set(একটি সি ++ সংগ্রহ) সহ এপ্রোচটিও বাস্তবায়ন করেছি , যা b2বাইনারি অনুসন্ধানের সাথে পদ্ধতির চেয়ে প্রায় 50% ধীর গতিতে, বেঞ্চমার্কে আসলে দ্বিতীয় স্থানে আসে । এটি বোধগম্য, যেমন setব্যবহারগুলি বাইনারি গাছ ব্যবহার করে, যেখানে সন্নিবেশ ব্যয় বাইনারি অনুসন্ধানের মতো। পার্থক্যটি হ'ল সদৃশ আইটেমগুলি পাওয়ার সুযোগ, যা অগ্রগতি কমিয়ে দেয়।

// b1: 20250.000 msec
// b2: 2296.000 msec
std::set<int> numbers;
while(numbers.size() < n_number_num)
    numbers.insert(n_Rand(n_item_num - 1)); // might have duplicates here
// generate unique random numbers

rand_num.resize(numbers.size());
std::copy(numbers.begin(), numbers.end(), rand_num.begin());
// copy the numbers from a set to a vector

সম্পূর্ণ উত্স কোড এখানে


2

আপনি সেট ইন্টারফেস ( এপিআই ) প্রয়োগকারী ক্লাসগুলির মধ্যে একটি ব্যবহার করতে পারেন , এবং তারপরে আপনার তৈরি প্রতিটি নম্বর, এটি সন্নিবেশ করানোর জন্য সেট.এডিডি () ব্যবহার করুন।

যদি ফেরতের মানটি মিথ্যা হয় তবে আপনি জানেন যে নম্বরটি ইতিমধ্যে উত্পন্ন হয়েছে।


2

এই সমস্ত LinkedHashSetনা করে Math.random()ফাংশন দ্বারা এটিতে একটি অবজেক্ট এবং এলোমেলো সংখ্যা তৈরি করুন .... যদি কোনও সদৃশ এন্ট্রি ঘটে তবে LinkedHashSetবস্তুটি তার তালিকায় সেই সংখ্যাটি যুক্ত করবে না ... যেহেতু এই সংগ্রহ শ্রেণিতে কোনও সদৃশ মান অনুমোদিত নয় .. শেষ পর্যন্ত আপনি কোনও নকল মান না রেখে র্যান্ডম সংখ্যার একটি তালিকা পান ....: ডি


2

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

উইকিপিডিয়া: ফিশার – ইয়েটস বদল একটি ও (কে) সংস্করণ থাকে যখন অ্যারে ইতিমধ্যে উপস্থিত থাকে। আপনার ক্ষেত্রে, উপাদানের কোনও অ্যারে নেই এবং উপাদানগুলির অ্যারে তৈরি করা খুব ব্যয়বহুল হতে পারে, বলুন যদি 20 এর পরিবর্তে সর্বোচ্চ 10000000 হয়।

এলোমেলোভাবে অ্যালগরিদম আকারের একটি অ্যারের সূচনা করে যেখানে প্রতিটি উপাদান তার সূচকের সমান হয়, কে রে্যান্ডম সংখ্যাকে প্রতিটি রেঞ্জের সাথে পূর্বের রেঞ্জের তুলনায় সর্বাধিক এক কম বাছাই করে থাকে এবং তারপরে অ্যারের শেষের দিকে উপাদানগুলিকে অদলবদল করে।

আপনি হ্যাশম্যাপ দিয়ে ও (কে) সময়ে একই অপারেশন করতে পারেন যদিও আমি তার ধরণের ব্যথা স্বীকার করি। নোট করুন যে কে এর চেয়ে কম এন এর চেয়ে কম হয়। (যেমন কে ~ এলজি (এন) বা তাই), অন্যথায় আপনার সরাসরি এলোমেলো ব্যবহার করা উচিত।

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

  1. এলোমেলো সংখ্যার বাছুন: প্রথমটি 0 থেকে এন -1, দ্বিতীয় 0 থেকে এন -2, তৃতীয় 0 থেকে এন -3 এবং এর মধ্যে, এনকে মাধ্যমে হবে।

  2. অদলবদলের সেট হিসাবে আপনার এলোমেলো সংখ্যার সাথে আচরণ করুন। প্রথম র্যান্ডম সূচকটি চূড়ান্ত অবস্থানে চলে আসে। দ্বিতীয় এলোমেলো সূচক দ্বিতীয় থেকে শেষ অবস্থানে চলে আসে। তবে ব্যাকিং অ্যারের বিরুদ্ধে কাজ করার পরিবর্তে আপনার হ্যাশম্যাপের বিরুদ্ধে কাজ করুন। আপনার হ্যাশম্যাপ অবস্থানের বাইরে থাকা প্রতিটি আইটেম সংরক্ষণ করবে।

int getValue(i) { if (map.contains(i)) return map[i]; return i; } void setValue(i, val) { if (i == val) map.remove(i); else map[i] = val; } int[] chooseK(int n, int k) { for (int i = 0; i < k; i++) { int randomIndex = nextRandom(0, n - i); //(n - i is exclusive) int desiredIndex = n-i-1; int valAtRandom = getValue(randomIndex); int valAtDesired = getValue(desiredIndex); setValue(desiredIndex, valAtRandom); setValue(randomIndex, valAtDesired); } int[] output = new int[k]; for (int i = 0; i < k; i++) { output[i] = (getValue(n-i-1)); } return output; }


creating the array of elements could be very expensive- কেন একটি অ্যারে তৈরি করা বদলের চেয়ে ব্যয়বহুল হওয়া উচিত? আমি মনে করি এই মুহুর্তে হতাশার কোনও কারণ নেই :-)
ওল্ফ

1

নিম্নলিখিত কোডগুলি [1, মি] এর মধ্যে একটি সিকোয়েন্স এলোমেলো সংখ্যা তৈরি করে যা এর আগে তৈরি করা হয়নি।

public class NewClass {

    public List<Integer> keys = new ArrayList<Integer>();

    public int rand(int m) {
        int n = (int) (Math.random() * m + 1);
        if (!keys.contains(n)) {
            keys.add(n);
            return n;
        } else {
            return rand(m);
        }
    }

    public static void main(String[] args) {
        int m = 4;
        NewClass ne = new NewClass();
        for (int i = 0; i < 4; i++) {
            System.out.println(ne.rand(m));
        }
        System.out.println("list: " + ne.keys);
    }
}


0

কার্ড ব্যাচের অ্যালগোরিদম রয়েছে: আপনি অর্ডারের সংখ্যার অ্যারে ("কার্ড ব্যাচ") তৈরি করেন এবং প্রতিটি পুনরাবৃত্তিতে আপনি এ থেকে এলোমেলো অবস্থানে একটি সংখ্যা নির্বাচন করেন (অবশ্যই "কার্ড ব্যাচ" থেকে নির্বাচিত নম্বরটি সরিয়ে ফেলবেন)।


0

এলোমেলোভাবে অ্যারে দ্রুত তৈরি করার জন্য এখানে একটি কার্যকর সমাধান। এলোমেলোকরণের পরে আপনি কেবল অ্যারের-বৃদ্ধি nউপাদানটি বাছাই করতে পারেন এবং ফিরে আসতে পারেন । এই সমাধানটিতে একটি এলোমেলো সংখ্যা পাওয়ার জন্য ও (1) এবং আরম্ভের জন্য ও (এন) রয়েছে, তবে ট্রেড অফ হিসাবে এন পর্যাপ্ত পরিমাণে বড় হয়ে গেলে মেমরির একটি ভাল পরিমাণ প্রয়োজন।ene


0

কালেকশন.শ্যাফলের চেয়ে পূর্ণসংখ্যার জন্য আরও দক্ষ এবং কম জটিল সমাধান রয়েছে।

সমস্যাটি হ'ল ধারাবাহিকভাবে কেবল সেট-এ বাছাই করা আইটেমগুলি থেকে সেটগুলিতে কিছু সেট বাছাই করা এবং সেগুলি অন্য কোথাও যাতে সেগুলি সেট করা থাকে। এটি ঠিক এলোমেলোভাবে কার্ড লেনদেন বা টুপি বা বিন থেকে বিজয়ী রাফল টিকিট আঁকার মতো।

এই অ্যালগরিদম কোনও অ্যারে লোড এবং লোড শেষে একটি এলোমেলো অর্ডার অর্জনের জন্য কাজ করে। এটি তালিকা সংগ্রহ (বা অন্য কোনও সূচক সংগ্রহ) যুক্ত করার জন্য এবং সংযোজনগুলির শেষে সংযোজনে একটি এলোমেলো ক্রম অর্জনের জন্যও কাজ করে।

এটি একক অ্যারে দিয়ে তৈরি করা যেতে পারে, একবার তৈরি করা হয়েছে বা একটি সংখ্যা হিসাবে অর্ডার করা সংগ্রহশালা, যেমন একটি তালিকা হিসাবে রয়েছে, একটি অ্যারের জন্য, প্রাথমিক বিন্যাসের আকারটি সমস্ত উদ্দেশ্যযুক্ত মানগুলি ধারণ করতে সঠিক আকার হওয়া দরকার। আপনি যদি না জানেন যে কতগুলি মান আগাম সংঘটিত হতে পারে, যেমন একটি অ্যারেলিস্ট বা তালিকা, যেখানে আকার অপরিবর্তনীয় নয়, এমন একটি সংখ্যাসূচক অর্ডারযুক্ত সংগ্রহ ব্যবহার করেও কাজ করবে। এটি পূর্ণসংখ্যা পর্যন্ত কোনও আকারের অ্যারের জন্য সর্বজনীনভাবে কাজ করবে MA MAX_VALUE যা মাত্র ২,০০,০০০,০০০ এরও বেশি। তালিকার অবজেক্টগুলির একই সূচক সীমা থাকবে। আপনার মাপের অ্যারেতে যাওয়ার আগে আপনার মেশিনটি মেমরির বাইরে চলে যেতে পারে। অ্যারেটি লোড করার পরে অবজেক্টের ধরণের টাইপিত অ্যারে লোড করা এবং এটিকে কিছু সংগ্রহে রূপান্তর করা আরও দক্ষ। লক্ষ্য সংগ্রহটি সংখ্যাগতভাবে সূচিকৃত না হলে এটি বিশেষভাবে সত্য।

ঠিক এই লিখিতভাবেই এই অ্যালগরিদমটি এমন একটি এমনকি এমনকি বিতরণ তৈরি করবে যেখানে কোনও নকল নেই। একটি দিক যা অত্যন্ত গুরুত্বপূর্ণ তা হ'ল পরবর্তী আকারের সারণিটি বর্তমান আকার + ১ পর্যন্ত হওয়া সম্ভব হয় সুতরাং দ্বিতীয় আইটেমটির জন্য এটি 0 বা অবস্থানের 1 জায়গায় সংরক্ষণ করা সম্ভব ছিল could 20 তম আইটেমটির জন্য, 0 থেকে 19 এর মধ্যে যেকোন স্থানে এটি সংরক্ষণ করা সম্ভব। এটি অন্য যে কোনও জায়গায় শেষ হওয়ার জন্য প্রথম আইটেমটি 0 স্থানে থাকা ঠিক ততটাই সম্ভব। পরবর্তী নতুন আইটেমটির জন্য পরবর্তী নতুন অবস্থান সহ যে কোনও জায়গায় যাওয়া ঠিক যেমন সম্ভব is

ক্রমটির এলোমেলোতা এলোমেলো সংখ্যা জেনারেটরের এলোমেলোতার মতো হবে as

এই অ্যালগরিদম কোনও অ্যারেতে এলোমেলো অবস্থানগুলিতে রেফারেন্স প্রকারগুলি লোড করতেও ব্যবহার করা যেতে পারে। যেহেতু এটি একটি অ্যারের সাথে কাজ করে, এটি সংগ্রহের সাথেও কাজ করতে পারে। এর অর্থ আপনাকে সংগ্রহটি তৈরি করতে হবে না এবং তারপরে এলোমেলো করে দেবে না বা বস্তুগুলি whateverোকানোর জন্য যেকোনো আদেশেই এটি অর্ডার করেছে। সংগ্রহের কেবল সংগ্রহের যে কোনও জায়গায় আইটেম সন্নিবেশ করানোর বা এটি যুক্ত করার ক্ষমতা থাকতে হবে have

// RandomSequence.java
import java.util.Random;
public class RandomSequence {

    public static void main(String[] args) {
        // create an array of the size and type for which
        // you want a random sequence
        int[] randomSequence = new int[20];
        Random randomNumbers = new Random();

        for (int i = 0; i < randomSequence.length; i++ ) {
            if (i == 0) { // seed first entry in array with item 0
                randomSequence[i] = 0; 
            } else { // for all other items...
                // choose a random pointer to the segment of the
                // array already containing items
                int pointer = randomNumbers.nextInt(i + 1);
                randomSequence[i] = randomSequence[pointer]; 
                randomSequence[pointer] = i;
                // note that if pointer & i are equal
                // the new value will just go into location i and possibly stay there
                // this is VERY IMPORTANT to ensure the sequence is really random
                // and not biased
            } // end if...else
        } // end for
        for (int number: randomSequence) {
                System.out.printf("%2d ", number);
        } // end for
    } // end main
} // end class RandomSequence

0

এটি সত্যই নির্ভর করে যে আপনার জন্য এলোমেলো প্রজন্মের প্রয়োজন ঠিক তার উপর নির্ভর করে তবে এখানে আমার গ্রহণ।

প্রথমে, এলোমেলো সংখ্যা উত্পন্ন করার জন্য একটি স্বতন্ত্র পদ্ধতি তৈরি করুন। সীমা জন্য অনুমতি নিশ্চিত করুন।

public static int newRandom(int limit){
    return generatedRandom.nextInt(limit);  }

এর পরে, আপনি একটি খুব সাধারণ সিদ্ধান্ত কাঠামো তৈরি করতে চাইবেন যা মানগুলির সাথে তুলনা করে। এই দুটি পদ্ধতির মধ্যে সম্পন্ন করা যেতে পারে। আপনার যদি যাচাই করার জন্য খুব সীমিত সংখ্যক সংখ্যা থাকে তবে একটি সাধারণ আইএফ স্টেটমেন্ট যথেষ্ট হবে:

public static int testDuplicates(int int1, int int2, int int3, int int4, int int5){
    boolean loopFlag = true;
    while(loopFlag == true){
        if(int1 == int2 || int1 == int3 || int1 == int4 || int1 == int5 || int1 == 0){
            int1 = newRandom(75);
            loopFlag = true;    }
        else{
            loopFlag = false;   }}
    return int1;    }

উপরেরগুলি ইনট 5 এর সাথে ইনট 2 এর সাথে ইনট 2 এর সাথে তুলনা করে পাশাপাশি এলোমেলোভাবে কোনও জিরো নেই তা নিশ্চিত করে তোলে।

এই দুটি পদ্ধতির জায়গায়, আমরা নিম্নলিখিতটি করতে পারি:

    num1 = newRandom(limit1);
    num2 = newRandom(limit1);
    num3 = newRandom(limit1);
    num4 = newRandom(limit1);
    num5 = newRandom(limit1);

অনুসরণ করেছেন:

        num1 = testDuplicates(num1, num2, num3, num4, num5);
        num2 = testDuplicates(num2, num1, num3, num4, num5);
        num3 = testDuplicates(num3, num1, num2, num4, num5);
        num4 = testDuplicates(num4, num1, num2, num3, num5);
        num5 = testDuplicates(num5, num1, num2, num3, num5);

যদি আপনার যাচাই করার জন্য আরও দীর্ঘ তালিকা থাকে তবে আরও জটিল পদ্ধতি কোডের স্বচ্ছতা এবং প্রক্রিয়াজাতকরণ সংস্থানগুলিতে উভয়ই ভাল ফলাফল পাবে।

আশাকরি এটা সাহায্য করবে. এই সাইটটি আমাকে এতটা সাহায্য করেছে, আমিও সাহায্য করতে কমপক্ষে TRY করতে বাধ্য বোধ করেছি।


0

আমি একটি স্নিপেট তৈরি করেছি যা কোনও সদৃশ র্যান্ডম পূর্ণসংখ্যার উত্পন্ন করে না। এই স্নিপেটের সুবিধা হ'ল আপনি এটিকে একটি অ্যারের তালিকা বরাদ্দ করতে পারেন এবং এলোমেলো আইটেমও তৈরি করতে পারেন।

কোনও সদৃশ র্যান্ডম জেনারেটর শ্রেণি নেই

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