109 lines
2 KiB
C++
109 lines
2 KiB
C++
//
|
|
// This source code is property of the Computer Graphics and Visualization
|
|
// chair of the TU Dresden. Do not distribute!
|
|
// Copyright (C) 2015-2017 CGV TU Dresden - All Rights Reserved
|
|
//
|
|
#pragma once
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include <random>
|
|
|
|
|
|
/*
|
|
Usage:
|
|
|
|
//C++0x Random Engine Mersenne Twister
|
|
std::mt19937 eng;
|
|
|
|
//a set data structure with amortize constant time insertion, removal, and uniform random sampling from its elements
|
|
sample_set<int> my_set;
|
|
my_set.reserve(3);
|
|
|
|
my_set.insert(1);
|
|
my_set.insert(2);
|
|
my_set.insert(6);
|
|
|
|
int rand_elem1 = my_set.sample(eng);//1,2 or 6
|
|
my_set.remove(2);
|
|
|
|
int rand_elem2 = my_set.sample(eng); //1 or 6
|
|
|
|
*/
|
|
|
|
|
|
template <typename T>
|
|
struct sample_set
|
|
{
|
|
|
|
typedef int element_index;
|
|
std::vector<T> elements;
|
|
std::unordered_map<T,element_index> index_lut;
|
|
|
|
|
|
//create empty set
|
|
sample_set(){}
|
|
|
|
//reserve memory for n elements
|
|
void reserve(size_t n)
|
|
{
|
|
elements.reserve(n);
|
|
index_lut.rehash(n);
|
|
}
|
|
|
|
//insert element elem into set
|
|
void insert(const T& elem)
|
|
{
|
|
//guard against duplicates
|
|
if (index_lut.find(elem) == index_lut.end())
|
|
{
|
|
element_index idx = (element_index)elements.size();
|
|
elements.push_back(elem);
|
|
index_lut[elem]=idx;
|
|
}
|
|
}
|
|
|
|
//remove element elem from set
|
|
bool remove(const T& elem)
|
|
{
|
|
auto it = index_lut.find(elem);
|
|
if(it == index_lut.end())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int i = it->second;
|
|
|
|
std::swap(elements[i],elements.back());
|
|
elements.pop_back();
|
|
|
|
index_lut.erase(it);
|
|
if(unsigned(i) < elements.size())
|
|
{
|
|
index_lut[elements[i]]=i;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//draw a sample from set
|
|
template <typename Engine>
|
|
const T& sample(Engine& eng)
|
|
{
|
|
int b = (element_index)(elements.size()-1);
|
|
std::uniform_int_distribution<int> uniform_dist(0,b);
|
|
element_index idx = uniform_dist(eng);
|
|
return elements[idx];
|
|
}
|
|
|
|
//returns number of elements in set
|
|
size_t size() const
|
|
{
|
|
return elements.size();
|
|
}
|
|
|
|
//returns true if set is empty
|
|
bool empty() const
|
|
{
|
|
return elements.empty();
|
|
}
|
|
|
|
};
|