如何通过迭代到最大值来填充stl :: map?

时间:2018-10-08 12:23:58

标签: c++

我有一个std::map,我使用以下方法来填充所提供数据类型的最大值。在这种情况下,如果Kint,则最大值为2,147,483,647。我希望我的地图具有2,147,483,647键,且键值相同。

下面的循环效率很低。有什么方法可以减少时间消耗?

for (auto i = keyBegin; i!=numeric_limits<K>::max(); i++) { 
    m_map[i] = val;
}

3 个答案:

答案 0 :(得分:5)

上面的代码的问题是,您要在地图末尾插入20亿个数字。但是 public class CustomerBuilder { private Customer customer = new Customer(); public CustomerBuilder setName(String name){ customer.setName(name); return this; } public CustomerBuilder setSurname(String surname){ customer.setSurname(surname); return this; } public CustomerBuilder setAge(int age){ customer.setAge(age); return this; } public CustomerBuilder setEmail(String email){ customer.setEmail(email); return this; } public Customer build() { return customer; } } public class OrderBuilder { private Order order = new Order(); public OrderBuilder setCustomer(Customer customer){ order.setCustomer(customer); return this; } public OrderBuilder setProduct(Product product){ order.setProduct(product); return this; } public OrderBuilder setQuantity(int quantity){ order.setQuantity(quantity); return this; } public OrderBuilder setOrderDate(LocalDate orderDate){ order.setOrderDate(orderDate); return this; } public Order build(){ return order; } } public class ProductBuilder { private Product product = new Product(); public ProductBuilder setCategory(Category category){ product.setCategory(category); return this; } public ProductBuilder setName(String name){ product.setName(name); return this; } public ProductBuilder setPrice(BigDecimal bigDecimal){ product.setPrice(bigDecimal); return this; } public Product build() { return product; } } 不知道您将在其中插入新项目!

operator[]是您所需要的。您有一个完美的提示-所有值都将直接插入std::map::insert(hint_before, value)

之前

答案 1 :(得分:2)

要补充现有的答案,实际上不是std::map的好用法。

地图旨在快速查找键和值的集合,其中键是“稀疏”的。它们通常被实现为树,需要大量的动态分配,树重新平衡以及牺牲缓存位置。对于一般的地图用例来说,这是值得的。

但是您的键远没有稀疏!您实际上在键类型范围内为每个可能的数字都有一个值。 这是数组的用途

使用数组,您将受益于缓存,您将受益于恒定时间的查找,并且您将不需要在容器内部进行任何动态分配。当然,由于巨大,您将需要动态分配容器本身,因此,您正在寻找std::vector

仅当您真的需要预先计算所有这些值时,才可以。如果您不一定需要全部使用它们,请考虑按需生成它们。因为,无论现代PC可以为您提供多少RAM,这听起来都像是对该技术的滥用。

答案 2 :(得分:0)

为补充MSalters的答案,建议使用map::insert(hint, {key, value})构造,我建议使用非默认分配器。专门的分配器可以进一步加快插入速度。考虑以下琐碎的分配器:

template <class T>
class chunk_allocator
{
private:
    struct node
    {
        union
        {
            node *next;
            char element[sizeof(T)];
        };
    };
public:
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using is_always_equal = std::false_type;
    using propagate_on_container_move_assignment = std::true_type;
    T*allocate(std::size_t n)
    {
        if (n > 1)
            return reinterpret_cast<T*>(::operator new(sizeof(T) * n));
        if (!m_free_head) populate();
        node * head = m_free_head;
        m_free_head = head->next;
        using node_ptr = node*;
        head->next.~node_ptr();
        return reinterpret_cast<T*>(&head->element);
    }
    void deallocate(T* p, std::size_t n) {
        if (!p)
            return;
        if (n > 1) {
            ::operator delete((void*)p);
            return;
        }
        node * new_head = new ((void*)p) node;
        new_head->next = m_free_head;
        m_free_head = new_head->next;
    }
private:
    static constexpr unsigned NODES_IN_CHUNK = 1000;

    void populate()
    {
        if (m_free_head) return;
        m_chunks.emplace_back();
        for (node & entry : m_chunks.back()) {
            entry.next = m_free_head;
            m_free_head = &entry;
        }
    }

    std::list<std::array<node, NODES_IN_CHUNK>> m_chunks;
    node * m_free_head = nullptr;
};

template< class T1, class T2 >
bool operator==( const chunk_allocator<T1>& a, const chunk_allocator<T2>& b )
{
    return (void*)&a == (void*)&b;
}
template< class T1, class T2 >
bool operator!=( const chunk_allocator<T1>& a, const chunk_allocator<T2>& b )
{
    return !(a == b);
}           

及其用途:

std::map<int, int, std::less<int>,
         chunk_allocator<std::pair<const int, int >>> m_map;

工作100,000,000个元素(在Windows上使用cygwin):

  • std :: allocator:插入:7.987,破坏:7.238
  • chunk_allocator:插入:2.745,破坏:1.357

在Linux上,差异并不大,但仍有可能提高2倍。

加分点-chunk_allocator占用较少的内存,因为它不对单个operator new节点使用map。每次对operator new的调用都必须维护内存管理簿记,chunk_allocator不必这样做。