শিফাল করার জন্য জাভাস্ক্রিপ্ট অ্যারে.সোর্ট () পদ্ধতিটি ব্যবহার করা কি সঠিক?


126

আমি কাউকে তার জাভাস্ক্রিপ্ট কোড দিয়ে সাহায্য করছিলাম এবং আমার চোখ এমন একটি বিভাগে ধরা পড়েছিল যা দেখতে দেখতে:

function randOrd(){
  return (Math.round(Math.random())-0.5);
}
coords.sort(randOrd);
alert(coords);

যদিও আমার প্রথমটি ছিল: আরে, এটি সম্ভবত কাজ করতে পারে না! তবে আমি কিছু পরীক্ষা-নিরীক্ষা করে দেখেছি যে এটি অবশ্যই কমপক্ষে সুন্দর এলোমেলো ফলাফল প্রদান করেছে।

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

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

কিন্তু তুমি কি ভাবছ?

এবং অন্য প্রশ্ন হিসাবে ... আমি এখন গিয়ে কীভাবে পরিমাপ করব যে এলোমেলো কৌশলটির ফলাফল কতটা এলোমেলো?

আপডেট: আমি কিছু পরিমাপ করেছি এবং উত্তরগুলির একটি হিসাবে নীচে ফলাফল পোস্ট করেছি।


কেবলমাত্র লক্ষ করা যায় যে ফলাফলটি কেবলমাত্র সাইন গণনাটি
অকার্যকর

2
" আমি দেখতে পেয়েছি যে এটি দুর্দান্ত এলোমেলো ফলাফল সরবরাহ করেছে বলে মনে হচ্ছে " "- সত্যিই ???
বার্গি

উত্তর:


109

এটি কখনই আমার পছন্দমতো বদলে যাওয়া নয়, আংশিক কারণ এটি যেমন আপনি বলছেন তেমন বাস্তবায়ন-নির্দিষ্ট। বিশেষত, আমি মনে করি মনে হয় যে জাভা বা .NET (কোনটি নিশ্চিত নয়) এর মধ্যে স্ট্যান্ডার্ড লাইব্রেরি বাছাই করা আপনি প্রায়শই সনাক্ত করতে পারেন যদি আপনি কিছু উপাদানগুলির মধ্যে একটি অসঙ্গতিপূর্ণ তুলনা শেষ করেন (যেমন আপনি প্রথমে দাবি A < Bএবং B < Cতারপর, তবে C < A)।

এটি আপনার প্রকৃত প্রয়োজনের চেয়ে আরও জটিল (মৃত্যুদন্ডের সময় বিবেচনা করে) পরিবর্তিত হয়ে শেষ হয়।

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

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

এই পদ্ধতির একটি ফিশার-ইয়েটস সাফল্য বলা হয় ।

আমি একবারে এই শ্যাফেলটি কোড আপ করার জন্য এবং আইটেমগুলিকে বদলাতে আপনার যে কোনও জায়গায় এটি পুনরায় ব্যবহার করার পক্ষে সর্বোত্তম অনুশীলন হিসাবে বিবেচনা করব। তারপরে নির্ভরযোগ্যতা বা জটিলতার ক্ষেত্রে আপনার বাছাইয়ের প্রয়োগের বিষয়ে চিন্তা করার দরকার নেই। এটি কোডের কয়েকটি লাইন (যা আমি জাভাস্ক্রিপ্টে চেষ্টা করব না!)

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


5
রেমন্ড চেন গুরুত্বের বিষয়ে গভীরভাবে যান যে তুলনা ফাংশনগুলি নিয়মগুলি অনুসরণ করে: ব্লগস.এমএসডিএন
জেসন ক্রেসোভাটি

1
যদি আমার যুক্তিটি সঠিক হয়, তবে সাজানো সংস্করণটি 'জেনুইন' সাফল্য তৈরি করে না !
ক্রিস্টোফ

@ ক্রিসটফ: এটির কথা চিন্তা করে, এমনকি ফিশার-ইয়েটস কেবলমাত্র "নিখুঁত" বিতরণ দিবে যদি র‌্যান্ড (এক্স) এর পরিধিটি ঠিক তারও বেশি হওয়ার গ্যারান্টিযুক্ত থাকে । আরএনজি-র জন্য কিছু এক্সের জন্য সাধারণত 2 ^ x সম্ভাব্য রাজ্যগুলি দেওয়া থাকে বলে আমি মনে করি না এটি র্যান্ড (3) এর জন্যও ঠিক হবে ।
জন স্কিটি

@ জোন: তবে ফিশার-ইয়েটস 2^xপ্রতিটি অ্যারে সূচকের জন্য রাজ্য তৈরি করবে , অর্থাৎ মোট 2 ^ (xn) রাজ্য হবে, যা 2 ডিগ্রি সেন্টিগ্রেড থেকে কিছুটা বড় হওয়া উচিত - বিবরণের জন্য আমার সম্পাদিত উত্তরটি দেখুন
ক্রিস্টোফ

@ ক্রিসটফ: আমি নিজের সম্পর্কে সঠিকভাবে ব্যাখ্যা নাও করতে পারি। মনে করুন আপনার কাছে মাত্র 3 টি উপাদান রয়েছে। আপনি প্রথমটি এলোমেলোভাবে বেছে নিন, সর্বোপরি 3.. সম্পূর্ণ ইউনিফর্ম বিতরণ পেতে , আপনাকে সম্পূর্ণ অভিন্নভাবে পরিসরে [0,3) এলোমেলো সংখ্যা বেছে নিতে সক্ষম হতে হবে - এবং পিআরএনজির 2 ^ n থাকলে সম্ভাব্য রাজ্যগুলি, আপনি এটি করতে পারবেন না - এক বা দু'জনের সম্ভাবনার কিছুটা কম হওয়ার সম্ভাবনা থাকে।
জন স্কিটি

118

জনের ইতিমধ্যে তত্ত্বটি আবৃত করার পরে , এখানে একটি বাস্তবায়ন দেওয়া হল:

function shuffle(array) {
    var tmp, current, top = array.length;

    if(top) while(--top) {
        current = Math.floor(Math.random() * (top + 1));
        tmp = array[current];
        array[current] = array[top];
        array[top] = tmp;
    }

    return array;
}

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


বোবোবোবির উত্তরের মন্তব্যে , আমি বলেছি যে প্রশ্নে থাকা অ্যালগরিদম সমানভাবে বিতরণ করা সম্ভাবনাগুলি তৈরি করতে পারে না (বাস্তবায়নের উপর নির্ভর করে sort())।

আমার যুক্তি এই রেখাগুলি বরাবর যায়: বাছাই অ্যালগরিদমের জন্য একটি নির্দিষ্ট সংখ্যক cতুলনা প্রয়োজন যেমন c = n(n-1)/2বুদবুদোর জন্য। আমাদের এলোমেলো তুলনা ফাংশন প্রতিটি তুলনার ফলাফলকে 2^c সমানভাবে সম্ভাব্য করে তোলে, তেমনি সমান সম্ভাব্য ফলাফলও রয়েছে। এখন, প্রতিটি ফলাফল n!অ্যারের এন্ট্রিগুলির যে কোনও একের অনুক্রমের সাথে সামঞ্জস্য করতে হবে , যা সাধারণ ক্ষেত্রে এমনকি এমনকি বিতরণকে অসম্ভব করে তোলে। (এটি একটি সরলকরণ, কারণ তুলনামূলক প্রকৃত সংখ্যা নির্ধারিত হওয়া ইনপুট অ্যারের উপর নির্ভর করে, তবে দৃ the়তা এখনও রাখা উচিত))

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

Math.random()পরিসীমাতে একটি সিডো-এলোমেলো সংখ্যা তৈরি করে [0;1[। জেএস ডাবল-স্পষ্টতা ভাসমান পয়েন্টের মানগুলি ব্যবহার করে, এটি 2^xসম্ভাব্য মানগুলির সাথে মিলে যায় যেখানে 52 ≤ x ≤ 63(আমি প্রকৃত সংখ্যাটি খুঁজে পেতে খুব অলস)। ব্যবহার করে উত্পন্ন সম্ভাব্যতা বিতরণ Math.random()ভাল আচরণ বন্ধ করবে যদি পারমাণবিক ঘটনার সংখ্যা একই মাত্রার মাত্রায় হয়।

ফিশার-ইয়েটস ব্যবহার করার সময়, প্রাসঙ্গিক প্যারামিটারটি অ্যারের আকার হয়, যা 2^52ব্যবহারিক সীমাবদ্ধতার কারণে কখনই যোগাযোগ করা উচিত নয় ।

এলোমেলো তুলনা ফাংশনটি বাছাই করার সময়, ফাংশনটি মূলত শুধুমাত্র যত্ন করে যদি রিটার্নের মানটি ইতিবাচক বা নেতিবাচক হয়, তাই এটি কখনও সমস্যা হবে না। তবে একটি অনুরূপটি রয়েছে: কারণ তুলনা ফাংশনটি ভাল আচরণ করা হয়েছে, 2^cসম্ভাব্য ফলাফলগুলি যেমন বলা হয়েছে, তেমনি সমান সম্ভাবনাও রয়েছে। যদি c ~ n log nতবে 2^c ~ n^(a·n)কোথায় a = const, যা এটি কমপক্ষে সম্ভব করে তোলে যা 2^cএকই পরিমাণে (বা তার চেয়েও কম) n!এবং এইভাবে অসম বন্টনের দিকে পরিচালিত করে, এমনকি যদি সাজানোর অ্যালগরিদম যেখানে সমানভাবে অনুক্রমের উপরে মানচিত্র করা যায়। এর যদি কোনও ব্যবহারিক প্রভাব থাকে তবে তা আমার বাইরে।

আসল সমস্যাটি হ'ল বাছাই করা অ্যালগরিদমগুলি সমানভাবে অনুমোদনে মানচিত্রের গ্যারান্টিযুক্ত নয়। এটি দেখতে সহজ যে Mergesort এটি প্রতিসাম্য হিসাবে কাজ করে তবে বুবল্বোর্ট বা আরও গুরুত্বপূর্ণভাবে কুইকসোর্ট বা হিপসোর্টের মতো কিছু সম্পর্কে যুক্তিযুক্ত নয়।


নীচের লাইন: যতক্ষণ sort()Mergesort ব্যবহার করা হয় ততক্ষণ আপনি কোণার কেস বাদে যথাযথভাবে নিরাপদ হওয়া উচিত (কমপক্ষে আমি আশা করি 2^c ≤ n!এটি একটি কোণার কেস), যদি না হয় তবে সমস্ত বেট বন্ধ রয়েছে।


বাস্তবায়নের জন্য ধন্যবাদ। এটি নির্লজ্জভাবে দ্রুত! বিশেষ করে সেই সময়ের মধ্যে আমি নিজের দ্বারা লিখেছিলাম যে ধীর বিড়ম্বনার সাথে তুলনা করুন।
রিনি সরসু

1
আপনি যদি আন্ডারস্কোর.জেএস লাইব্রেরিটি ব্যবহার করছেন তবে উপরের ফিশার-ইয়েটস সাফাল
স্টিভ

এর জন্য আপনাকে অনেক ধন্যবাদ, আপনার এবং জনস উত্তরের সংমিশ্রণটি আমাকে এমন একটি সমস্যা সমাধান করতে সহায়তা করেছে যা আমি এবং সহকর্মী প্রায় 4 ঘন্টা একত্রে কাটিয়েছি! আমাদের কাছে ওপিতে অনুরূপ পদ্ধতি ছিল তবে এটি দেখতে পেল যে র্যান্ডমাইজেশনটি খুব ঝুঁকিপূর্ণ ছিল, তাই আমরা আপনার পদ্ধতিটি গ্রহণ করেছি এবং কিছুটা jquery এর সাথে কাজ করার জন্য কিছুটা চিত্রের স্লাইডে স্লাইডারের জন্য স্লাইডারের জন্য কাজ করতে কিছুটা পরিবর্তন করেছি some দুর্দান্ত র্যান্ডমাইজেশন।
হ্যালো ওয়ার্ল্ড

16

আমি এলোমেলো সাজানোর ফলাফলগুলি কতটা এলোমেলো করে তার কিছু পরিমাপ করেছি ...

আমার কৌশলটি ছিল একটি ছোট অ্যারে [1,2,3,4] নেওয়া এবং এর সমস্ত (4! = 24) অনুমান তৈরি করা। তারপরে আমি অ্যারে শফলিং ফাংশনটি প্রচুর পরিমাণে প্রয়োগ করব এবং প্রতিটি ক্রমান্বয়ে কতবার উত্পন্ন হয় তা গণনা করব। একটি ভাল শিফলিং অ্যালগরিটম ফলাফলগুলি সমস্ত আদেশের উপর সমানভাবে বিতরণ করত, যখন কোনও খারাপ ফলাফল সেই অভিন্ন ফলাফল তৈরি করে না।

ফায়ারফক্স, অপেরা, ক্রোম, আই 6/7/8 এ পরীক্ষিত নীচের কোডটি ব্যবহার করে।

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

সম্পাদনা: এই পরীক্ষাটি এলোমেলোভাবে বা এর অভাবের সাথে সঠিকভাবে মাপা যায় নি। আমি পোস্ট করা অন্যান্য উত্তর দেখুন।

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

// ক্রিশফের পোস্ট করা এলোমেলো ফাংশন।
var shuffle = ফাংশন (অ্যারে) {
    var tmp, বর্তমান, শীর্ষ = অ্যারে. দৈর্ঘ্য;

    যদি (শীর্ষ) (যখন শীর্ষে) {
        কারেন্ট = ম্যাথ.ফ্লুর (ম্যাথ.র্যান্ডম () * (শীর্ষ + 1));
        tmp = অ্যারে [কারেন্ট];
        অ্যারে [কারেন্ট] = অ্যারে [শীর্ষ];
        অ্যারে [শীর্ষ] = টিএমপি;
    }

    রিটার্ন অ্যারে;
};

// এলোমেলো বাছাই ফাংশন
var rnd = ফাংশন () {
  রিটার্ন ম্যাথ.উইন্ড (ম্যাথআর্যান্ডম ()) - ০.৫;
};
var র্যান্ডসোর্ট = ফাংশন (এ) {
  রিটার্ন A.sort (rnd);
};

var অনুগমন = ফাংশন (এ)
  যদি (উঃ দৈর্ঘ্য == 1) {
    ফিরে [এ];
  }
  অন্য {
    var perms = [];
    (var i = 0; i <দৈর্ঘ্য; i ++) এর জন্য {
      var x = এ্লাইস (i, i + 1);
      var xs = A.slice (0, i) .ccat (A.slice (i + 1));
      var subperms = ক্রমবর্ধমান (xs);
      (var j = 0; j <subperms.length; j ++) এর জন্য {
        perms.push (x.concat (subperms [ঞ]));
      }
    }
    ফেরত পার্সস;
  }
};

var পরীক্ষা = ফাংশন (এ, পুনরাবৃত্তি, ফানক) {
  // init ক্রম
  var stats = {};
  var perms = ক্রমবর্ধমান (A);
  (ভারে আমি পার্মে) for
    পরিসংখ্যান ["" + পারমস [i]] = 0;
  }

  // বহুবার পরিবর্তন এবং পরিসংখ্যান সংগ্রহ
  var start = নতুন তারিখ ();
  (var i = 0; i <পুনরাবৃত্তি; i ++) for
    var shuffled = ফানক (এ);
    পরিসংখ্যান [ "," + এলোমেলো] ++,;
  }
  var end = নতুন তারিখ ();

  // ফর্ম্যাট ফলাফল
  var arr = [];
  (পরিসংখ্যানগুলিতে আমি) for
    arr.push (i + "" + পরিসংখ্যান [i]);
  }
  ফিরে আসুন
};

সতর্কতা ("এলোমেলো বাছাই:" + পরীক্ষা ([1,2,3,4], 100000, র্যান্ডসোর্ট));
সতর্কতা ("বদলান:" + পরীক্ষা ([1,2,3,4], 100000, বদল));

11

মজার বিষয় হল, মাইক্রোসফ্ট তাদের পিক-র্যান্ডম-ব্রাউজার-পৃষ্ঠাতে একই কৌশলটি ব্যবহার করেছিল

তারা কিছুটা আলাদা তুলনা ফাংশন ব্যবহার করেছে:

function RandomSort(a,b) {
    return (0.5 - Math.random());
}

আমার কাছে প্রায় দেখতে একই রকম, তবে এটি এতটা এলোমেলো নয় ...

সুতরাং আমি আবার লিখিত নিবন্ধে ব্যবহৃত একই পদ্ধতিটি দিয়ে আবার কিছু পরীক্ষার তৈরি করেছি এবং প্রকৃতপক্ষে - দেখা গেল যে এলোমেলো-বাছাই-পদ্ধতিতে ত্রুটিযুক্ত ফলাফল এসেছে। নতুন পরীক্ষার কোড এখানে:

function shuffle(arr) {
  arr.sort(function(a,b) {
    return (0.5 - Math.random());
  });
}

function shuffle2(arr) {
  arr.sort(function(a,b) {
    return (Math.round(Math.random())-0.5);
  });
}

function shuffle3(array) {
  var tmp, current, top = array.length;

  if(top) while(--top) {
    current = Math.floor(Math.random() * (top + 1));
    tmp = array[current];
    array[current] = array[top];
    array[top] = tmp;
  }

  return array;
}

var counts = [
  [0,0,0,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0]
];

var arr;
for (var i=0; i<100000; i++) {
  arr = [0,1,2,3,4];
  shuffle3(arr);
  arr.forEach(function(x, i){ counts[x][i]++;});
}

alert(counts.map(function(a){return a.join(", ");}).join("\n"));

আমি দেখতে পাচ্ছি না কেন এটি 0.5.Math.random () হতে হবে, কেন কেবল ম্যাথ.রেন্ডম () নয়?
আলেকজান্ডার মিলস

1
@AlexanderMills: comparator ফাংশন প্রেরণ করা sort()থেকে বড় আসতে অনুমিত হয়, কম, অথবা তুলনা উপর নির্ভর করে শূন্য সমান aএবং b। ( ডেভেলপার.মোজিলা.আর.ইন-
ইউএস

@ লার্শ হ্যাঁ এটি উপলব্ধি করে
আলেকজান্ডার মিলস

9

আমি আমার ওয়েবসাইটটিতে একটি সহজ পরীক্ষার পৃষ্ঠা রেখেছি যা আপনার বর্তমান ব্রাউজারের পক্ষপাতিত্ব দেখায় বনাম অন্যান্য জনপ্রিয় ব্রাউজারগুলির তুলনায় বিভিন্ন পদক্ষেপ বদলে যায়। এটি কেবল ব্যবহারের ভয়াবহ পক্ষপাত দেখায়Math.random()-0.5 , অন্য একটি 'এলোমেলো' সাফল্য যা পক্ষপাতদুষ্ট নয় এবং উপরে উল্লিখিত ফিশার-ইয়েটস পদ্ধতি।

আপনি দেখতে পাচ্ছেন যে কিছু ব্রাউজারগুলিতে 50% এর চেয়ে বেশি সম্ভাবনা রয়েছে যে 'পরিবর্তন' এর সময় নির্দিষ্ট উপাদানগুলি স্থান পরিবর্তন করবে না!

দ্রষ্টব্য: আপনি কোডটি পরিবর্তন করে সাফারির জন্য @ ক্রিসটফ দ্বারা ফিশার-ইয়েটসের রূপান্তরটি কিছুটা দ্রুত করতে পারবেন:

function shuffle(array) {
  for (var tmp, cur, top=array.length; top--;){
    cur = (Math.random() * (top + 1)) << 0;
    tmp = array[cur]; array[cur] = array[top]; array[top] = tmp;
  }
  return array;
}

পরীক্ষার ফলাফল: http://jsperf.com/optimized-fisher-yates


5

আমি মনে করি যেসব ক্ষেত্রে আপনি বিতরণ সম্পর্কে পছন্দ করেন না এবং আপনি উত্স কোডটি ছোট হতে চান।

জাভাস্ক্রিপ্টে (যেখানে উত্সটি ধারাবাহিকভাবে প্রেরণ করা হয়), ছোট ব্যান্ডউইথের ব্যয়কে আলাদা করে।


2
কথাটি হ'ল, আপনি বিতরণ সম্পর্কে আপনি যতটা ভাবেন ঠিক তার চেয়ে বেশি, এবং "ছোট কোড" এর জন্য সবসময়ই রয়েছে arr = arr.map(function(n){return [Math.random(),n]}).sort().map(function(n){return n[1]});, যা খুব বেশি দীর্ঘ না হওয়ার এবং আসলে সঠিকভাবে বিতরণ করার সুবিধা রয়েছে। খুব সংকুচিত নুথ / এফওয়াই শফল ভেরিয়েন্টগুলিও রয়েছে।
ড্যানিয়েল মার্টিন

@ ড্যানিয়েলমার্টিন যে ওয়ান-লাইনারের একটি উত্তর হওয়া উচিত। এছাড়াও, পার্স ত্রুটিগুলি এড়ানোর, দুই সেমিকোলন যোগ করার জন্য তাই এটি ভালো দেখায় প্রয়োজন: arr = arr.map(function(n){return [Math.random(),n];}).sort().map(function(n){return n[1];});
গিয়াকোমো 1968

2

এটি অবশ্যই একটি হ্যাক। অনুশীলনে, অসীম লুপিং অ্যালগরিদম সম্ভবত না। আপনি যদি জিনিসগুলি বাছাই করেন তবে আপনি কর্ডগুলি অ্যারের মাধ্যমে লুপ করতে পারেন এবং এর মতো কিছু করতে পারেন:

for (var i = 0; i < coords.length; i++)
    coords[i].sortValue = Math.random();

coords.sort(useSortValue)

function useSortValue(a, b)
{
  return a.sortValue - b.sortValue;
}

(এবং তারপরে সাজ্টভ্যালু অপসারণ করার জন্য আবার লুপ করুন)

এখনও একটি হ্যাক যদিও। আপনি যদি এটি সুন্দরভাবে করতে চান তবে আপনাকে এটি কঠোরভাবে করতে হবে :)


2

এটি চার বছর কেটে গেছে, তবে আমি এটি উল্লেখ করতে চাই যে র্যান্ডম তুলনাকারী পদ্ধতিটি সঠিকভাবে বিতরণ করা হবে না, আপনি যেভাবেই অ্যালগরিদমকে বাছাই করুন তা নয়।

প্রমাণ:

  1. nউপাদানগুলির একটি অ্যারের জন্য , হুবহু n!ক্রমশক্তি (যেমন সম্ভাব্য শফলস) রয়েছে।
  2. একটি রদবদলের সময় প্রতিটি তুলনা হ'ল দুটি সেট ক্রয়ের মধ্যবর্তী একটি পছন্দ। এলোমেলো তুলনাকারীর জন্য, প্রতিটি সেট বেছে নেওয়ার 1/2 সুযোগ রয়েছে।
  3. সুতরাং, প্রতিটি অনুচ্ছেদে পি এর জন্য, ক্রমাগত পি দিয়ে শেষ হওয়ার সম্ভাবনা হ'ল বিভক্ত 2 ^ কে (কিছু কে) এর সাথে একটি ভগ্নাংশ, কারণ এটি এই জাতীয় ভগ্নাংশের সমষ্টি (যেমন 1/8 + 1/16 = 3/16 )।
  4. এন = 3 এর জন্য, সমানভাবে সম্ভাব্য ছয়টি অনুক্রম রয়েছে। প্রতিটি আদেশের সুযোগটি তখন 1/6। 1/6 এর বিভাজন হিসাবে 2 পাওয়ার হিসাবে ভগ্নাংশ হিসাবে প্রকাশ করা যায় না।
  5. অতএব, মুদ্রা ফ্লিপ বাছাইয়ের ফলে কখনই বদলে যাবে না a

কেবলমাত্র সঠিক আকারে বিতরণ করা যেতে পারে এমন আকারগুলি হ'ল এন = 0,1,2।


অনুশীলন হিসাবে, এন = 3 এর জন্য বিভিন্ন ধরণের অ্যালগরিদমের সিদ্ধান্ত গাছ আঁকার চেষ্টা করুন।


প্রমাণের মধ্যে একটি ফাঁক রয়েছে: যদি কোনও সাজানো অ্যালগরিদম তুলনা করার সামঞ্জস্যের উপর নির্ভর করে এবং অসামঞ্জস্যপূর্ণ তুলনাকারীর সাথে সীমাহীন রানটাইম থাকে, তবে এটির সম্ভাবনাগুলি অসীম পরিমাণে থাকতে পারে, যা 1/6 পর্যন্ত যোগ করার অনুমতি দেয় এমনকি যদি যোগফলের প্রতিটি ডিনোমিনেটর 2 এর শক্তি one

এছাড়াও, যদি কোনও তুলনাকারীর উভয় উত্তর (যেমন (Math.random() < P)*2 - 1ধ্রুবক হিসাবে P) দেওয়ার একটি নির্দিষ্ট সুযোগ থাকে , তবে উপরের প্রমাণটি ধারণ করে। যদি তুলনামূলক পরিবর্তে পূর্ববর্তী উত্তরের উপর ভিত্তি করে তার প্রতিকূলতাকে পরিবর্তন করে, তবে ন্যায্য ফলাফল উত্পন্ন করা সম্ভব। প্রদত্ত বাছাই করা অ্যালগরিদমের জন্য এই জাতীয় তুলক খুঁজে পাওয়া কোনও গবেষণামূলক কাগজ হতে পারে।


1

আপনি যদি ডি 3 ব্যবহার করছেন তবে সেখানে বিল্ট-ইন শফল ফাংশন রয়েছে (ফিশার-ইয়েটস ব্যবহার করে):

var days = ['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche'];
d3.shuffle(days);

এবং এখানে মাইক এটি সম্পর্কে বিশদ যাচ্ছি:

http://bost.ocks.org/mike/shuffle/


0

এখানে একটি পদ্ধতির যা একটি একক অ্যারে ব্যবহার করে:

মূল যুক্তিটি হ'ল:

  • এন উপাদানগুলির একটি অ্যারে দিয়ে শুরু করা
  • অ্যারে থেকে একটি এলোমেলো উপাদান সরান এবং অ্যারের উপর টিপুন
  • অ্যারের প্রথম এন - ১ উপাদান থেকে একটি এলোমেলো উপাদান সরান এবং অ্যারেতে এটি চাপুন
  • অ্যারের প্রথম এন - ২ টি উপাদান থেকে একটি এলোমেলো উপাদান সরান এবং অ্যারেতে এটি চাপুন
  • ...
  • অ্যারের প্রথম উপাদানটি সরান এবং অ্যারেতে এটি টিপুন
  • কোড:

    for(i=a.length;i--;) a.push(a.splice(Math.floor(Math.random() * (i + 1)),1)[0]);

    উল্লেখযোগ্য সংখ্যক উপাদানকে ছোঁয়াতে দিতে আপনার প্রয়োগের উচ্চ ঝুঁকি রয়েছে। নিম্নমানের উপাদানগুলির উপরে যে পরিমাণ চাপ দেওয়া হয়েছে তার দ্বারা এগুলি কেবল পুরো অ্যারে স্থানান্তরিত হবে। এই পরিবর্তন এঁকে একটি প্যাটার্ন আঁকা যা এটি অবিশ্বাস্য করে তোলে।
    কির কানোজ

    @ কিরকানোস, আমি নিশ্চিত না যে আমি আপনার মন্তব্যটি বুঝতে পেরেছি। আমার প্রস্তাবিত সমাধানটি হ'ল ও (এন)। এটি অবশ্যই প্রতিটি উপাদানকে "স্পর্শ" করতে চলেছে। এখানে প্রদর্শনের জন্য একটি মজার শব্দ
    ic3b3rg

    0

    আপনি Array.sort()কোনও অ্যারে বদলে ফাংশনটি ব্যবহার করতে পারেন - হ্যাঁ।

    ফলাফল কি এলোমেলো - না।

    নিম্নলিখিত কোড স্নিপেট বিবেচনা করুন:

    var array = ["a", "b", "c", "d", "e"];
    var stats = {};
    array.forEach(function(v) {
      stats[v] = Array(array.length).fill(0);
    });
    //stats = {
    //    a: [0, 0, 0, ...]
    //    b: [0, 0, 0, ...]
    //    c: [0, 0, 0, ...]
    //    ...
    //    ...
    //}
    var i, clone;
    for (i = 0; i < 100; i++) {
      clone = array.slice(0);
      clone.sort(function() {
        return Math.random() - 0.5;
      });
      clone.forEach(function(v, i) {
        stats[v][i]++;
      });
    }
    
    Object.keys(stats).forEach(function(v, i) {
      console.log(v + ": [" + stats[v].join(", ") + "]");
    })

    নমুনা আউটপুট:

    a [29, 38, 20,  6,  7]
    b [29, 33, 22, 11,  5]
    c [17, 14, 32, 17, 20]
    d [16,  9, 17, 35, 23]
    e [ 9,  6,  9, 31, 45]

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

    এই নিবন্ধে আরও অন্তর্দৃষ্টি দেওয়া হয়েছে:
    অ্যারে.সোর্ট () কোনও অ্যারে বদলানোর জন্য ব্যবহার করা উচিত নয়


    -3

    এর মধ্যে কোন ভুল নেই.

    .Sort () এ আপনি যে ফাংশনটি পাস করেন তা দেখতে সাধারণত কিছু একটা লাগে

    ফাংশন বাছাইয়ের কাজ (প্রথম, দ্বিতীয়)
    {
      // উদাহরণ:
      প্রথম ফিরে - দ্বিতীয়;
    }
    

    বাছাইয়ের কাজটিতে আপনার কাজটি ফিরে আসা:

    • প্রথমে সেকেন্ডের আগে গেলে একটি নেতিবাচক সংখ্যা
    • ধনাত্মক সংখ্যাটি যদি প্রথমের পরে যায়
    • এবং 0 যদি তারা সম্পূর্ণ সমান হয়

    উপরের বাছাই ফাংশন জিনিসগুলিকে ক্রমযুক্ত করে।

    যদি আপনি ফিরে আসেন এবং এলোমেলোভাবে আপনার কাছে যা থাকে তবে আপনি একটি এলোমেলো অর্ডার পাবেন।

    মাইএসকিউএলের মতো:

    টেবিল থেকে র্যান্ড দ্বারা বাই নির্বাচন করুন ()
    

    5
    সেখানে হয় এই পদ্ধতির সঙ্গে কিছু ভুল: জাতীয় বাস্তবায়ন দ্বারা ব্যবহৃত বাছাই আলগোরিদিম উপর নির্ভর করে, সম্ভাব্যতা সমানভাবে বিতরণ করা হবে!
    ক্রিস্টোফ

    এটি কি আমরা ব্যবহারিকভাবে চিন্তিত কিছু?
    bobobobo

    4
    @ বোবোবো: আবেদনের উপর নির্ভর করে, হ্যাঁ, কখনও কখনও আমরা করি; এছাড়াও, একটি সঠিকভাবে কাজ করে shuffle()কেবল একবার লিখতে হবে, সুতরাং এটি আসলেই কোনও সমস্যা নয়: কেবল আপনার কোড ভল্টে স্নিপেটটি রাখুন এবং যখনই আপনার প্রয়োজন হবে এটি সন্ধান করুন
    ক্রিস্টোফ
    আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
    Licensed under cc by-sa 3.0 with attribution required.