карта порівняно з hash_map в C ++


117

У мене питання з hash_mapі mapна C ++. Я розумію, що mapце в STL, але hash_mapце не стандарт. Яка різниця між ними?

Відповіді:


133

Вони реалізуються дуже різними способами.

hash_map( unordered_mapу TR1 та Boost; використовуйте замість них) використовуйте хеш-таблицю, де ключ хешируется до слота в таблиці, а значення зберігається у списку, прив'язаному до цього ключа.

map реалізується як збалансоване дерево бінарного пошуку (зазвичай це червоне / чорне дерево).

Аналіз unordered_mapповинен давати трохи кращі показники доступу до відомих елементів колекції, але mapдодаток матиме додаткові корисні характеристики (наприклад, він зберігається у відсортованому порядку, що дозволяє пройти від початку до кінця). unordered_mapбуде швидше вставляти та видаляти, ніж a map.


7
Я не повністю згоден з вами щодо виступу. На продуктивність впливає цілий ряд параметрів, і я б лаяв будь-якого програміста, що використовує невпорядковану_мапу, лише 10 записів, оскільки "це швидше". Спершу хвилюйтеся щодо інтерфейсу / функціональності, продуктивності пізніше.
Матьє М.

24
Ну так, це допомагає, якщо ви розумієте свою проблему. До певних порядків, мабуть, це дуже добре, але важливо зрозуміти характеристики продуктивності обох контейнерів, оскільки вони різняться різними способами, оскільки об'єм даних збільшується.
Джо

7
Цікаво, що я просто поміняв std :: map на boost :: unordered_map у додатку, в якому я роблю безліч випадкових пошуків, але також перебираю всі клавіші на карті. Я заощадив велику кількість часу на пошуку, але повернув його за допомогою ітерацій, тому повернувся назад до карти та шукаю інші способи підвищення продуктивності програми.
Ерік Гарнісон

4
@ErikGarrison Якщо ви використовуєте випадковий доступ та ітерацію набагато більше, ніж ви вставляєте та видаляєте елементи, ви можете розміщувати свої об’єкти як у дереві, так і у хеш-мапі (зберігаючи покажчик або ще краще спільний_ptr, на ті самі об’єкти обох у якщо ви використовували фактичні екземпляри). Тоді ви отримаєте час доступу (O) (1) через хеш-карту та час ітерації O (n) через карту. Звичайно, ви повинні пам’ятати, щоразу додавати та видаляти вказівники з обох. Ви можете легко написати спеціальний клас контейнерів, який (можливо, також шаблонує його), який би інкапсулював цю поведінку для вас.
спрайт

2
@ErikGarrison Звичайно, якщо ви спробуєте цей метод, ви заплатите за незначну додаткову площу. Однак, оскільки ви використовуєте вказівники, це не повинно бути занадто багато. Якщо ви дійсно хочете, ви можете перейти за борт і написати власну реалізацію AVL та використовувати покажчик вузла як тип даних у hash_map, це надасть вам O (1) час доступу до вузла в дереві, з якого ви зможете лінійно повторювати туди, де вам потрібно. Звичайно, це передбачало б трохи кодування, і я не впевнений, що це окупиться, якщо вам не доведеться багато повторювати з місця та випадкового доступу.
спрайт

35

hash_mapбуло поширеним розширенням, яке надали багато реалізацій бібліотеки. Саме тому він був перейменований, unordered_mapколи він був доданий до стандарту C ++ у складі TR1. карта, як правило, реалізована з врівноваженим бінарним деревом, як червоно-чорне дерево (реалізації залежать від курсу). hash_mapі unordered_mapзазвичай реалізуються за допомогою хеш-таблиць. Таким чином порядок не підтримується. unordered_mapВставити / видалити / запит буде O (1) (постійний час), де на карті буде O (log n), де n - кількість елементів у структурі даних. Так unordered_mapшвидше, і якщо ви не дбаєте про порядок предметів, слід віддавати перевагу над map. Іноді хочеться підтримувати порядок (упорядкований ключем), і для цього mapбув би вибір.


9
Я зазначу, що до хешмапу є найгірший випадок доступу O (N), коли вірогідні зіткнення (поганий хеш-фунц, занадто високий коефіцієнт завантаження тощо)
KitsuneYMG

Хороша хешмап має очікувану вартість O (1), це не гарантовано. Погані хеш-карти можуть мати очікувану вартість, яка не є O (1).
Чіткіший

14

Деякі з ключових відмінностей полягають у вимогах щодо складності.

  • A mapпотрібен O(log(N))час для вставки та пошуку операцій, оскільки він реалізований як структура даних Red-Black Tree .

  • Потрібен unordered_map"середній" час O(1)для вставок та знахідок, але це може бути найгіршим часом O(N). Це тому, що він реалізований за допомогою структури даних Hash Table .

Так, як правило, unordered_mapбуде швидше, але залежно від клавіш і хеш-функції, яку ви зберігаєте, може стати набагато гірше.


4

Специфікація C ++ не говорить точно, який алгоритм потрібно використовувати для контейнерів STL. Однак це ставить певні обмеження щодо їх продуктивності, що виключає використання хеш-таблиць для mapінших та асоціативних контейнерів. (Вони найчастіше реалізуються з червоними / чорними деревами.) Ці обмеження потребують кращої продуктивності для цих контейнерів, ніж їх можуть доставити хеш-таблиці.

Однак багато людей дійсно хочуть хеш-таблиць, тому контейнери-асоціативні контейнери на основі хешу вже багато років є поширеним розширенням. Отже, вони додавали unordered_mapта інше до пізніших версій стандарту C ++.


Він був фактично доданий у TR1 (std :: tr1 :: unordered_map), а не C ++ 0x
Terry Mahaffey

Я вважав, що причина, mapяк правило, врівноважена btree через те, що вона використовує operator<()як засіб визначення місця розташування.
KitsuneYMG

@kts: Чи реально будь-які реалізації STL використовують B-дерево?
bk1e

Технічно всі дерева бінарного пошуку - це b-дерева (1-2 дерева). При цьому, я не знаю жодної STL, яка використовує щось, крім червоного / чорного
KitsuneYMG

@ bk1e "Правильні" B-дерева надзвичайно корисні у базах даних, де потрібно "жирні" дерева-вузли, які добре узгоджуються зі сторінками диска. ОТОХ, це не так корисно для моделі "плоскої" пам'яті, яка використовується в "звичайних" програмах - у всіх реалізаціях STL, які я знаю, використовуються червоно-чорні дерева.
Бранко Димитріевич

3

mapреалізується з balanced binary search tree(як правило, a rb_tree), оскільки всі учасники в balanced binary search treeсортуються, так це карта;

hash_mapреалізовано від hashtable. Тому що всі члени в hashtableнесортовані, тому члени в hash_map(unordered_map)не сортуються.

hash_mapне є стандартною бібліотекою c ++, але тепер вона перейменована на unordered_map(можна подумати про її перейменоване) і стає c ++ стандартною бібліотекою, оскільки c ++ 11 див. це питання. Різниця між hash_map та unororder_map? для більш детальної інформації.

Нижче я наведу основний інтерфейс із вихідного коду того, як реалізується карта двох типів.

карта:

Нижче наведений код лише для того, щоб показати, що карта - лише обгортка balanced binary search tree, майже вся його функція - це лише виклик balanced binary search treeфункції.

template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
    // used for rb_tree to sort
    typedef Key    key_type;

    // rb_tree node value
    typedef std::pair<key_type, value_type> value_type;

    typedef Compare key_compare;

    // as to map, Key is used for sort, Value used for store value
    typedef rb_tree<key_type, value_type, key_compare> rep_type;

    // the only member value of map (it's  rb_tree)
    rep_type t;
};

// one construct function
template<typename InputIterator>
map(InputIterator first, InputIterator last):t(Compare()){
        // use rb_tree to insert value(just insert unique value)
        t.insert_unique(first, last);
}

// insert function, just use tb_tree insert_unique function
//and only insert unique value
//rb_tree insertion time is : log(n)+rebalance
// so map's  insertion time is also : log(n)+rebalance 
typedef typename rep_type::const_iterator iterator;
std::pair<iterator, bool> insert(const value_type& v){
    return t.insert_unique(v);
};

hash_map:

hash_mapреалізується з hashtableструктури якої приблизно так:

введіть тут опис зображення

У наведеному нижче коді я дам основну частину hashtable, а потім дає hash_map.

// used for node list
template<typename T>
struct __hashtable_node{
    T val;
    __hashtable_node* next;
};

template<typename Key, typename Value, typename HashFun>
class hashtable{
    public:
        typedef size_t   size_type;
        typedef HashFun  hasher;
        typedef Value    value_type;
        typedef Key      key_type;
    public:
        typedef __hashtable_node<value_type> node;

        // member data is buckets array(node* array)
        std::vector<node*> buckets;
        size_type num_elements;

        public:
            // insert only unique value
            std::pair<iterator, bool> insert_unique(const value_type& obj);

};

Як map'sтільки член є rb_tree, hash_map'sєдиний член є hashtable. Це основний код, як показано нижче:

template<typename Key, typename Value, class HashFun = std::hash<Key>>
class hash_map{
    private:
        typedef hashtable<Key, Value, HashFun> ht;

        // member data is hash_table
        ht rep;

    public:
        // 100 buckets by default
        // it may not be 100(in this just for simplify)
        hash_map():rep(100){};

        // like the above map's insert function just invoke rb_tree unique function
        // hash_map, insert function just invoke hashtable's unique insert function
        std::pair<iterator, bool> insert(const Value& v){
                return t.insert_unique(v);
        };

};

Нижче на зображенні показано, коли у хеш-мапі є 53 відра, а вставити деякі значення - це внутрішня структура.

введіть тут опис зображення

На зображенні нижче показано деяку різницю між картою та hash_map (unordered_map), зображення походить із способу вибору між картою та unordered_map? :

введіть тут опис зображення


1

Я не знаю, що дає, але для очищення () 150K непідписаних цілих чисел та плаваючих значень потрібно hash_map більше 20 секунд. Я просто біжу і читаю чужий код.

Це, як вона включає hash_map.

#include "StdAfx.h"
#include <hash_map>

Я читав це тут https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap

кажучи, що clear () є порядком O (N). Це для мене дуже дивно, але так воно і є.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.