STL には、これにすぐに適したデータ構造はありませんが、これを実装する簡単でかなり効率的な方法の 1 つは、マップとポインターのベクトルを使用することです。はmap
オブジェクトを配列内のインデックスにマップし (オブジェクトが存在するかどうかのチェックが効率的であり、オブジェクトが既に存在する場合はインデックスをすぐに利用できるようにするため) vector
、マップ内のオブジェクトにインデックスをマップします (そのため、インデックスによるオブジェクトの取得は効率的です)。
std::map<T,size_t> objects;
std::vector<const T *> indexed;
要素を追加するには:
size_t add_element(const T &v) {
std::map<T,size_t>::iterator it=objects.find(v);
if(it==objects.end()) {
it=objects.insert(std::map<T,size_t>::value_type(v,objects.size())).first;
indexed.push_back(&it->first);
}
return it->second;
}
(個人的なスタイルによる明らかな変更は、マップ イテレータのベクトルを格納し、毎回 map::insert を使用し、結果の bool 部分をチェックしてindexed
更新が必要かどうかを確認することなどです。)
要素を取得するには:
const T &get_element(size_t index) {
return *indexed[index];
}
そして、それはそれです。もちろん、1 つの問題は、オブジェクトがセットに含まれると、変更できないことです。これは、ここで実装された方法からの一種のリークです。マップ キーは const であるため、明らかな理由がありますが、実際には、実装に関係なく、とにかく必要なものだと思います。重複がないことを主張している場合は、オブジェクトがリストに入ると、変更によって別のオブジェクトの複製になる場合に備えて、変更可能であってはなりません。
size_t
(また、ここで使用して少しごまかしていることにも注意してください。std::vector<const T *>::size_type
より正確には正しいと思います。これは主に簡潔にするためです!)