Обычный способ выбрать случайный элемент из связанного списка - дать шанс 1/1, 1/2, 1/3, ..., 1 / n заменить выбранный элемент текущим элементом в каждая ссылка.
#include <cstdlib>
#include <ctime>
#include <iostream>
namespace {
template<typename T>
T randomPickerHelper(int& sz, T first) {
return first;
}
template<typename T, typename ...Args>
T randomPickerHelper(int& sz, T first, Args ...rest) {
T next = randomPickerHelper(sz, rest...);
return std::rand() % ++sz ? next : first;
}
}
template<typename T, typename... Args>
T randomPicker(T first, Args ...rest) {
int sz = 1;
return randomPickerHelper(sz, first, rest...);
}
int main() {
std::srand(std::time(0));
for (int i = 0; i < 1000000; ++i) {
std::cout << randomPicker(1, 2, 3, 4, 5) << std::endl;
}
return 0;
}
Звонит rand()
много раз, хотя.
template<typename T, typename ...Args>
struct Count {
static const int sz = Count<Args...>::sz + 1;
};
template<typename T>
struct Count<T> {
static const int sz = 1;
};
template<typename T>
T pick(int n, T first) {
return first;
}
template<int N, typename T, typename ...Args>
T pick(int n, T first, Args ...rest) {
if (n == Count<T, Args...>::sz) {
return first;
}
return pick(n, rest...);
}
template<typename T, typename ...Args>
T randomPicker(T first, Args ...rest) {
return pick(std::rand() % Count<T, Args...>::sz + 1, first, rest...);
}
Мне кажется, это возможно, но GCC 4.6.0 не поддерживает расширение <Args...>
.