双方向の地図について、より効率的な実装はありますか?
質問
私は簡単な
双方向マップ
クラスを作成しました。
std::map
インスタンスを内部的に保存し、ユーザーフレンドリーなインタフェースを提供します。
template<class T1, class T2> class Bimap
{
std::map<T1, T2> map1;
std::map<T2, T1> map2;
// ...
};
-
2 倍のメモリを必要としない、より効率的な双方向マップの実装方法はありますか?
-
バイマップは通常どのように実装されるのですか?
EDITです。
-
bimap要素はmutableとimmutableのどちらであるべきですか? (の要素を変更することはできません。
map1
のキーを変更する必要があります。map2
のキーを変更する必要がありますが、キーは const であり、それは不可能です - 解決策は?) -
ユーザーがバイマップにキーと値のペアを挿入すると、バイマップはそのキーと値のペアのコピーを作成して保存し、その後内部の2番目のマップ(キーと値が反転している)はコピーせず、元のペアを指すようにすべきなのです。これはどのように実現できるのでしょうか?
EDIT 2:
どのように解決するのですか?
バイマップのすべての単純な実装において、データを二重に保存することには一定の問題があります。もし、外部からのポインタのバイマップに分解することができれば、これを容易に無視することができ、単に両方のマップをフォームの
std::map<A*,B*>
という形式にしておけばよいのです。
A->A*
のルックアップを避けるために、外部からのストレージを気にする必要があります)。しかし、どうせポインタがあるのなら、単純に
std::pair<A,B>
を格納する場所に
A
と
B
を別々にするのですか?
があると良いですね。
std::map<A,B*>
の代わりに
std::map<A*,B*>
に変更することで、例えば、文字列に関連付けられた要素を、ペアを作成した元の文字列へのポインタの代わりに、同じ内容を持つ新しく作成された文字列で検索することができるようになるからです。しかし、各エントリーにキーの完全なコピーを保存し、正しいバケットを見つけるためにハッシュにのみ依存することが通例です。こうすれば、ハッシュが衝突した場合でも、返される項目は正しいものになります...。
しかし、もしあなたが素早く、そして汚くしたいのであれば、次のような方法があります。
ハキハキとした解決策です。
2つのマップを作成する
std::map<size_t, A> mapA
とstd::map<size_t, B> mapB
. 挿入時に、挿入される両方の要素をハッシュ化し、それぞれのマップのキーを取得します。void insert(const A &a, const B &b) { size_t hashA = std::hash<A>(a); size_t hashB = std::hash<B>(b); mapA.insert({hashB, a}); mapB.insert({hashA, b}); }
Lookupも同様に実装されています。
を使うことで
multimap
の代わりに
map
を使うようにし、取得したすべての要素をそれぞれ他のマップのルックアップで確認します(取得候補の
b
から
mapA
ハッシュ
b
を検索し
mapB
を探し、それが目的のキーと一致すれば、次の候補に反復する b そうでなければ、これは有効な実装です。
エントリーを比較するために使用される要素のコピー (上記参照) をストレージとしてのみ使用することで、より優れたソリューションが得られます。しかし、それを理解するのは少し難しいです。詳しく説明すると
より良い解決策です。
として2組のペアを作成します。
std::set<pair<A, B*>>
とstd::set<pair<B, A*>>
をオーバーロードしoperator<
とoperator==
のように、ペアの最初の要素だけを考慮に入れるようにします(または、対応する比較クラスを提供します)。マップの代わりにペアのセットを作成する必要があります(内部的には同じように見えますが)。A
とB
はメモリ上で一定の位置にある。を挿入するとpair<A, B>
が挿入されると、それを上記のセットに適合する2つの要素に分割する。
std::set<pair<B, A*>> mapA;
std::set<pair<A, B*>> mapB;
void insert(const A &a, const B &b) {
auto aitr = mapA.insert({b, nullptr}).first; // creates first pair
B *bp = &(aitr->first); // get pointer of our stored copy of b
auto bitr = mapB.insert({a, bp}).first;
// insert second pair {a, pointer_to_b}
A *ap = &(bitr->first); // update pointer in mapA to point to a
aitr->second = ap;
}
<ブロッククオート
ルックアップがシンプルに行えるようになりました。
std::set
のルックアップとポインタのデリファレンスで行えるようになりました。
このより良い解決策は、boostが使用する解決策に似ています - 彼らはペアの2番目の要素としていくつかの匿名化されたポインタを使用し、したがって
reinterpret_cast
s.
なお、この
.second
の部分のペアはmutableである必要があることに注意してください(だから、私は
std::pair
が使えるかどうかはわかりません)、あるいは別の抽象化されたレイヤーを追加する必要があります (
std::set<pair<B, A**>> mapA
) を追加しなければなりません。どちらの解決策でも、要素への非恒等式の参照を返すために一時的な要素が必要です。
関連
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】Enterキーを押して続行する
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++エラー。アーキテクチャ x86_64 に対して未定義のシンボル
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み】fpermissiveフラグは何をするのですか?
-
[解決済み】「Expected '(' for function-style cast or type construction」エラーの意味とは?
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー