2008-12-17 9 views
50

में पूर्णांक की एक सूची यादृच्छिक रूप से "सॉर्ट" (शफल) के लिए सबसे प्रभावी तरीका है, मुझे सबसे प्रभावी तरीके से पूर्णांक (0-1999) की यादृच्छिक रूप से 'क्रमबद्ध' करने की आवश्यकता है। कोई विचार?सी #

वर्तमान में, मैं कुछ इस तरह कर रहा हूँ:

bool[] bIndexSet = new bool[iItemCount]; 

for (int iCurIndex = 0; iCurIndex < iItemCount; iCurIndex++) 
{ 
    int iSwapIndex = random.Next(iItemCount); 
    if (!bIndexSet[iSwapIndex] && iSwapIndex != iCurIndex) 
    { 
     int iTemp = values[iSwapIndex]; 
     values[iSwapIndex] = values[iCurIndex]; 
     values[iCurIndex] = values[iSwapIndex]; 
     bIndexSet[iCurIndex] = true; 
     bIndexSet[iSwapIndex] = true; 
    } 
} 
+0

ध्यान दें कि आप एक iTemp var बनाते हैं, लेकिन इसका उपयोग न करें। यह निश्चित रूप से मुद्दों का कारण बन जाएगा। – Aistina

+0

आह, हाँ। मेरा मतलब मान [iCurIndex] = iTemp असाइन करना था। – Carl

+2

यह कहने का एक बेहतर तरीका शायद "पूर्णांक की सूची का यादृच्छिक क्रमपरिवर्तन बनाने का सबसे प्रभावी तरीका" – ICR

उत्तर

51

एक अच्छा रैखिक समय फेरबदल एल्गोरिथ्म Fisher-Yates shuffle है।

आपके प्रस्तावित एल्गोरिदम के साथ आपको एक समस्या मिल जाएगी, क्योंकि आप शफल के अंत के पास हैं, आपका लूप यादृच्छिक रूप से चुने गए तत्वों की तलाश में बहुत समय व्यतीत करेगा जो अभी तक स्वैप नहीं किए गए हैं। स्वैप करने के आखिरी तत्व में आने के बाद यह अनिश्चित समय ले सकता है।

इसके अलावा, ऐसा लगता है कि सॉर्ट करने के लिए तत्वों की एक विषम संख्या होने पर आपके एल्गोरिदम कभी समाप्त नहीं होंगे।

+1

जब तक आपके उत्तर के बाद से एल्गोरिदम संपादित नहीं किया जाता है, तब तक शफल के अंत में कोई धीमा नहीं होगा। iCurIndex को कभी भी कथन में अन्य को सौंपा नहीं गया है। हालांकि क्या होगा जब iCurIndex == iSwapIndex जब भी कई अनगिनत तत्व होंगे। – Ash

2

अपने दक्षता में सुधार करने के लिए आप मान/सूचकांक कि यह दर्शाता है कि वे बदली कर रहे थे के लिए एक बूलियन बजाय बदली कर दिया है का एक सेट रख सकते हैं। शेष पूल से अपना यादृच्छिक स्वैप इंडेक्स चुनें। जब पूल 0 होता है, या जब आपने प्रारंभिक सूची के माध्यम से इसे बनाया है तो आप कर चुके हैं। आपके पास यादृच्छिक स्वैप अनुक्रमणिका मान चुनने का प्रयास करने की क्षमता नहीं है।

जब आप एक स्वैप करते हैं, सिर्फ उन्हें पूल से हटा दें।

डेटा के आकार के लिए आप देख रहे हैं कि यह कोई बड़ा सौदा नहीं है।

4

मैं दक्षता कारक के बारे में सुनिश्चित नहीं हूँ, लेकिन मैं अगर तुम एक ArrayList का उपयोग कर के लिए विरोध नहीं कर रहे हैं निम्नलिखित करने के लिए कुछ इसी तरह का इस्तेमाल किया है,:

private ArrayList ShuffleArrayList(ArrayList source) 
{ 
    ArrayList sortedList = new ArrayList(); 
    Random generator = new Random(); 

    while (source.Count > 0) 
    { 
     int position = generator.Next(source.Count); 
     sortedList.Add(source[position]); 
     source.RemoveAt(position); 
    } 

    return sortedList; 
} 

इस का उपयोग करते हुए, आपको चिंता करने की जरूरत नहीं है मध्यवर्ती स्वैपिंग के बारे में।

+2

Array.RemoveAt एक ओ (एन) ऑपरेशन है, और आपके लूप का प्रत्येक पुनरावृत्ति स्रोत सरणी के आकार को 1 से घटा देता है। इससे आपके कार्यों की जटिलता array.count से 0, या O ((एन^2 + एन)/2)। यह काम करता है, लेकिन यह बहुत ही कुशल नहीं है। – Juliet

4

जैसा कि ग्रेग ने Fisher-Yates shuffle को इंगित किया सबसे अच्छा तरीका होगा। यहाँ विकिपीडिया से एल्गोरिथ्म के एक कार्यान्वयन है:

public static void shuffle (int[] array) 
{ 
    Random rng = new Random(); // i.e., java.util.Random. 
    int n = array.length;  // The number of items left to shuffle (loop invariant). 
    while (n > 1) 
    { 
     int k = rng.nextInt(n); // 0 <= k < n. 
     n--;      // n is now the last pertinent index; 
     int temp = array[n];  // swap array[n] with array[k] (does nothing if k == n). 
     array[n] = array[k]; 
     array[k] = temp; 
    } 
} 

कार्यान्वयन ऊपर पर Random.nextInt (int) निर्भर करता है प्रदान पर्याप्त यादृच्छिक और निष्पक्ष परिणाम

+1

मैंने इस समाधान का उपयोग VB.NET में किया और एक आकर्षण की तरह काम किया !! :) धन्यवाद –

+0

@MathieuG 8 वर्षों के बाद, मीका के प्रयासों काटा गया! ;) –

0

चाहेंगे कुछ नहीं की तरह इस काम?

var list = new[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; 
var random = new Random(); 
list.Sort((a,b)=>random.Next(-1,1)); 
+0

हां, लेकिन यह बड़ी सूचियों के लिए कुशल नहीं होगा - सॉर्टिंग ओ (एन लॉग एन) है, जहां फिशर येट्स रैखिक है। – Thelema

+0

int [] या IEnumerable में कोई सॉर्ट विधि नहीं है, केवल सूची foson

+1

मुझे पता है, यह एक प्राचीन उत्तर है, लेकिन यह प्रश्न अभी भी Google खोज में आता है: यह कभी नहीं करें। यह आपकी सूची को यादृच्छिक रूप से * नहीं करेगा *। आपकी सूची दूसरों के मुकाबले कुछ निश्चित आदेशों में होने की संभावना अधिक होगी। –

30
static Random random = new Random(); 

public static IEnumerable<T> RandomPermutation<T>(IEnumerable<T> sequence) 
{ 
    T[] retArray = sequence.ToArray(); 


    for (int i = 0; i < retArray.Length - 1; i += 1) 
    { 
     int swapIndex = random.Next(i, retArray.Length); 
     if (swapIndex != i) { 
      T temp = retArray[i]; 
      retArray[i] = retArray[swapIndex]; 
      retArray[swapIndex] = temp; 
     } 
    } 

    return retArray; 
} 

सूचियों या अन्य वस्तुओं को लागू करने को संभालने के लिए संशोधित IEnumerable

+0

उपरोक्त कैसे कहा जाएगा यदि मेरे पास केवल तारों के साथ सरणीसूची थी? –

+5

'random'ext (i + 1, array.Length)' if' जांच से बचने के लिए। इसके अलावा 'i kolobok

+2

पुराना धागा - लेकिन अगर कोई उपर्युक्त कोड की प्रतिलिपि बनाने के बारे में सोच रहा है - तो यह सही तरीके से काम नहीं करता है। सूची में पहला तत्व कभी नहीं चुना जाता है - कभी! – dotnetnoob

18

हम किसी भी IList संग्रह के लिए एक यादृच्छिक प्रगणक प्राप्त करने के लिए इस से बाहर एक विस्तार विधि

class Program 
{ 
    static void Main(string[] args) 
    { 
     IList<int> l = new List<int>(); 
     l.Add(7); 
     l.Add(11); 
     l.Add(13); 
     l.Add(17); 

     foreach (var i in l.AsRandom()) 
      Console.WriteLine(i); 

     Console.ReadLine(); 
    } 
} 


public static class MyExtensions 
{ 
    public static IEnumerable<T> AsRandom<T>(this IList<T> list) 
    { 
     int[] indexes = Enumerable.Range(0, list.Count).ToArray(); 
     Random generator = new Random(); 

     for (int i = 0; i < list.Count; ++i) 
     { 
      int position = generator.Next(i, list.Count); 

      yield return list[indexes[position]]; 

      indexes[position] = indexes[i]; 
     } 
    } 
} 

इस का उपयोग करता है बना सकते हैं सूची के सूचकांक पर एक रिवर्स फिशर-येट्स शफल है जिसे हम यादृच्छिक रूप से गिनना चाहते हैं। इसका एक आकार का होग (4 * सूची आवंटित करना। बाइट बाइट्स) आवंटित करता है, लेकिन ओ (एन) में चलता है।

+0

मुझे यह संस्करण पसंद है, धन्यवाद! – psulek

-1

मैं एक अस्थायी Hashtable का उपयोग कर एक विधि बनाया है, Hashtable की प्राकृतिक कुंजी प्रकार randomize करने के लिए अनुमति देता है। बस जोड़ें, पढ़ें और छोड़ दें।

int min = 1; 
int max = 100; 
Random random; 
Hashtable hash = new Hashtable(); 
for (int x = min; x <= max; x++) 
{ 
    random = new Random(DateTime.Now.Millisecond + x); 
    hash.Add(random.Next(Int32.MinValue, Int32.MaxValue), x); 
} 
foreach (int key in hash.Keys) 
{ 
    HttpContext.Current.Response.Write("<br/>" + hash[key] + "::" + key); 
} 
hash.Clear(); // cleanup 
+1

GetHashCode() किसी भी तरह से यादृच्छिकता की गारंटी देता है। –

0

मुझे लगता है कि पिछले दो लाइनों को मीका के जवाब में अंतरण किया जाना चाहिए। तो, कोड लग सकता है आईसीआर के जवाब

तरह
public static void shuffle(int[] array) { 
     Random rng = new Random(); // i.e., java.util.Random. 
     int n = array.Length;  // The number of items left to shuffle (loop invariant). 
     while (n > 1) { 
      int k = rng.Next(n); // 0 <= k < n. 
      n--;      // n is now the last pertinent index; 
      int temp = array[n];  // swap array[n] with array[k] (does nothing if k == n). 
      array[n] = array[k]; 
      array[k] = temp; 

     } 
    } 
1

बहुत तेजी से है, लेकिन जिसके परिणामस्वरूप सरणियों सामान्य रूप से वितरित नहीं कर रहे हैं। आप एक सामान्य वितरण चाहते हैं, यहाँ कोड है:

public static IEnumerable<T> RandomPermutation<T>(this IEnumerable<T> sequence, int start,int end) 
    { 
     T[] array = sequence as T[] ?? sequence.ToArray(); 

     var result = new T[array.Length]; 

     for (int i = 0; i < start; i++) 
     { 
      result[i] = array[i]; 
     } 
     for (int i = end; i < array.Length; i++) 
     { 
      result[i] = array[i]; 
     } 

     var sortArray=new List<KeyValuePair<double,T>>(array.Length-start-(array.Length-end)); 
     lock (random) 
     { 
      for (int i = start; i < end; i++) 
      { 
       sortArray.Add(new KeyValuePair<double, T>(random.NextDouble(), array[i])); 
      } 
     } 

     sortArray.Sort((i,j)=>i.Key.CompareTo(j.Key)); 

     for (int i = start; i < end; i++) 
     { 
      result[i] = sortArray[i - start].Value; 
     } 

     return result; 
    } 

नोट है कि मेरे परीक्षणों में, इस एल्गोरिथ्म प्रदान की एक आईसीआर से 6 बार धीमी थी, लेकिन इस एक ही रास्ता मैं एक पाने के लिए साथ आने कर सकता है सामान्य परिणाम वितरण

0

किस बारे में:

System.Array.Sort(arrayinstance, RandomizerMethod); 
... 
//any evoluated random class could do it ! 
private static readonly System.Random Randomizer = new System.Random(); 

private static int RandomizerMethod<T>(T x, T y) 
    where T : IComparable<T> 
{ 
    if (x.CompareTo(y) == 0) 
     return 0; 

    return Randomizer.Next().CompareTo(Randomizer.Next()); 
} 

देखा!