র্যান্ডম এবং অর্ডারবাই ব্যবহার করা কি একটি ভাল শফল অ্যালগরিদম?


164

কোডিং হরর- এ আমি বিভিন্ন শ্যাফল আলগোরিদিম সম্পর্কে একটি নিবন্ধ পড়েছি । আমি দেখেছি যে কোথাও লোকেরা তালিকা বদলানোর জন্য এটি করেছে:

var r = new Random();
var shuffled = ordered.OrderBy(x => r.Next());

এটি কি একটি ভাল শ্যাফেল অ্যালগরিদম? এটি ঠিক কীভাবে কাজ করে? এটি কি এটি করার একটি গ্রহণযোগ্য উপায়?

উত্তর:


205

এটি আমার পছন্দ মতো বদলে যাওয়া নয়, বেশিরভাগ কারণেই এটি কোনও কারণ ছাড়াই এটি O (n লগ এন) হয় যখন কোনও ও (এন) স্থানান্তর কার্যকর করা সহজ হয়। প্রশ্নের উপাদানটি মূলত প্রতিটি উপাদানকে একটি এলোমেলো (আশাকরি অনন্য!) নম্বর দিয়ে তার পরে সেই সংখ্যা অনুসারে উপাদানগুলি অর্ডার করে "কাজ করে"।

আমি ফিশার-ইয়েটস সাফল্যের ডার্সটেনফিল্ডের বৈকল্পিকটি পছন্দ করি যা উপাদানগুলিকে অদলবদল করে।

একটি সাধারণ Shuffleএক্সটেনশন পদ্ধতি প্রয়োগ করা মূলত কলিং ToListবা ToArrayইনপুটটিতে ফিশার-ইয়েসের বিদ্যমান বাস্তবায়ন ব্যবহার করে। ( Randomজীবনকে আরও সুন্দর করে তোলার জন্য প্যারামিটার হিসাবে পাস করুন around) চারপাশে প্রচুর বাস্তবায়ন রয়েছে ... আমি সম্ভবত কোনও উত্তর পেয়েছি।

এই জাতীয় একটি এক্সটেনশন পদ্ধতি সম্পর্কে দুর্দান্ত জিনিসটি হ'ল পাঠকের কাছে এটি খুব স্পষ্ট হবে যে আপনি আসলে যা করার চেষ্টা করছেন।

সম্পাদনা: এখানে একটি সাধারণ বাস্তবায়ন (কোনও ত্রুটি যাচাইয়ের নয়!):

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    // Note i > 0 to avoid final pointless iteration
    for (int i = elements.Length-1; i > 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        int swapIndex = rng.Next(i + 1);
        T tmp = elements[i];
        elements[i] = elements[swapIndex];
        elements[swapIndex] = tmp;
    }
    // Lazily yield (avoiding aliasing issues etc)
    foreach (T element in elements)
    {
        yield return element;
    }
}

সম্পাদনা: নীচের পারফরম্যান্সের উপর দেওয়া মন্তব্যগুলি আমাকে মনে করিয়ে দিয়েছে যে উপাদানগুলি পরিবর্তন করার সাথে সাথে আমরা আসলে ফিরে আসতে পারি:

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    for (int i = elements.Length - 1; i >= 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        // ... except we don't really need to swap it fully, as we can
        // return it immediately, and afterwards it's irrelevant.
        int swapIndex = rng.Next(i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
    }
}

এটি এখন যতটা প্রয়োজন তেমন কাজ করবে।

মনে রাখবেন যে উভয় ক্ষেত্রেই Randomআপনার যেমন ব্যবহার করা হয়েছে তেমন সাবধানতা অবলম্বন করা উচিত :

  • Randomমোটামুটি একই সময়ে দুটি উদাহরণ তৈরি করা এলোমেলো সংখ্যার একই ক্রম উপার্জন করবে (যখন একই পদ্ধতিতে ব্যবহৃত হবে)
  • Random থ্রেড-নিরাপদ নয়।

আমার একটি নিবন্ধ রয়েছেRandom যার উপর এই সমস্যাগুলির উপর আরও বিশদে যায় এবং সমাধান সরবরাহ করে।


5
ঠিক আছে, ছোট, তবে গুরুত্বপূর্ণ বিষয়গুলির জন্য বাস্তবায়নগুলি আমি এখানে বলব স্ট্যাক ওভারফ্লোতে এখানে খুঁজে পাওয়া সর্বদা সুন্দর। সুতরাং হ্যাঁ দয়া করে, আপনি =) চান হলে
অশ্বারোহণে

9
জন - আপনার ফিশার-ইয়েটসের ব্যাখ্যা প্রশ্নে প্রদত্ত বাস্তবায়নের সমান (নিষ্পাপ সংস্করণ)। ডার্সটেনফিল্ড / নথ অ্যাসাইনমেন্ট দ্বারা নয়, ও (এন) অর্জন করে একটি হ্রাসমান সেট এবং অদলবদল থেকে নির্বাচন করে। এইভাবে নির্বাচিত এলোমেলো সংখ্যাটি পুনরাবৃত্তি হতে পারে এবং অ্যালগরিদমটি কেবল ও (এন) নেয়।
tvanfosson

8
আপনি সম্ভবত এই বিষয়ে আমার কাছ থেকে শুনে অসুস্থ হয়ে পড়ছেন, তবে আমি আমার ইউনিট পরীক্ষাগুলিতে একটি সামান্য সমস্যার মধ্যে পড়েছিলাম যার বিষয়ে আপনি সচেতন হতে চান। এলিমেন্টআট-এর সাথে এমন এক গণ্ডগোল রয়েছে যা এটি প্রতিবারই অবিশ্বাস্য ফলাফল দেয়, এটি বাড়িয়ে তোলে inv আমার পরীক্ষায় আমি এড়াতে চেক করার আগে ফলাফলটি বাস্তবায়িত করছি।
tvanfosson

3
@ ট্যানফোসন: মোটেই অসুস্থ নয় :) তবে হ্যাঁ, কলকারীদের সচেতন হওয়া উচিত যে এটি অলসভাবে মূল্যায়ন করা হয়েছে।
জন স্কিটে

4
একটু দেরী, কিন্তু দয়া করে মনে রাখবেন source.ToArray();আছে করতে হবে using System.Linq;একই ফাইলের মধ্যে। আপনি যদি তা না করেন তবে আপনি এই ত্রুটিটি পেয়েছেন:'System.Collections.Generic.IEnumerable<T>' does not contain a definition for 'ToArray' and no extension method 'ToArray' accepting a first argument of type 'System.Collections.Generic.IEnumerable<T>' could be found (are you missing a using directive or an assembly reference?)
পাওয়ারলর্ড

70

এটি জোন স্কিটির উত্তরের ভিত্তিতে তৈরি ।

এই উত্তরে, অ্যারে পরিবর্তন করা হয়, তারপরে ব্যবহার করে ফিরে আসে yield। নেট ফলাফলটি হ'ল অ্যারেটি পূর্বাভাসের সময়কালের জন্য মেমরিতে রাখা হয়, পাশাপাশি পুনরাবৃত্তির জন্য প্রয়োজনীয় বস্তুগুলি, এবং তবুও ব্যয়টি শুরুতেই হয় - ফলনটি মূলত একটি ফাঁকা লুপ।

এই অ্যালগরিদম গেমগুলিতে প্রচুর ব্যবহৃত হয়, যেখানে প্রথম তিনটি আইটেম বাছাই করা হয় এবং অন্যগুলি কেবল পরে পরে প্রয়োজন হয়। আমার পরামর্শটি yieldনাম্বারগুলিতে অদলবদল হওয়ার সাথে সাথেই। এটি পুনর্নির্মাণ ব্যয়কে ও (1) এ রাখার সময় (মূলত প্রতি পুনরাবৃত্তিতে 5 টি অপারেশন) রাখার সময় শুরুর ব্যয়টি হ্রাস করবে। মোট ব্যয় একই থাকবে, তবে এলোমেলো হওয়া নিজেই দ্রুত হবে। যে ক্ষেত্রে এটি বলা হয় collection.Shuffle().ToArray()তাত্ত্বিকভাবে এটি কোনও তাত্পর্যপূর্ণ করবে না, তবে পূর্বোক্ত ব্যবহারের ক্ষেত্রে এটি শুরুর গতি বাড়িয়ে তুলবে। এছাড়াও, এটি আপনার ক্ষেত্রে কেবল কয়েকটি অনন্য আইটেম প্রয়োজন এমন ক্ষেত্রে অ্যালগরিদমকে দরকারী করে তুলবে। উদাহরণস্বরূপ, যদি আপনাকে 52 টি ডেক থেকে তিনটি কার্ড বের করার প্রয়োজন হয়, আপনি কল করতে পারবেন deck.Shuffle().Take(3)এবং কেবল তিনটি স্ব্যাপ বদলে যাবে (যদিও পুরো অ্যারেটি প্রথমে অনুলিপি করতে হবে)।

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    // Note i > 0 to avoid final pointless iteration
    for (int i = elements.Length - 1; i > 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        int swapIndex = rng.Next(i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
        // we don't actually perform the swap, we can forget about the
        // swapped element because we already returned it.
    }

    // there is one item remaining that was not returned - we return it now
    yield return elements[0]; 
}

সেকি! এটি সম্ভবত উত্সের সমস্ত আইটেম ফিরিয়ে দেবে না। আপনি এনট্রিেশনগুলির জন্য অনন্য হয়ে এলোমেলো সংখ্যার উপর নির্ভর করতে পারবেন না।
পি ড্যাডি

2
চতুর! (এবং আমি এই 15 টি চরিত্রের জিনিসগুলিকে ঘৃণা করি ...)
v

@ পি বাবা: হু? বিশদ যত্ন?
সুইভিশ

1
অথবা আপনি <0>> = 0 এর সাথে প্রতিস্থাপন করতে পারেন এবং এটি করতে হবে না (যদিও অতিরিক্ত অতিরিক্ত আরএনজি হিট প্লাস রিডানডেন্ট অ্যাসাইনমেন্ট)
ফ্রাইগুই

4
সূত্রের ব্যয় হিসাবে স্টার্টআপ ব্যয় হ'ল (এন); টুআররে ();
ডেভ হিলিয়ার

8

স্কিটির এই উদ্ধৃতি থেকে শুরু:

এটি আমার পছন্দ মতো বদলে যাওয়া নয়, বেশিরভাগ কারণেই এটি কোনও কারণ ছাড়াই এটি O (n লগ এন) হয় যখন কোনও ও (এন) স্থানান্তর কার্যকর করা সহজ হয়। প্রশ্নের উপাদানটি মূলত প্রতিটি উপাদানকে একটি এলোমেলো ( আশাকরি অনন্য! ) নম্বর দিয়ে তার পরে সেই সংখ্যা অনুসারে উপাদানগুলি অর্ডার করে "কাজ করে" ।

আমি আশাবাদী অনন্য কারণ ব্যাখ্যা করার জন্য কিছুটা এগিয়ে যাব !

এখন, গণনার কাছ থেকে Oআর্ডার বাই :

এই পদ্ধতিটি একটি স্থিতিশীল বাছাই করে; তা হল, যদি দুটি উপাদানের কীগুলি সমান হয় তবে উপাদানগুলির ক্রম সংরক্ষণ করা হবে

এই অত্যন্ত গুরুত্বপূর্ণ! যদি দুটি উপাদান একই র্যান্ডম সংখ্যাটি "গ্রহণ" করে তবে কী ঘটে? এটি ঘটে যে তারা একই ক্রমে থাকে তবে তারা অ্যারেতে থাকে। এখন, এটি হওয়ার সম্ভাবনা কী? ঠিক গণনা করা কঠিন, তবে জন্মদিনের সমস্যাটিও হ'ল ঠিক এই সমস্যা।

এখন, এটা কি বাস্তব? এটা সত্যি?

সর্বদা হিসাবে, যখন সন্দেহ হয়, প্রোগ্রামের কয়েকটি লাইন লিখুন: http://pastebin.com/5CDnUxPG

কোডের এই সামান্য ব্লকটি ফিশার-ইয়েটস অ্যালগরিদমকে পিছনে সম্পন্ন করে ফিশার-ইয়েটস অ্যালগরিদম ব্যবহার করে নির্দিষ্ট সময়ের জন্য 3 টি উপাদানের একটি অ্যারেরকে বদলে দেয় ( উইকির পৃষ্ঠায় দুটি সিউডো কোড অ্যালগোরিদম রয়েছে ... তারা সমতুল্য উত্পাদন করে ফলাফল, তবে একটি প্রথম থেকে শেষ এলিমেন্টে করা হয়, অন্যটি শেষ থেকে প্রথম উপাদান পর্যন্ত করা হয়), http://blog.codinghorror.com/the-danger-of-naivete/ এর মজাদার ভুল অ্যালগরিদম এবং ব্যবহার করে .OrderBy(x => r.Next())এবং .OrderBy(x => r.Next(someValue))

এখন, র্যান্ডম.নেক্সট হ'ল

একটি 32-বিট স্বাক্ষরিত পূর্ণসংখ্যা যা 0 এর চেয়ে বড় বা সমান এবং ম্যাক্সভ্যালু থেকে কম।

সুতরাং এটি সমতুল্য

OrderBy(x => r.Next(int.MaxValue))

এই সমস্যাটি বিদ্যমান কিনা তা পরীক্ষা করার জন্য, আমরা অ্যারেটি বড় করতে পারি (খুব ধীরে ধীরে কিছু) বা এলোমেলো সংখ্যা জেনারেটরের সর্বাধিক মান হ্রাস করতে পারি ( int.MaxValue"বিশেষ" সংখ্যা নয় ... এটি কেবল একটি খুব বড় সংখ্যা)। শেষ পর্যন্ত, যদি অ্যালগরিদম স্থিতিশীলতার দ্বারা পক্ষপাতী না হয় OrderBy, তবে মানগুলির যে কোনও পরিসীমা একই ফলাফল দেয়।

প্রোগ্রামটি পরে 1 ... 4096 পরিসরে কিছু মান পরীক্ষা করে। ফলাফলটির দিকে তাকালে এটি পুরোপুরি স্পষ্ট যে কম মানগুলির জন্য (<128), অ্যালগরিদমটি খুব পক্ষপাতদুষ্ট (4-8%)। 3 টি মান সহ আপনার কমপক্ষে প্রয়োজন r.Next(1024)। আপনি যদি অ্যারেটিকে বড় (4 বা 5) করেন তবে r.Next(1024)তা যথেষ্ট নয়। আমি বদলে যাওয়া এবং গণিতে বিশেষজ্ঞ নই, তবে আমি মনে করি অ্যারের প্রতিটি দৈর্ঘ্যের অতিরিক্ত দৈর্ঘ্যের জন্য আপনার সর্বাধিক মানের জন্য 2 অতিরিক্ত বিট প্রয়োজন (কারণ জন্মদিনের প্যারাডক্সটি স্কয়ারটি (সংখ্যাসমূহ) এর সাথে সংযুক্ত, তাই) যদি সর্বোচ্চ মান 2 ^ 31 হয় তবে আমি বলব যে আপনি 2 ^ 12/2 ^ 13 বিট (4096-8192 উপাদান) পর্যন্ত অ্যারে বাছাই করতে সক্ষম হবেন


ভালভাবে বলা হয়েছে, এবং নিখুঁতভাবে মূল প্রশ্নটি নিয়ে একটি সমস্যা প্রদর্শন করে। এটি জনের উত্তরের সাথে একীভূত করা উচিত।
TheSoftwareJedi

6

এটি বেশিরভাগ উদ্দেশ্যেই সম্ভবত ঠিক আছে এবং প্রায়শই এটি সত্যিকারের এলোমেলো বিতরণ উত্পন্ন করে (র্যান্ডম.নেক্সট () দুটি অভিন্ন র্যান্ডম পূর্ণসংখ্যার উত্পাদন ব্যতীত)।

এটি সিরিজের প্রতিটি উপাদানকে এলোমেলো পূর্ণসংখ্যার স্থির করে, তারপরে এই সংখ্যার দ্বারা ক্রমটি অর্ডার করে কাজ করে।

এটি 99.9% অ্যাপ্লিকেশনগুলির জন্য সম্পূর্ণরূপে গ্রহণযোগ্য (যদি না আপনি উপরের প্রান্তের কেসটি হ্যান্ডেল করার প্রয়োজন না করেন)। এছাড়াও, রানটাইমের সময় স্কিটের আপত্তিটি বৈধ, সুতরাং আপনি যদি একটি দীর্ঘ তালিকাটি বদলে ফেলেন তবে আপনি এটি ব্যবহার করতে নাও চান।


4

এটি এর আগেও বহুবার উঠে এসেছে। স্ট্যাকওভারফ্লোতে ফিশার-ইয়েটস অনুসন্ধান করুন।

আমি এই অ্যালগরিদমের জন্য একটি সি # কোড নমুনা লিখেছি। আপনি যদি পছন্দ করেন তবে আপনি এটি অন্য কোনও ধরণের পরামিতি করতে পারেন can

static public class FisherYates
{
        //      Based on Java code from wikipedia:
        //      http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
        static public void Shuffle(int[] deck)
        {
                Random r = new Random();
                for (int n = deck.Length - 1; n > 0; --n)
                {
                        int k = r.Next(n+1);
                        int temp = deck[n];
                        deck[n] = deck[k];
                        deck[k] = temp;
                }
        }
}

2
আপনার Randomমতো স্ট্যাটিক ভেরিয়েবল হিসাবে ব্যবহার করা উচিত নয় - Randomথ্রেড-নিরাপদ নয়। দেখুন csharpindepth.com/Articles/Chapter12/Random.aspx
জন স্কিট

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

1
এর অর্থ হ'ল এটি ওপি'র পদ্ধতির চেয়ে "কম ভুল"। এর অর্থ এই নয় যে এটি কোনও কোড যা বোঝা ছাড়াই ব্যবহার করা উচিত যে এটি মাল্টি-থ্রেড প্রসঙ্গে নিরাপদে ব্যবহার করা যাবে না ... যা এমন কিছু যা আপনি উল্লেখ করেন নি। স্থিতিশীল সদস্যরা একাধিক থ্রেড থেকে নিরাপদে ব্যবহার করতে পারবেন এমন একটি যুক্তিসঙ্গত প্রত্যাশা রয়েছে
জন স্কিটি

@ জোন স্কিটি: অবশ্যই, আমি এটি পরিবর্তন করতে পারি। সম্পন্ন. আমি মনে করি যে সাড়ে তিন বছর আগে কোনও প্রশ্নের উত্তরে এসে বলেছিল, "এটি ভুল কারণ এটি মাল্টিথ্রেডেড ইউজ-কেস পরিচালনা করে না" যখন ওপি কখনই অ্যালগরিদমের চেয়ে বেশি কিছু বলেনি। আমার উত্তরগুলি বছরের পর বছর পর্যালোচনা করুন। প্রায়শই আমি ওপিগুলিকে উত্তর দিয়েছি যা বর্ণিত প্রয়োজনীয়তার বাইরে চলে গেছে। আমি এর জন্য সমালোচিত হয়েছি। যদিও আমি ওপিগুলিকে এমন সব উত্তর ব্যবহারের উপযুক্ত উত্তর পাব তা আশা করি না।
হুগড্রাউন

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

3

আপনি যদি পারফরম্যান্সে খুব বেশি চিন্তিত না হন তবে একটি ভাল শাফলিং অ্যালগরিদমের মতো মনে হচ্ছে। আমি কেবল যে সমস্যাটি চিহ্নিত করতে পারি তা হ'ল এটির আচরণটি নিয়ন্ত্রণযোগ্য নয়, তাই এটি পরীক্ষা করতে আপনার অসুবিধা হতে পারে।

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


3

আমি জোন স্কিটির উত্তর পুরোপুরি সন্তোষজনক বলে পেয়েছি তবে আমার ক্লায়েন্টের রোবো-স্ক্যানার এর কোনও উদাহরণ জানাবে Random সুরক্ষা ত্রুটি হিসাবে । তাই আমি এটিকে বদলে ফেললাম System.Security.Cryptography.RNGCryptoServiceProvider। বোনাস হিসাবে, এটি উল্লিখিত যে থ্রেড-সুরক্ষা ইস্যুটি ঠিক করে es অন্যদিকে RNGCryptoServiceProviderব্যবহারের চেয়ে 300x ধীর হিসাবে পরিমাপ করা হয়েছেRandom

ব্যবহার:

using (var rng = new RNGCryptoServiceProvider())
{
    var data = new byte[4];
    yourCollection = yourCollection.Shuffle(rng, data);
}

পদ্ধতি:

/// <summary>
/// Shuffles the elements of a sequence randomly.
/// </summary>
/// <param name="source">A sequence of values to shuffle.</param>
/// <param name="rng">An instance of a random number generator.</param>
/// <param name="data">A placeholder to generate random bytes into.</param>
/// <returns>A sequence whose elements are shuffled randomly.</returns>
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, RNGCryptoServiceProvider rng, byte[] data)
{
    var elements = source.ToArray();
    for (int i = elements.Length - 1; i >= 0; i--)
    {
        rng.GetBytes(data);
        var swapIndex = BitConverter.ToUInt32(data, 0) % (i + 1);
        yield return elements[swapIndex];
        elements[swapIndex] = elements[i];
    }
}

3

একটি অ্যালগরিদম খুঁজছেন? আপনি আমার ShuffleListক্লাস ব্যবহার করতে পারেন :

class ShuffleList<T> : List<T>
{
    public void Shuffle()
    {
        Random random = new Random();
        for (int count = Count; count > 0; count--)
        {
            int i = random.Next(count);
            Add(this[i]);
            RemoveAt(i);
        }
    }
}

তারপরে, এটি এর মতো ব্যবহার করুন:

ShuffleList<int> list = new ShuffleList<int>();
// Add elements to your list.
list.Shuffle();

এটা কিভাবে কাজ করে?

আসুন 5 প্রথম পূর্ণসংখ্যার প্রাথমিক সাজানো তালিকা নেওয়া যাক: { 0, 1, 2, 3, 4 }

পদ্ধতিটি উপাদানের নুবার গণনা করে শুরু হয় এবং এটি কল করে count। তারপরে, countপ্রতিটি পদক্ষেপে হ্রাসের সাথে , এটি 0এবং এর মধ্যে একটি এলোমেলো সংখ্যা নেয়count এবং তালিকার শেষে এটা চলে আসে।

নিম্নলিখিত ধাপে ধাপে উদাহরণে, যে আইটেমগুলি স্থানান্তরিত হতে পারে সেগুলি তাত্পর্যপূর্ণ , নির্বাচিত আইটেমটি সাহসী :

0 1 2 3 4
0 1 2 3 4
0 1 2 4 3
0 1 2 4 3
1 2 4 3 0
1 2 4 3 0
1 2 3 0 4
1 2 3 0 4
2 3 0 4 1
2 3 0 4 1
3 0 4 1 2


এটি ও (এন) নয়। অপসারণ একা হ'ল ও (এন)।
পাপারাজ্জো

হুম, মনে হচ্ছে তুমি ঠিক বলেছ, আমার খারাপ! আমি সেই অংশটি সরিয়ে ফেলব।
স্টিভড্রোজ

1

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


1

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

পাশা-ও-Matic

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


1

আমি বলব যে এখানে অনেক উত্তর যেমন "তালিকার প্রতিটি মানের জন্য একটি নতুন এলোমেলো মান উত্পন্ন করে এই অ্যালগরিদম পরিবর্তন হয়ে যায়, তারপরে সেই র্যান্ডম মানগুলির দ্বারা তালিকার ক্রম" খুব ভুল হতে পারে!

আমি মনে করি যে এটি উত্স সংগ্রহের প্রতিটি উপাদানকে এলোমেলো মান দেয় না। পরিবর্তে কুইকোর্টের মতো চলমান অ্যালগরিদম হতে পারে যা তুলনামূলক ফাংশনটিকে প্রায় n লগ এন বার বলবে। কিছু ধরণের অ্যালগরিটিম সত্যই এই তুলনা-ফাংশন স্থিতিশীল এবং সর্বদা একই ফলাফল ফিরে প্রত্যাশা করে!

এটি কি হতে পারে না যে আইইনিউমারেবলস্পটরের প্রতিটি অ্যালগরিদম ধাপের জন্য কুইকোর্টের জন্য একটি তুলনা ফাংশন কল করে এবং প্রতিটি সময় x => r.Next()উভয় পরামিতির জন্য ফাংশনকে এই ক্যাশে না করে কল করে !

সেক্ষেত্রে আপনি সম্ভবত সাজানোর অ্যালগরিদমকে বিশৃঙ্খলা করতে পারেন এবং এটি অ্যালগরিদমটি যে প্রত্যাশাটি তৈরি করছে তার চেয়ে অনেক খারাপ করতে পারে। অবশ্যই, এটি শেষ পর্যন্ত স্থিতিশীল হয়ে উঠবে এবং কিছু ফিরিয়ে দেবে।

আমি পরে এটি একটি নতুন "নেক্সট" ফাংশনের ভিতরে ডিবাগিং আউটপুট রেখে পরীক্ষা করে দেখতে পারি যাতে কী ঘটে see রিফ্লেক্টরে আমি তাত্ক্ষণিকভাবে এটি কীভাবে কাজ করে তা জানতে পারি না।


1
এটি কেস নয়: অভ্যন্তরীণ ওভাররাইড শূন্য কমম্পিউটকিস (টিলেট [] উপাদানগুলি, ইন্ট গণনা); ঘোষণার ধরণ: System.Linq.EnumerableSorter <TElement, TKey> সমাবেশ: System.Core, সংস্করণ = 3.5.0.0 এই ফাংশনটি সমস্ত কীগুলির সাহায্যে প্রথমে একটি অ্যারে তৈরি করে যা কুইকোর্টটি সাজানোর আগে
ক্রিশ্চিয়ান

এটি জেনে রাখা ভাল - এখনও একটি বাস্তবায়ন বিশদটি যদিও, যা ভবিষ্যতের সংস্করণগুলিতে সম্ভবত ধারণা পরিবর্তন করতে পারে!
ব্লারগার্ড

-5

সমস্ত নতুন থ্রেড এবং ক্যাশে প্রতি নতুন পরীক্ষার সাথে সাফ কোড সহ চালুর সময়,

প্রথম অসফল কোড। এটি লিনকিউপ্যাডে চলে। আপনি যদি এই কোডটি পরীক্ষা করে অনুসরণ করেন।

Stopwatch st = new Stopwatch();
st.Start();
var r = new Random();
List<string[]> list = new List<string[]>();
list.Add(new String[] {"1","X"});
list.Add(new String[] {"2","A"});
list.Add(new String[] {"3","B"});
list.Add(new String[] {"4","C"});
list.Add(new String[] {"5","D"});
list.Add(new String[] {"6","E"});

//list.OrderBy (l => r.Next()).Dump();
list.OrderBy (l => Guid.NewGuid()).Dump();
st.Stop();
Console.WriteLine(st.Elapsed.TotalMilliseconds);

list.OrderBy (x => r.Next ()) 38.6528 এমএস ব্যবহার করে

list.OrderBy (x => গাইড। নিউগুইড ()) 36.7634 এমএস ব্যবহার করে (এটি এমএসডিএন থেকে প্রস্তাবিত))

দ্বিতীয়বারের পরে উভয় একই সময় ব্যবহার করে।

সম্পাদনা করুন: ইন্টেল কোর আই 7 4@2.1GHz, রাম 8 জিবি ডিডিআর 3 @ 1600, এইচডিডি সাতা 5200 আরপিএমের সাথে টেস্ট কোড [তথ্য: www.rodbox.com/s/pbtmh5s9lw285kp/data]

using System;
using System.Runtime;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Threading;

namespace Algorithm
{
    class Program
    {
        public static void Main(string[] args)
        {
            try {
                int i = 0;
                int limit = 10;
                var result = GetTestRandomSort(limit);
                foreach (var element in result) {
                    Console.WriteLine();
                    Console.WriteLine("time {0}: {1} ms", ++i, element);
                }
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            } finally {
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey(true);
            }
        }

        public static IEnumerable<double> GetTestRandomSort(int limit)
        {
            for (int i = 0; i < 5; i++) {
                string path = null, temp = null;
                Stopwatch st = null;
                StreamReader sr = null;
                int? count = null;
                List<string> list = null;
                Random r = null;

                GC.Collect();
                GC.WaitForPendingFinalizers();
                Thread.Sleep(5000);

                st = Stopwatch.StartNew();
                #region Import Input Data
                path = Environment.CurrentDirectory + "\\data";
                list = new List<string>();
                sr = new StreamReader(path);
                count = 0;
                while (count < limit && (temp = sr.ReadLine()) != null) {
//                  Console.WriteLine(temp);
                    list.Add(temp);
                    count++;
                }
                sr.Close();
                #endregion

//              Console.WriteLine("--------------Random--------------");
//              #region Sort by Random with OrderBy(random.Next())
//              r = new Random();
//              list = list.OrderBy(l => r.Next()).ToList();
//              #endregion

//              #region Sort by Random with OrderBy(Guid)
//              list = list.OrderBy(l => Guid.NewGuid()).ToList();
//              #endregion

//              #region Sort by Random with Parallel and OrderBy(random.Next())
//              r = new Random();
//              list = list.AsParallel().OrderBy(l => r.Next()).ToList();
//              #endregion

//              #region Sort by Random with Parallel OrderBy(Guid)
//              list = list.AsParallel().OrderBy(l => Guid.NewGuid()).ToList();
//              #endregion

//              #region Sort by Random with User-Defined Shuffle Method
//              r = new Random();
//              list = list.Shuffle(r).ToList();
//              #endregion

//              #region Sort by Random with Parallel User-Defined Shuffle Method
//              r = new Random();
//              list = list.AsParallel().Shuffle(r).ToList();
//              #endregion

                // Result
//              
                st.Stop();
                yield return st.Elapsed.TotalMilliseconds;
                foreach (var element in list) {
                Console.WriteLine(element);
            }
            }

        }
    }
}

ফলাফলের বর্ণনা: https://www.DPboxbox.com/s/9dw9wl259dfs04g/ResultDescription.PNG
ফলাফল স্ট্যাটাস: https://www.roidbox.com/s/ewq5ybtsvesme4d/ResultStat.PNG

উপসংহার:
ধরে নিন: লিনকিউ অর্ডারবাই (r.Next ()) এবং অর্ডারবাই (Guid.NewGuid ()) প্রথম সমাধানে ব্যবহারকারী-সংজ্ঞায়িত সাফল্যের পদ্ধতির চেয়ে খারাপ নয়।

উত্তর: এগুলি দ্বন্দ্ব।


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

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

কোডটির কার্যকারিতা পরিমাপ করার বিন্দুটি কী যা সমস্যার সমাধান করে না? উভয় কার্যকর যে দুটি সমাধানের মধ্যে পারফরম্যান্স শুধুমাত্র বিবেচনা করা হয় । আপনার যখন কাজের সমাধান হয় তখন আপনি সেগুলি তুলনা শুরু করতে পারেন ।
26:40

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

এটি খুব সাধারণ সোজাসাপ্টা বদলানো অ্যালগরিদমের চেয়ে লক্ষণীয়ভাবে কম দক্ষ, তবে আবারও, কর্মক্ষমতাটি অপ্রাসঙ্গিক । তারা কম পারফরম্যান্ট হওয়া ছাড়াও নির্ভরযোগ্যভাবে ডেটা বদল করছে না।
পরিবেশন করুন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.