1

据我所知,在 C++ (STL) 甚至 C++1y 中都没有双义映射数据结构/ADT。但我需要一个排序的关联容器,它允许我将键集映射到值集,反之亦然。

什么是最好的方法或现有的解决方案?

我的建议是:

#!/usr/bin/env bash -vex
# cls ; bash self.bash 2>&1 | tee self.log | less
WARN="-W -Wall -Wextra -Werror"
g++ -x c++ - -std=gnu++1y $WARN -Ofast -o a <<__EOF && ./a && echo -e "\e[1;32msucceeded\e[0m" || echo -e "\e[1;31mfailed\e[0m"
#include <list>
#include <tuple>
#include <map>
#include <functional>

#include <string>

#include <cstdlib>
#include <cassert>

template< typename A, typename B >
class bijection
{

    using data_type = std::list< std::tuple< A const, B const > >;

public :

    using iterator = typename data_type::iterator;
    using const_iterator = typename data_type::const_iterator;

private :

    using direct_mapping_type = std::map< std::reference_wrapper< A const >, iterator, std::less< A const & > > ;
    using inverse_mapping_type = std::map< std::reference_wrapper< B const >, iterator, std::less< B const & > >;
    using direct_iterator = typename direct_mapping_type::iterator;
    using inverse_iterator = typename inverse_mapping_type::iterator;

public :

    auto size() const { return data_.size(); }

    iterator find(A const & a)
    {
        auto const direct = direct_mapping_.find(a);
        if (direct == direct_mapping_.end()) {
            return data_.end();
        } else {
            return direct->second;
        }
    }

    iterator find(B const & b)
    {
        auto const inverse = inverse_mapping_.find(b);
        if (inverse == inverse_mapping_.end()) {
            return data_.end();
        } else {
            return inverse->second;
        }
    }

    auto erase(iterator pos)
    {
        auto const & element = *pos;
        direct_mapping_.erase(std::get< 0 >(element));
        inverse_mapping_.erase(std::get< 1 >(element));
        return data_.erase(pos);
    }

    template< typename X, typename Y >
    std::tuple< iterator, bool, bool > insert(X && x, Y && y)
    {
        direct_iterator direct = direct_mapping_.find(x);
        inverse_iterator inverse = inverse_mapping_.find(y);
        bool const d = (direct != direct_mapping_.end());
        bool const i = (inverse != inverse_mapping_.end());
        if (d && i) {
            iterator ix = inverse->second;
            iterator iy = direct->second;
            inverse_mapping_.erase(inverse);
            direct_mapping_.erase(direct);
            if (ix != iy) {
                inverse_mapping_.erase(std::get< 1 >(*iy));
                direct_mapping_.erase(std::get< 0 >(*ix));
                data_.erase(iy);
                data_.erase(ix);
            } else {
                data_.erase(ix); // iy
            }
        } else if (d) {
            iterator iy = direct->second;
            direct_mapping_.erase(direct);
            inverse_mapping_.erase(std::get< 1 >(*iy));
            data_.erase(iy);
        } else if (i) {
            iterator ix = inverse->second;
            inverse_mapping_.erase(inverse);
            direct_mapping_.erase(std::get< 0 >(*ix));
            data_.erase(ix);
        }
        data_.emplace_back(std::forward< X >(x), std::forward< Y >(y));
        auto const & element = data_.back();
        iterator it = --data_.end();
        direct_mapping_.emplace(std::get< 0 >(element), it);
        inverse_mapping_.emplace(std::get< 1 >(element), it);
        return std::make_tuple(it, d, i);
    }

private :

    data_type data_;
    direct_mapping_type direct_mapping_;
    inverse_mapping_type inverse_mapping_;

};

int main()
{
    using A = std::size_t;
    using B = std::string;
    using M = bijection< A, B >;
    M m;
    assert(1 == (m.insert(A(111), B("111")), m.size()));
    assert(1 == (m.insert(A(111), B("111")), m.size()));
    assert(2 == (m.insert(A(222), B("222")), m.size()));
    assert(3 == (m.insert(A(333), B("333")), m.size()));
    assert(2 == (m.insert(A(222), B("111")), m.size()));
    assert(3 == (m.insert(A(111), B("222")), m.size()));
    assert(2 == (m.insert(A(111), B("111")), m.size()));
    assert(1 == (m.insert(A(333), B("111")), m.size()));
    assert(1 == (m.insert(A(333), B("333")), m.size()));
    assert(1 == (m.insert(A(111), B("333")), m.size()));
    assert(0 == (m.erase(m.find(A(111))), m.size()));
    return EXIT_SUCCESS;
}
__EOF
4

1 回答 1

6

如果你需要一些已经测试过的东西,你可以使用Boost Bimap库。

于 2013-08-19T18:42:38.510 回答