Bir kümeden rastgele bir eleman seçme


180

Bir kümeden rastgele bir öğeyi nasıl seçerim? Özellikle bir HashSet veya LinkedHashSet, Java rastgele bir öğe seçmek ilgileniyorum. Diğer diller için de çözümler bekliyoruz.


5
Bunun gerçekten istediğiniz şey olup olmadığını görmek için bazı koşullar belirtmelisiniz. - Rastgele bir öğeyi nasıl seçiyor olabilirsiniz? - Verilerin bir HashSet veya LinkedHashSet içinde saklanması gerekiyor mu, ikisi de rastgele erişilemez. - Karma büyük mü? Anahtarlar küçük mü?
David Nehme

Yanıtlar:


88
int size = myHashSet.size();
int item = new Random().nextInt(size); // In real life, the Random object should be rather more shared than this
int i = 0;
for(Object obj : myhashSet)
{
    if (i == item)
        return obj;
    i++;
}

94
MyHashSet büyükse, rastgele nesneyi bulmak için ortalama olarak (n / 2) yinelemeler gerektiğinden bu oldukça yavaş bir çözüm olacaktır.
daniel

6
verileriniz bir karma kümesindeyse, O (n) zamanına ihtiyacınız vardır. Sadece tek bir öğe seçiyorsanız ve veriler bir HashSet içinde saklanıyorsa, bunun hiçbir yolu yoktur.
David Nehme

8
@David Nehme: Bu, Java'daki HashSet spesifikasyonundaki bir dezavantajdır. C ++ 'da, rasgele öğeleri daha verimli bir şekilde seçmemizi sağlayan, hasheti oluşturan kovalara doğrudan erişebilmek tipiktir. Java'da rasgele öğeler gerekiyorsa, kullanıcının kaputun altına bakmasına izin veren özel bir karma kümesini tanımlamak faydalı olabilir. Biraz daha bilgi için [boost's docs] [1] 'e bakınız. [1] boost.org/doc/libs/1_43_0/doc/html/unordered/buckets.html
Aaron McDaid

11
Eğer küme çoklu erişim üzerinden mutasyona uğramazsa, onu bir diziye kopyalayıp O (1) 'e erişebilirsiniz. Sadece myHashSet.toArray () kullanın
ykaganovich

2
@ykaganovich bu seti daha da kötüleştirmez, çünkü set yeni bir diziye kopyalanmalıdır. docs.oracle.com/javase/7/docs/api/java/util/… "bu koleksiyon bir dizi tarafından desteklenmiş olsa bile bu yöntem yeni bir dizi
ayırmalıdır

73

Biraz ilgili Bildiniz mi:

java.util.CollectionsTüm koleksiyonları karıştırmak için yararlı yöntemler vardır : Collections.shuffle(List<?>)ve Collections.shuffle(List<?> list, Random rnd).


Müthiş! Bu java doc hiçbir yerde çapraz referans değildir! Gibi Python'un random.shuffle ()
SMCI

25
Ancak bu yalnızca List'lerle, yani .get () işlevine sahip yapılarla çalışır.
bourbaki4481472

4
@ bourbaki4481472 kesinlikle doğrudur. Bu sadece OP tarafından tartışılan arayüz için Listdeğil, Setarayüzü genişleten koleksiyonlar için geçerlidir .
Thomas

31

A ArrayListve a HashMap: [element -> index] kullanarak Java için hızlı çözüm .

Motivasyon: RandomAccessÖzellikle setten rastgele bir öğe seçmek için özelliklere sahip bir dizi öğeye ihtiyacım vardı ( pollRandomyönteme bakınız ). İkili ağaçta rastgele gezinme doğru değildir: ağaçlar düzgün bir şekilde dengelenmez, bu da düzgün bir dağılıma yol açmaz.

public class RandomSet<E> extends AbstractSet<E> {

    List<E> dta = new ArrayList<E>();
    Map<E, Integer> idx = new HashMap<E, Integer>();

    public RandomSet() {
    }

    public RandomSet(Collection<E> items) {
        for (E item : items) {
            idx.put(item, dta.size());
            dta.add(item);
        }
    }

    @Override
    public boolean add(E item) {
        if (idx.containsKey(item)) {
            return false;
        }
        idx.put(item, dta.size());
        dta.add(item);
        return true;
    }

    /**
     * Override element at position <code>id</code> with last element.
     * @param id
     */
    public E removeAt(int id) {
        if (id >= dta.size()) {
            return null;
        }
        E res = dta.get(id);
        idx.remove(res);
        E last = dta.remove(dta.size() - 1);
        // skip filling the hole if last is removed
        if (id < dta.size()) {
            idx.put(last, id);
            dta.set(id, last);
        }
        return res;
    }

    @Override
    public boolean remove(Object item) {
        @SuppressWarnings(value = "element-type-mismatch")
        Integer id = idx.get(item);
        if (id == null) {
            return false;
        }
        removeAt(id);
        return true;
    }

    public E get(int i) {
        return dta.get(i);
    }

    public E pollRandom(Random rnd) {
        if (dta.isEmpty()) {
            return null;
        }
        int id = rnd.nextInt(dta.size());
        return removeAt(id);
    }

    @Override
    public int size() {
        return dta.size();
    }

    @Override
    public Iterator<E> iterator() {
        return dta.iterator();
    }
}

Bu işe yarar ama soru Set arayüzü ile ilgiliydi. Bu çözüm, kullanıcıları RandomSet'in somut tip referanslarına sahip olmaya zorlar.
Johan Tidén

Bu çözümü gerçekten çok seviyorum, ancak iş parçacığı güvenli değil, Harita ve Liste arasında yanlışlıklar olabilir, bu yüzden bazı senkronize bloklar
eklerdim

@KonstantinosChalkias yerleşik koleksiyonları da iş parçacığı için güvenli değildir. Sadece adı Concurrentolanlar gerçekten güvenlidir, sarılmış olanlar Collections.synchronized()yarı güvenlidir. Ayrıca OP eşzamanlılık hakkında hiçbir şey söylemedi, bu yüzden bu geçerli ve iyi bir cevap.
TWiStErRob

Buraya döndürülen yineleyici öğeleri kaldıramaz dta(bu, Iterators.unmodifiableIteratorörneğin guava'lar aracılığıyla elde edilebilir ). Aksi takdirde, AbstractSet ve bu yineleyiciyle çalışan ebeveynleri gibi removeAll ve retainAll öğelerinin varsayılan uygulamaları sizin durumunuzu bozacaktır RandomSet!
muued

Güzel çözüm. Her düğüm köklü alt ağaçtaki düğüm sayısını içeriyorsa aslında bir ağaç kullanabilirsiniz. Ardından 0..1'de rastgele bir gerçek hesaplayın ve düğüm sayılarına göre her düğümde ağırlıklı 3 yönlü bir karar verin (geçerli düğümü seçin veya sol veya sağ alt ağaca inin). Ama imo çözümünüz çok daha hoş.
Gene

30

Bu, kabul edilen yanıttaki her bir for döngüsünden daha hızlıdır:

int index = rand.nextInt(set.size());
Iterator<Object> iter = set.iterator();
for (int i = 0; i < index; i++) {
    iter.next();
}
return iter.next();

For-each yapısı Iterator.hasNext()her döngüyü çağırır , ancak o zamandan beri index < set.size()bu kontrol gereksiz bir ek yüktür. Hızda% 10-20'lik bir artış gördüm, ancak YMMV. (Ayrıca, bu ek bir iade ifadesi eklemek zorunda kalmadan derler.)

Bu kodun (ve diğer cevapların çoğunun) yalnızca Set'e değil, herhangi bir Koleksiyona da uygulanabileceğini unutmayın. Genel yöntem formunda:

public static <E> E choice(Collection<? extends E> coll, Random rand) {
    if (coll.size() == 0) {
        return null; // or throw IAE, if you prefer
    }

    int index = rand.nextInt(coll.size());
    if (coll instanceof List) { // optimization
        return ((List<? extends E>) coll).get(index);
    } else {
        Iterator<? extends E> iter = coll.iterator();
        for (int i = 0; i < index; i++) {
            iter.next();
        }
        return iter.next();
    }
}

15

Java ile yapmak istiyorsanız, öğeleri bir çeşit rastgele erişim koleksiyonuna (ArrayList gibi) kopyalamayı düşünmelisiniz. Çünkü, kümeniz küçük olmadığı sürece, seçilen öğeye erişmek pahalı olacaktır (O (1) yerine O (n)). [ed: liste kopyası da O (n)]

Alternatif olarak, gereksinimlerinize daha uygun başka bir Set uygulaması arayabilirsiniz. ListOrderedSet Commons Koleksiyonları'ndan umut verici görünüyor.


8
Bir listeye kopyalamak zamanla O (n) 'ye mal olacak ve aynı zamanda O (n) hafızayı kullanacak, bu yüzden neden doğrudan haritadan getirmekten daha iyi bir seçim olsun ki?
Mdma

12
Setten kaç kez almak istediğinize bağlıdır. Kopya bir kerelik bir işlemdir ve daha sonra setten istediğiniz kadar seçim yapabilirsiniz. Yalnızca bir öğe seçiyorsanız, evet kopya daha hızlı bir şey yapmaz.
Dan Dyer

Tekrar ile seçim yapabilmek istiyorsanız, sadece bir seferlik bir işlemdir. Seçilen öğenin kümeden kaldırılmasını istiyorsanız, O (n) 'a geri dönersiniz.
TurnipEntropy

13

Java 8'de:

static <E> E getRandomSetElement(Set<E> set) {
    return set.stream().skip(new Random().nextInt(set.size())).findFirst().orElse(null);
}

9

Java dilinde:

Set<Integer> set = new LinkedHashSet<Integer>(3);
set.add(1);
set.add(2);
set.add(3);

Random rand = new Random(System.currentTimeMillis());
int[] setArray = (int[]) set.toArray();
for (int i = 0; i < 10; ++i) {
    System.out.println(setArray[rand.nextInt(set.size())]);
}

11
Yanıtınız işe yarıyor, ancak set.toArray () bölümü nedeniyle çok verimli değil.
Clue Less

12
toArray öğesini döngü dışına taşımalısınız.
David Nehme

8
List asList = new ArrayList(mySet);
Collections.shuffle(asList);
return asList.get(0);

21
Bu uçsuz bucaksız verimsiz. ArrayList yapıcısı verilen sette .toArray () öğesini çağırır. ToArray (çoğu standart koleksiyon uygulamasında olmasa da çoğunda) tüm koleksiyonu tekrarlar ve bir diziyi giderken doldurur. Ardından, her öğeyi rastgele bir öğeyle değiştiren listeyi karıştırırsınız. Rastgele bir öğenin setini yinelemek çok daha iyi olur.
Chris Bode

4

Bu, kabul edilen cevap (Khoth) ile aynıdır, ancak gereksiz sizeve ideğişkenler kaldırılmıştır.

    int random = new Random().nextInt(myhashSet.size());
    for(Object obj : myhashSet) {
        if (random-- == 0) {
            return obj;
        }
    }

Yukarıda bahsedilen iki değişkeni ortadan kaldırsa da, yukarıdaki çözüm hala rasgele kalmaktadır, çünkü 0her yinelemenin üzerine doğru kendini azaltmak için rastgele (rastgele seçilen bir dizinden başlayarak) güveniyoruz .


1
Üçüncü hattı da olabilir if (--random < 0) {, nerede randomulaşır -1.
Salvador

3

Clojure çözümü:

(defn pick-random [set] (let [sq (seq set)] (nth sq (rand-int (count sq)))))

1
Bu çözüm de doğrusaldır, çünkü nthöğeyi elde etmek için de geçiş yapmanız gerekir seq.
Bruno Kim

1
Aynı şekilde lineer olduğu gibi doğrusaldır: D
Krzysztof Wolny

2

Perl 5

@hash_keys = (keys %hash);
$rand = int(rand(@hash_keys));
print $hash{$hash_keys[$rand]};

İşte bunu yapmanın bir yolu.


2

C ++. Bu, tüm set üzerinde tekrarlama veya sıralama gerektirmediği için makul derecede hızlı olmalıdır. Bu, tr1'i destekledikleri varsayılarak, çoğu modern derleyiciyle birlikte çalışmalıdır . Değilse, Boost'u kullanmanız gerekebilir.

Boost dokümanlar Kuvvetlendirme kullanmayın bile, bu açıklamaya burada faydalıdır.

İşin püf noktası, verilerin bölümlere ayrıldığı gerçeğinden faydalanmak ve rasgele seçilen bir kovayı (uygun olasılıkla) hızlı bir şekilde tanımlamaktır.

//#include <boost/unordered_set.hpp>  
//using namespace boost;
#include <tr1/unordered_set>
using namespace std::tr1;
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;

int main() {
  unordered_set<int> u;
  u.max_load_factor(40);
  for (int i=0; i<40; i++) {
    u.insert(i);
    cout << ' ' << i;
  }
  cout << endl;
  cout << "Number of buckets: " << u.bucket_count() << endl;

  for(size_t b=0; b<u.bucket_count(); b++)
    cout << "Bucket " << b << " has " << u.bucket_size(b) << " elements. " << endl;

  for(size_t i=0; i<20; i++) {
    size_t x = rand() % u.size();
    cout << "we'll quickly get the " << x << "th item in the unordered set. ";
    size_t b;
    for(b=0; b<u.bucket_count(); b++) {
      if(x < u.bucket_size(b)) {
        break;
      } else
        x -= u.bucket_size(b);
    }
    cout << "it'll be in the " << b << "th bucket at offset " << x << ". ";
    unordered_set<int>::const_local_iterator l = u.begin(b);
    while(x>0) {
      l++;
      assert(l!=u.end(b));
      x--;
    }
    cout << "random item is " << *l << ". ";
    cout << endl;
  }
}

2

Yukarıdaki çözüm gecikme anlamındadır, ancak seçilen her bir endeksin eşit olasılığını garanti etmez.
Dikkat edilmesi gerekiyorsa, rezervuar örneklemeyi deneyin. http://en.wikipedia.org/wiki/Reservoir_sampling .
Collections.shuffle () (birkaç kişi tarafından önerildiği gibi) böyle bir algoritma kullanır.


1

"Diğer diller için çözümler de hoş geldiniz" dediğinden, Python için sürüm:

>>> import random
>>> random.choice([1,2,3,4,5,6])
3
>>> random.choice([1,2,3,4,5,6])
4

3
Hızlı aramalar gibi şeyleri desteklemediğinden yalnızca [1,2,3,4,5,6] bir küme değil, bir listedir.
Thomas Ahle

Hala yapabilirsiniz: >>> random.choice (list (set (range (5)))) >>> 4 İdeal değil ama kesinlikle ihtiyacınız varsa yapacağız.
SapphireSun

1

Sadece set / dizinin boyutunu / uzunluğunu elde edemez, 0 ile boyut / uzunluk arasında rastgele bir sayı üretemez, ardından dizini bu sayı ile eşleşen öğeyi çağıramaz mısınız? HashSet .size () yöntemine sahiptir, eminim.

Psuedocode'ta -

function randFromSet(target){
 var targetLength:uint = target.length()
 var randomIndex:uint = random(0,targetLength);
 return target[randomIndex];
}

Bu yalnızca söz konusu kapsayıcı rasgele dizin aramayı destekliyorsa çalışır. Birçok kap uygulaması yoktur (örneğin, karma tablolar, ikili ağaçlar, bağlantılı listeler).
David Haley

1

PHP, "set" in bir dizi olduğunu varsayar:

$foo = array("alpha", "bravo", "charlie");
$index = array_rand($foo);
$val = $foo[$index];

Mersenne Twister fonksiyonları daha iyidir ancak PHP'de array_rand'ın MT eşdeğeri yoktur.


Çoğu set uygulaması bir get (i) veya indeksleme operatörüne sahip değildir, bu yüzden OP, bu yüzden OP'nin bir set belirttiğini varsayar
DownloadPizza

1

Simgenin bir set türü ve rastgele eleman operatörü var, tekli "?"

? set( [1, 2, 3, 4, 5] )

1 ile 5 arasında rastgele bir sayı üretecektir.

Bir program çalıştırıldığında rastgele tohum 0 olarak başlatılır, böylece her çalıştırma kullanımında farklı sonuçlar elde edilir randomize()


1

C # dilinde

        Random random = new Random((int)DateTime.Now.Ticks);

        OrderedDictionary od = new OrderedDictionary();

        od.Add("abc", 1);
        od.Add("def", 2);
        od.Add("ghi", 3);
        od.Add("jkl", 4);


        int randomIndex = random.Next(od.Count);

        Console.WriteLine(od[randomIndex]);

        // Can access via index or key value:
        Console.WriteLine(od[1]);
        Console.WriteLine(od["def"]);

onlar crappy java sözlük (ya da her ne olursa olsun LinkedHashSet, ne olursa olsun, cehennem ne olursa olsun) "rastgele erişilemez" (sanırım anahtar ile erişilir) çünkü aşağı indirilmiş gibi görünüyor. Java bok beni çok güldürüyor
Federico Berasategui

1

Javascript çözümü;)

function choose (set) {
    return set[Math.floor(Math.random() * set.length)];
}

var set  = [1, 2, 3, 4], rand = choose (set);

Veya alternatif olarak:

Array.prototype.choose = function () {
    return this[Math.floor(Math.random() * this.length)];
};

[1, 2, 3, 4].choose();

İkinci alternatifi tercih ederim. :-)
marcospereira

ooh, yeni dizi yöntemi eklemeyi uzatmayı seviyorum!
matt lohkamp

1

Lisp'te

(defun pick-random (set)
       (nth (random (length set)) set))

Bu sadece listeler için geçerli, değil mi? Bununla ELTbirlikte herhangi bir dizi için çalışabilir.
Ken

1

Mathematica'da:

a = {1, 2, 3, 4, 5}

a[[  Length[a] Random[]  ]]

Veya son sürümlerde basitçe:

RandomChoice[a]

Bu, belki de açıklama eksik olduğu için bir aşağı oy aldı, bu yüzden burada:

Random[]0 ile 1 arasında bir sahte sözde float oluşturur. Bu, listenin uzunluğuyla çarpılır ve ardından tavan işlevi, bir sonraki tamsayıya yuvarlamak için kullanılır. Bu indeks daha sonra buradan çıkarılır a.

Karma tablo işlevi Mathematica'daki kurallarla sık sık yapıldığından ve kurallar listelerde saklandığından, aşağıdakiler kullanılabilir:

a = {"Badger" -> 5, "Bird" -> 1, "Fox" -> 3, "Frog" -> 2, "Wolf" -> 4};

1

Peki ya

public static <A> A getRandomElement(Collection<A> c, Random r) {
  return new ArrayList<A>(c).get(r.nextInt(c.size()));
}

1

Eğlence için ret örneklemesine dayalı bir RandomHashSet yazdım. HashMap tabloya doğrudan erişmemize izin vermediğinden, biraz hileli, ama iyi çalışmalı.

Fazladan bellek kullanmaz ve arama süresi O (1) itfa edilir. (Java HashTable yoğun olduğundan).

class RandomHashSet<V> extends AbstractSet<V> {
    private Map<Object,V> map = new HashMap<>();
    public boolean add(V v) {
        return map.put(new WrapKey<V>(v),v) == null;
    }
    @Override
    public Iterator<V> iterator() {
        return new Iterator<V>() {
            RandKey key = new RandKey();
            @Override public boolean hasNext() {
                return true;
            }
            @Override public V next() {
                while (true) {
                    key.next();
                    V v = map.get(key);
                    if (v != null)
                        return v;
                }
            }
            @Override public void remove() {
                throw new NotImplementedException();
            }
        };
    }
    @Override
    public int size() {
        return map.size();
    }
    static class WrapKey<V> {
        private V v;
        WrapKey(V v) {
            this.v = v;
        }
        @Override public int hashCode() {
            return v.hashCode();
        }
        @Override public boolean equals(Object o) {
            if (o instanceof RandKey)
                return true;
            return v.equals(o);
        }
    }
    static class RandKey {
        private Random rand = new Random();
        int key = rand.nextInt();
        public void next() {
            key = rand.nextInt();
        }
        @Override public int hashCode() {
            return key;
        }
        @Override public boolean equals(Object o) {
            return true;
        }
    }
}

1
Tam olarak ne düşünüyordum! En iyi cevap!
mmm

Aslında, geri dönersek, eğer hashmap çok fazla çarpışmaya sahipse ve birçok sorgu yapıyorsak, bu oldukça tekdüze değil. Java hashmap kovalar / zincirleme kullanır ve bu kod her zaman belirli bir kova ilk eleman döndürecektir. Yine de hash fonksiyonunun rastgeleliği üzerinde tekdüzeyiz.
Thomas Ahle

1

Java 8 ile en kolayı:

outbound.stream().skip(n % outbound.size()).findFirst().get()

burada nrastgele bir tam sayıdır. Tabii ki daha az performansa sahip.for(elem: Col)


1

Guava ile Khoth'un cevabından biraz daha iyisini yapabiliriz:

public static E random(Set<E> set) {
  int index = random.nextInt(set.size();
  if (set instanceof ImmutableSet) {
    // ImmutableSet.asList() is O(1), as is .get() on the returned list
    return set.asList().get(index);
  }
  return Iterables.get(set, index);
}

0

MT, PHP kullanarak:

$items_array = array("alpha", "bravo", "charlie");
$last_pos = count($items_array) - 1;
$random_pos = mt_rand(0, $last_pos);
$random_item = $items_array[$random_pos];

0

Ayrıca dizi kullanım dizisine aktarabilirsiniz, muhtemelen küçük ölçekte çalışacaktır.

Object[] arr = set.toArray();

int v = (int) arr[rnd.nextInt(arr.length)];

0

Eğer Setrastgele herhangi bir garanti olmadan, sadece "herhangi" bir nesne seçmek istiyorsanız , en kolay ilk yineleyici tarafından iade edilir.

    Set<Integer> s = ...
    Iterator<Integer> it = s.iterator();
    if(it.hasNext()){
        Integer i = it.next();
        // i is a "random" object from set
    }

1
Bu rastgele bir seçim olmayacak. Aynı işlemi aynı sette birden çok kez gerçekleştirdiğinizi düşünün. Bence sipariş aynı olacak.
Menezes Sousa

0

Khoth'un cevabını başlangıç ​​noktası olarak kullanan genel bir çözüm.

/**
 * @param set a Set in which to look for a random element
 * @param <T> generic type of the Set elements
 * @return a random element in the Set or null if the set is empty
 */
public <T> T randomElement(Set<T> set) {
    int size = set.size();
    int item = random.nextInt(size);
    int i = 0;
    for (T obj : set) {
        if (i == item) {
            return obj;
        }
        i++;
    }
    return null;
}

0

Ne yazık ki, bu Standart Kütüphane seti kapsayıcılarında verimli bir şekilde (O (n) 'den daha iyi) yapılamaz.

Karma kümelere ve ikili kümelere rastgele seçim fonksiyonu eklemek çok kolay olduğu için bu garip. Seyrek bir karma kümesinde, bir hit elde edene kadar rastgele girişleri deneyebilirsiniz. İkili ağaç için, maksimum O (log2) adımla, sol veya sağ alt ağaç arasında rastgele seçim yapabilirsiniz. Aşağıdakilerin bir demosunu uyguladım:

import random

class Node:
    def __init__(self, object):
        self.object = object
        self.value = hash(object)
        self.size = 1
        self.a = self.b = None

class RandomSet:
    def __init__(self):
        self.top = None

    def add(self, object):
        """ Add any hashable object to the set.
            Notice: In this simple implementation you shouldn't add two
                    identical items. """
        new = Node(object)
        if not self.top: self.top = new
        else: self._recursiveAdd(self.top, new)
    def _recursiveAdd(self, top, new):
        top.size += 1
        if new.value < top.value:
            if not top.a: top.a = new
            else: self._recursiveAdd(top.a, new)
        else:
            if not top.b: top.b = new
            else: self._recursiveAdd(top.b, new)

    def pickRandom(self):
        """ Pick a random item in O(log2) time.
            Does a maximum of O(log2) calls to random as well. """
        return self._recursivePickRandom(self.top)
    def _recursivePickRandom(self, top):
        r = random.randrange(top.size)
        if r == 0: return top.object
        elif top.a and r <= top.a.size: return self._recursivePickRandom(top.a)
        return self._recursivePickRandom(top.b)

if __name__ == '__main__':
    s = RandomSet()
    for i in [5,3,7,1,4,6,9,2,8,0]:
        s.add(i)

    dists = [0]*10
    for i in xrange(10000):
        dists[s.pickRandom()] += 1
    print dists

Çıktı olarak [995, 975, 971, 995, 1057, 1004, 966, 1052, 984, 1001] çıktı.

Kendim için de aynı sorunla mücadele ettim ve hava durumuna henüz bu daha verimli seçimin performans kazancının bir python tabanlı koleksiyon kullanmanın yükü olduğuna karar vermedim. Elbette rafine edebilir ve C'ye çevirebilirdim, ama bugün benim için çok fazla iş var :)


1
Bunun ikili bir ağaçta uygulanmadığını düşünmememin bir nedeni, böyle bir yöntemin öğeleri düzgün bir şekilde seçmemesidir. Sol / sağ çocukları olmayan düğümler olduğundan, sol çocuğun sağ çocuktan daha fazla öğe içerdiği (veya tersi) bir durum ortaya çıkabilir, bu da sağ (veya sol) çocukta bir öğeyi seçmeyi daha olası hale getirir.
Willem Van Onsem

1
@CommuSoft: Bu yüzden her alt ağacın boyutunu saklıyorum, böylece olasılıklarıma göre seçebiliyorum.
Thomas Ahle
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.