세트에서 임의의 요소 선택


180

세트에서 임의의 요소를 어떻게 선택합니까? 특히 Java의 HashSet 또는 LinkedHashSet에서 임의의 요소를 선택하는 데 관심이 있습니다. 다른 언어에 대한 솔루션도 환영합니다.


5
이것이 실제로 원하는지 확인하려면 몇 가지 조건을 지정해야합니다. -어떻게 무작위 요소를 선택해야할까요? -데이터를 HashSet 또는 LinkedHashSet에 저장해야합니까, 임의로 액세스 할 수있는 것은 아닙니다. -해시가 큰가요? 키가 작습니까?
David Nehme

답변:


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이 크면 임의의 객체를 찾기 위해 평균 (n / 2) 반복이 필요하기 때문에 다소 느린 솔루션입니다.
다니엘

6
데이터가 해시 세트에 있으면 O (n) 시간이 필요합니다. 단일 요소를 선택하고 데이터가 HashSet에 저장된 경우 그 주위에 방법이 없습니다.
David Nehme

8
@David Nehme : 이것은 Java HashSet 사양의 단점입니다. C ++에서는 해시 셋을 구성하는 버킷에 직접 액세스 할 수있는 것이 일반적이므로 임의 요소를보다 효율적으로 선택할 수 있습니다. Java에서 임의의 요소가 필요한 경우 사용자가 후드를 볼 수 있도록 사용자 정의 해시 세트를 정의하는 것이 좋습니다. 이에 대한 자세한 내용은 [부스트 문서] [1]을 참조하십시오. [1] boost.org/doc/libs/1_43_0/doc/html/unorder/buckets.html
Aaron McDaid

11
세트가 다중 액세스에 대해 변경되지 않은 경우 세트를 배열로 복사 한 다음 O (1)에 액세스 할 수 있습니다. 그냥 myHashSet.toArray ()를 사용
ykaganovich

2
@ykaganovich는 세트를 새로운 배열로 복사해야하기 때문에 문제가 더 나쁘지 않습니까? docs.oracle.com/javase/7/docs/api/java/util/… "이 메소드는이 콜렉션이 배열에 의해 지원 되더라도 새로운 배열을 할당해야합니다"
anton1980

73

다소 관련이 있습니까?

java.util.Collections전체 컬렉션을 섞는 데 유용한 방법이 있습니다 : Collections.shuffle(List<?>)Collections.shuffle(List<?> list, Random rnd).


대박! 이것은 Java doc의 어느 곳에서나 상호 참조되지 않습니다! Python의 random.shuffle ()
smci

25
그러나 이것은 List, 즉 .get () 함수가있는 구조에서만 작동합니다.
bourbaki4481472

4
@ bourbaki4481472는 절대적으로 정확합니다. 이것은 OP가 논의한 List인터페이스가 아니라 인터페이스를 확장하는 컬렉션에만 적용됩니다 Set.
토머

31

ArrayListand HashMap: [element-> index]를 사용하는 Java 용 빠른 솔루션 .

동기 부여 : RandomAccess특히 세트에서 임의의 항목을 선택하려면 속성 이있는 항목 세트가 필요했습니다 ( pollRandom방법 참조 ). 이진 트리의 임의 탐색은 정확하지 않습니다. 트리가 완벽하게 균형을 이루지 못하므로 균일 한 분포가 이루어지지 않습니다.

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();
    }
}

잘 작동하지만 문제는 Set 인터페이스에 관한 것입니다. 이 솔루션은 사용자가 RandomSet에 대한 구체적인 유형 참조를 갖도록합니다.
Johan Tidén

이 솔루션은 정말 마음에 들지만 스레드 안전하지 않으므로 맵과 목록간에 부정확 한 부분이 발생할 수 있으므로 동기화 된 블록을 추가합니다.
Kostas Chalkias

@KonstantinosChalkias 내장 컬렉션은 스레드로부터 안전하지 않습니다. 이름 Concurrent이 있는 것만 정말로 안전하고, 싸인 Collections.synchronized()것은 반 안전합니다. 또한 OP는 동시성에 대해 아무 말도하지 않았으므로 유효하고 좋은 대답입니다.
TWiStErRob

여기에 반환 된 반복자는 요소를 제거 할 수 없어야합니다 dta( Iterators.unmodifiableIterator예 : 구아바를 통해 수행 할 수 있음 ). 그렇지 않으면 AbstractSet의 removeAll 및 retainAll 및 해당 반복자와 함께 작업하는 부모의 기본 구현은 사용자를 엉망으로 만듭니다 RandomSet!
muued

좋은 해결책. 각 노드에 루트가있는 서브 트리에 노드 수가 포함되어 있으면 실제로 트리를 사용할 수 있습니다. 그런 다음 0..1에서 임의의 실수를 계산하고 노드 수를 기준으로 각 노드에서 가중치 3 방향 결정 (현재 노드 선택 또는 왼쪽 또는 오른쪽 하위 트리로 내려 가기)을 결정하십시오. 그러나 당신의 솔루션은 훨씬 좋습니다.
유전자

30

이것은 허용 된 답변의 for-each 루프보다 빠릅니다.

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 구문은 Iterator.hasNext()모든 루프를 호출 하지만 이후 index < set.size()로이 검사는 불필요한 오버 헤드입니다. 속도가 10-20 % 향상되었지만 YMMV가 나타났습니다. 또한 여분의 return 문을 추가하지 않고도 컴파일됩니다.

이 코드 (및 대부분의 다른 답변)는 Set뿐만 아니라 모든 Collection에 적용 할 수 있습니다. 일반적인 방법 양식에서 :

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로 작성하려면 요소를 일종의 임의 액세스 콜렉션 (예 : ArrayList)에 복사하는 것을 고려해야합니다. 집합이 작지 않으면 선택한 요소에 액세스하는 데 비용이 많이 듭니다 (O (1) 대신 O (n)). [ed : 목록 사본도 O (n)입니다]

또는 요구 사항과 더 일치하는 다른 Set 구현을 찾을 수 있습니다. Commons Collections 의 ListOrderedSet 은 유망한 것으로 보입니다.


8
목록에 복사하는 데 시간이 걸리고 O (n) 메모리도 사용되므로 맵에서 직접 가져 오는 것보다 더 나은 선택이 필요한 이유는 무엇입니까?
mdma

12
세트에서 선택하려는 횟수에 따라 다릅니다. 사본은 한 번만 수행하면 필요한만큼 세트에서 선택할 수 있습니다. 하나의 요소 만 선택하는 경우 예, 사본으로 인해 더 빨리 만들지 않습니다.
Dan Dyer

반복해서 선택하고 싶을 때는 한 번만 조작하면됩니다. 선택한 항목을 세트에서 제거하려면 O (n)으로 돌아갑니다.
TurnipEntropy

13

자바 8 :

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

9

자바에서 :

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
귀하의 답변은 효과가 있지만 set.toArray () 부분으로 인해 효율적이지 않습니다.
Clue Less

12
toArray를 루프 외부로 이동해야합니다.
David Nehme

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

21
이것은 매우 비효율적입니다. ArrayList 생성자는 제공된 집합에서 .toArray ()를 호출합니다. ToArray (대부분의 모든 표준 컬렉션 구현은 아님)는 전체 컬렉션을 반복하여 배열을 채 웁니다. 그런 다음 각 요소를 임의 요소로 바꾸는 목록을 섞습니다. 세트를 임의의 요소로 반복하는 것이 훨씬 낫습니다.
Chris Bode

4

이것은 답변 (Khoth)과 동일하지만 불필요 size하고 i변수가 제거되었습니다.

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

위에서 언급 한 두 가지 변수를 제거하더라도 위의 해결 방법은 무작위로 유지됩니다 (임의로 선택한 인덱스에서 시작하여) 0.


1
세 번째 줄은 수 if (--random < 0) {, 어디에 random도달 -1.
살바도르

3

클로저 솔루션 :

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

1
이 솔루션은 또한 선형입니다. nth요소 를 얻으려면을 횡단해야 하기 때문 seq입니다.
Bruno Kim

1
그것은 한 줄에 잘
맞아서

2

펄 5

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

한 가지 방법이 있습니다.


2

C ++. 전체 세트를 반복하거나 정렬 할 필요가 없으므로 합리적으로 빠릅니다. tr1 을 지원한다고 가정하면 대부분의 최신 컴파일러에서 즉시 사용할 수 있습니다. 그렇지 않으면 Boost를 사용해야 할 수도 있습니다.

부스트 문서는 당신이 부스트를 사용하지 않는 경우에도, 이것을 설명하는 여기에 도움이됩니다.

비결은 데이터가 버킷으로 나뉘어져 있다는 사실을 활용하고 무작위로 선택한 버킷을 적절한 확률로 신속하게 식별하는 것입니다.

//#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

위의 솔루션은 대기 시간 측면에서 말하지만 각 인덱스가 선택 될 가능성은 동일하지 않습니다.
이것이 고려되어야한다면, 저수지 샘플링을 시도하십시오. http://en.wikipedia.org/wiki/Reservoir_sampling .
Collections.shuffle () (몇 안되는 사람)은 그러한 알고리즘 중 하나를 사용합니다.


1

"다른 언어에 대한 솔루션도 환영합니다"라고 말 했으므로 다음은 Python 버전입니다.

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

3
[1,2,3,4,5,6] 만 세트가 아니라 빠른 검색과 같은 기능을 지원하지 않기 때문에 목록입니다.
Thomas Ahle

>>> random.choice (list (set (range (5)))) >>> 4 이상적이지는 않지만 절대적으로 필요한 경우 수행합니다.
사파이어

1

세트 / 배열의 크기 / 길이를 가져 와서 0과 크기 / 길이 사이의 난수를 생성 한 다음 색인이 해당 숫자와 일치하는 요소를 호출 할 수 없습니까? HashSet에는 .size () 메서드가 있습니다.

유사 코드에서-

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

문제의 컨테이너가 임의의 인덱스 조회를 지원하는 경우에만 작동합니다. 많은 컨테이너 구현 (예 : 해시 테이블, 이진 트리, 연결된 목록)은 그렇지 않습니다.
David Haley

1

"set"이 배열이라고 가정하면 PHP는 다음과 같습니다.

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

Mersenne Twister 함수는 더 좋지만 PHP에는 array_rand에 해당하는 MT가 없습니다.


대부분의 세트 구현에는 get (i) 또는 인덱싱 연산자가 없으므로 id는 OP가 세트를 지정한 이유를 가정합니다.
DownloadPizza

1

아이콘 에는 유형이 설정되고 임의 요소 연산자 인 단항 "?"가 있으므로 표현식은

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

1에서 5 사이의 난수를 생성합니다.

임의의 시드는 프로그램이 실행될 때 0으로 초기화되므로 각 실행 사용에서 다른 결과를 생성합니다 randomize()


1

C #에서

        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"]);

엉뚱한 자바 사전 (또는 그와 관계없이 LinkedHashSet이라고도 함)을 "무작위로 액세스"할 수 없기 때문에 다운 키 팅 된 것처럼 보입니다 (키에 의해 액세스되는 것 같습니다). 자바 쓰레기 나를 너무 많이 웃게
페데리코 Berasategui에게

1

자바 스크립트 솔루션;)

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

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

또는 대안으로 :

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

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

나는 두 번째 대안을 선호합니다. :-)
marcospereira

새로운 배열 방법을 추가하는 것을 좋아합니다!
matt lohkamp

1

lisp에서

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

이것은 목록에서만 작동합니다. 로 ELT그 어떤 순서를 위해 일할 수 있습니다.
Ken

1

Mathematica에서 :

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

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

또는 최신 버전에서 간단히 :

RandomChoice[a]

설명이 부족하기 때문에 다운 투표권을 받았으므로 여기에 하나가 있습니다.

Random[]0과 1 사이의 의사 난수 부동 소수점을 생성합니다. 이것은 목록의 길이에 곱한 다음 천장 함수를 사용하여 다음 정수로 올림합니다. 이 색인은에서 추출됩니다 a.

해시 테이블 기능은 Mathematica의 규칙으로 자주 수행되며 규칙은 목록에 저장되므로 다음을 사용할 수 있습니다.

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

1

그냥 어때?

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

1

재미있게 나는 거부 샘플링을 기반으로 RandomHashSet을 작성했습니다. HashMap은 우리가 테이블에 직접 액세스 할 수 없기 때문에 약간 해키이지만 잘 작동합니다.

추가 메모리를 사용하지 않으며 조회 시간이 O (1)로 상각됩니다. (Java HashTable이 조밀하기 때문에).

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
정확히 내가 생각했던 것! 최고의 답변!
mmm

실제로 다시 돌아와서, 해시 맵에 많은 충돌이 있고 많은 쿼리를 수행하면 이것이 균일하지 않다고 생각합니다. Java 해시 맵은 버킷 / 체인을 사용하기 때문에이 코드는 항상 특정 버킷의 첫 번째 요소를 반환합니다. 우리는 여전히 해시 함수의 임의성에 대해 균일합니다.
Thomas Ahle

1

Java 8에서 가장 쉬운 방법은 다음과 같습니다.

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

여기서 n임의의 정수입니다. 물론 그것은 그것보다 성능이 떨어집니다.for(elem: Col)


1

구아바 를 사용하면 Khoth의 답변보다 조금 더 잘 할 수 있습니다.

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 :

$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

또한 집합을 배열 사용 배열로 전송할 수 있습니다. 아마도 작은 규모로 작동합니다.

Object[] arr = set.toArray();

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

0

Set임의성에 대한 보장없이 "에서"임의의 객체를 선택 하려면 가장 쉬운 방법은 반복자가 처음 반환하는 것입니다.

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

1
그러나 이것은 무작위 선택이 아닙니다. 동일한 세트에서 여러 번 동일한 작업을 수행한다고 상상해보십시오. 나는 순서가 같다고 생각합니다.
Menezes Sousa

0

Khoth의 답변을 출발점으로 사용하는 일반적인 솔루션.

/**
 * @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

불행히도 이것은 표준 라이브러리 세트 컨테이너에서 효율적으로 수행 할 수 없습니다 (O (n)보다 낫습니다).

이진 집합뿐만 아니라 해시 집합에 무작위 선택 기능을 추가하는 것이 매우 쉽기 때문에 이상합니다. 희소하지 않는 해시 세트에서는 적중을 얻을 때까지 임의의 항목을 시도 할 수 있습니다. 이진 트리의 경우 최대 O (log2) 단계를 사용하여 왼쪽 또는 오른쪽 하위 트리 중에서 임의로 선택할 수 있습니다. 아래의 데모를 구현했습니다.

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

출력으로 [995, 975, 971, 995, 1057, 1004, 966, 1052, 984, 1001]을 얻었으므로 분포 솔기가 양호합니다.

나는 나 자신을 위해 같은 문제로 어려움을 겪었고, 아직이 더 효율적인 선택의 성능 향상이 파이썬 기반 컬렉션을 사용하는 오버 헤드 가치가 있다고 날씨를 결정하지 않았습니다. 물론 그것을 다듬고 C로 번역 할 수는 있었지만 오늘은 너무 많은 일입니다. :)


1
이것이 바이너리 트리에서 구현되지 않았다고 생각하는 이유는 그러한 방법이 항목을 균일하게 선택하지 않기 때문입니다. 왼쪽 / 오른쪽 자식이없는 노드이므로 왼쪽 자식이 오른쪽 자식보다 많은 항목을 포함하는 경우 (또는 그 반대) 상황이 발생할 수 있으므로 오른쪽 (또는 왼쪽) 자식에서 항목을 선택하는 것이 더 가능성이 높습니다.
Willem Van Onsem

1
@CommuSoft : 그렇기 때문에 각 하위 트리의 크기를 저장하므로이를 기반으로 확률을 선택할 수 있습니다.
Thomas Ahle
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.