2012-02-18 87 views
16

Tôi có một vector chứa các phần tử n. Tôi cần chọn một tập hợp con gồm các phần tử m ngẫu nhiên từ vectơ mà không lặp lại. Cách hiệu quả nhất để làm điều này là gì? Tôi cần phải làm điều này vài nghìn lần trong mã của tôi.Chọn các phần tử m một cách ngẫu nhiên từ một vector chứa các phần tử n

Giải pháp trên đầu tôi là sử dụng rand() để tạo số ngẫu nhiên k giữa 0n. Sau đó chọn phần tử thứ k trong vectơ và chèn nó vào một std::set. Tiếp tục làm điều này cho đến khi kích thước của bộ này bằng m. Bây giờ tôi đã đảm bảo rằng tập hợp chứa m các yếu tố độc đáo được chọn ngẫu nhiên từ tập hợp các yếu tố n.

Các giải pháp khả thi khác là gì?

Cảm ơn.

+4

làm 'std: : random_shuffle() 'trên vectơ và kéo các phần tử' m' đầu tiên ra khỏi nó, có lẽ? – jrok

+0

@jrok: trong khi đơn giản, đó là _highly không hiệu quả khi 'm' nhỏ hơn nhiều so với' n'. –

+0

có thể trùng lặp của [Thuật toán để chọn một kết hợp đơn lẻ, ngẫu nhiên của các giá trị?] (Http://stackoverflow.com/questions/2394246/algorithm-to-select-a-single-random-combination-of-values) –

Trả lời

29

Bạn muốn có một Fisher-Yates shuffle (dừng sau khi M lặp):

template<class BidiIter > 
BidiIter random_unique(BidiIter begin, BidiIter end, size_t num_random) { 
    size_t left = std::distance(begin, end); 
    while (num_random--) { 
     BidiIter r = begin; 
     std::advance(r, rand()%left); 
     std::swap(*begin, *r); 
     ++begin; 
     --left; 
    } 
    return begin; 
} 

Demo tại http://ideone.com/3A3cv. Tốc độ này nhanh hơn đáng kể so với std::random_shuffle khi bạn chỉ cần một vài số ngẫu nhiên trong tập hợp và sẽ chỉ ở cùng tốc độ ngay cả khi N==M.

+0

@ Burr Cảm ơn! Tôi có một triệu phần tử trong vector của mình, trong đó tôi chỉ cần chọn ngẫu nhiên 100 phần tử. Điều này thật đúng với gì mà tôi đã tìm kiếm. – Vinay

+0

Cảm ơn bạn đã nhập mã! Hoạt động hoàn hảo. – Danvil

+2

rand(): xem http://codereview.stackexchange.com/questions/39001/fisher-yates-modern-shuffle-algorithm – dani

3

Một cách để bạn có thể làm điều này là để tạo ra một danh sách tất cả các chỉ số của vector, shuffle họ, và lấy n đầu tiên được các chỉ số của các đối tượng được lựa chọn:

struct rangegenerator { 
    rangegenerator(int init) : start(init) { } 

    int operator()() { 
     return start++; 
    } 

    int start; 
}; 

vector<T> numbers; // this is filled somewhere else 

vector<int> indices(numbers.size()); 

generate(begin(indices), end(indices), rangegenerator(0)); 

random_shuffle(begin(indices), end(indices)); 

// then take the first n elements of indices and use them as indices into numbers 
+3

Khi 'm' nhỏ hơn nhiều so với' n', điều này rất không hiệu quả. Nó không khó để đưa ra một câu trả lời đó là nhanh hơn này cho tất cả 'm' (nơi' m' là ít hơn 'n') –

+0

@Seth: Sẽ phải đồng ý với Moo. Đây có lẽ là một trong những cách tồi tệ nhất để hoàn thành nhiệm vụ nhất định - không chắc tại sao OP đánh dấu nó như một câu trả lời. Câu trả lời đúng là câu trả lời của Burr. –

+1

@JaredKrumsie OP hỏi về "các giải pháp khả thi khác" và những gì tôi viết chắc chắn là một giải pháp khả thi. Cách duy nhất một câu trả lời sẽ không chính xác là nếu nó không hoạt động chút nào. –

Các vấn đề liên quan