我有一个std::map
,我使用以下方法来填充所提供数据类型的最大值。在这种情况下,如果K
为int
,则最大值为2,147,483,647
。我希望我的地图具有2,147,483,647
键,且键值相同。
下面的循环效率很低。有什么方法可以减少时间消耗?
for (auto i = keyBegin; i!=numeric_limits<K>::max(); i++) {
m_map[i] = val;
}
答案 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):
在Linux上,差异并不大,但仍有可能提高2倍。
加分点-chunk_allocator
占用较少的内存,因为它不对单个operator new
节点使用map
。每次对operator new
的调用都必须维护内存管理簿记,chunk_allocator
不必这样做。