2015-10-02 3 views
1

Я создал карту unit64_t для uint64_t. Это код, который я написал было проанализировать пространство сложности:Неупорядоченная карта, занимающая много места

#include <bits/stdc++.h> 
#include "sparsehash/internal/sparseconfig.h" 
#include "sparsehash/sparse_hash_map" 

using namespace std; 

int main(int argc, char *argv[]){ 

    std::string input,reference; 

    while (getline(cin,input)) { 
    reference += input; 
    input.clear(); 
    } 

    cout<<"length of reference = "<<reference.length()<<endl; 
    unordered_map<uint64_t, uint64_t> m; 
    //google::sparse_hash_map<uint64_t, pair<short,long>> m; 

    for (auto it = reference.begin(); it != reference.end(); it++) { 
     m[it-reference.begin()]= it-reference.begin(); 
    } 

    return 0; 
} 

Когда я запускаю это с/USR/BIN/время, это выход производится по программе:

length of reference = 4641652 
    Command being timed: "./a.out" 
    User time (seconds): 2.97 
    System time (seconds): 0.15 
    Percent of CPU this job got: 99% 
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.13 
    Average shared text size (kbytes): 0 
    Average unshared data size (kbytes): 0 
    Average stack size (kbytes): 0 
    Average total size (kbytes): 0 
    Maximum resident set size (kbytes): 251816 
    Average resident set size (kbytes): 0 
    Major (requiring I/O) page faults: 0 
    Minor (reclaiming a frame) page faults: 68259 
    Voluntary context switches: 1 
    Involuntary context switches: 104 
    Swaps: 0 
    File system inputs: 0 
    File system outputs: 0 
    Socket messages sent: 0 
    Socket messages received: 0 
    Signals delivered: 0 
    Page size (bytes): 4096 
    Exit status: 0 

Неупорядоченный Кажется, что карта занимает 250 МБ пространства. Это кажется необычно высоким. Почему это произойдет. Тот же код с разрешенным хешем google занимает всего 89 МБ пространства, что более разумно.

Я не понимаю, почему неупорядоченная карта C++ занимает столько места?

+0

Я ничего не вижу, чтобы указать, что использование памяти должно быть больше или меньше 250 МБ. Почему вы думаете, что это большая память? Сколько элементов вы кладете на карту? Учитывали ли вы распределение распределения и обслуживание карты? Рассматривали ли вы предоставление нам соответствующей информации? –

+0

Да, вход представляет собой строку размером 4.5Mb. Я помещаю каждую свою позицию в карту. – user1995120

+0

@ user1995120: если вы сохраняете позиции в строке, которая значительно меньше 4 ГБ (максимально адресуемая с 32-разрядными номерами), и забота об использовании памяти, зачем использовать 64-битные значения? (Если вы хотите сохранить возможность обработки> строк 4 ГБ, вы все равно сможете использовать шаблоны для создания 32- и 64-разрядных версий кода и использовать оптимальный вариант во время выполнения). –

ответ

2

У вас есть 4641652 записей. Таким образом, общий размер необработанных данных составляет 4641652*2*8 byte ~= 74 MB.

Существует важный факт о хэш-таблицах. В быстрых хеш-таблицах много хэш-ведер, а хэш-таблицы с небольшим количеством хэш-кодов медленны.

В основном все сводится к хеш-коллизиям. Если у вас много хэш-ведер (и у вас есть хорошая функция хеширования), то хэш-коллизии случаются редко. Поэтому поиск действительно очень быстрый. С другой стороны, если ваш стол маленький (не много хэш-ковшей), то случайные столкновения происходят регулярно. Таким образом, функция поиска намного медленнее.

std::unordered_map В настоящее время std::unordered_map мужественный desiged как быстрый хеш-стол, поэтому он имеет довольно много накладных расходов. Есть гораздо больше хэш-ведер, чем записи. В этом случае накладные расходы составляют около 250/74 ~= 3.3x, что кажется вполне нормальным.

Но sparsehash предназначен для максимально возможного накладного расхода (около ~ 2 бит на запись). Но, конечно, это означает, что это намного медленнее.

Если вы используете хэш-карту, вы всегда должны думать о том, хотите ли вы скорости или хотите быть эффективной с точки зрения памяти.

+1

В каждом ковше для коллизий (скорее всего, указатель) есть накладные расходы для другого ~ 37 МБ или ~ 121 МБ, и для неиспользуемых ведер (потому что в списке ведер много пустых ведер). Кроме того, память, используемая старым, более коротким массивом ковша с момента последнего перепрограммирования карты. – 1201ProgramAlarm

+0

@ 1201ProgramAlarm: зависит от реализации. Обработка столкновений с помощью связанных списков будет действовать, как вы описываете, но обработка столкновений посредством цепочки (так что столкновение хэшей ставит вторую запись где-то еще предсказуемым образом) не будет иметь этих накладных расходов (хотя для этого потребуется использовать маркеры для ранее заполненных ковшей поэтому алгоритм цепочки может найти перемещенную запись, если исходная запись впоследствии будет удалена).Python использует цепочку, а не списки; не удивлялись бы, если бы некоторые продавцы делали то же самое, по крайней мере, для некоторых случаев. – ShadowRanger

+1

@ShadowRanger: ["chaining"] (https://en.wikipedia.org/wiki/Hash_table#Separate_chaining_with_linked_lists) - еще один термин, используемый для связывания списков сталкивающихся элементов - то, что вы описываете (и используется питоном), известно как * открытая адресация * или * закрытое хеширование *. И никакие реализации 'std :: unordered_map' не используют этот метод - он несовместим с требованиями стандарта (в частности, по умолчанию« max_load_factor »1.0 и только переименовывается, когда это превышено). –

Смежные вопросы