簡體   English   中英

C ++ STL unordered_map如何解決沖突?

[英]How does C++ STL unordered_map resolve collisions?

C ++ STL unordered_map如何解決沖突?

查看http://www.cplusplus.com/reference/unordered_map/unordered_map/ ,它顯示“唯一鍵容器中沒有兩個元素可以具有等效鍵。”

這應該意味着容器確實解決了碰撞。 但是,該頁面並沒有告訴我它是如何做到的。 我知道一些解決沖突的方法,比如使用鏈表和/或探測。 我想知道的是c ++ STL unordered_map如何解析它。

該標准比大多數人似乎意識到的更多地定義了這一點。

具體而言,該標准要求(§23.2.5/ 9):

無序關聯容器的元素被組織成桶。 具有相同哈希碼的密鑰出現在同一個存儲桶中。

該接口包括一個在恆定時間內運行的bucket_count (表103)。 它還包括一個bucket_size ,它必須按時間線性運行桶的大小。

這基本上描述了使用沖突鏈的實現。 當您使用碰撞鏈時,滿足所有要求介於簡單和簡單之間。 bucket_count()是數組中元素的數量。 bucket_size()是沖突鏈中的元素數。 分別使它們處於恆定和線性時間是簡單而直接的。

相比之下,如果使用線性探測或雙重散列等方法,那些要求幾乎不可能滿足。 具體來說,所有散列到特定值的項目都需要在同一個桶中着陸,並且您需要能夠在恆定時間內對這些桶進行計數。

但是,如果你使用線性探測或雙重散列之類的東西,找到散列到相同值的所有項目意味着你需要散列值,然后遍歷表格中非空項目的“鏈”以查找有多少那些哈希值相同。 但是,對於散列到相同值的項目數,這並不是線性的 - 它與散列到相同沖突值的項目數呈線性關系。

有了足夠的額外工作和相當多的要求將某些要求的含義拉伸到斷點,幾乎不可能使用除碰撞鏈之外的其他東西來創建哈希表,並且至少仍然滿足要求 - - 但我不確定這是可能的,而且肯定會涉及很多額外的工作。

簡介: std::unordered_set (或unordered_map )的所有實際實現無疑都使用了碰撞鏈接。 雖然可能(幾乎不可能)使用線性探測或雙重散列來滿足要求,但這樣的實現似乎失去了很多並且幾乎沒有任何回報。

我找到了這個答案,尋找如何檢測我的類型何時發生碰撞,所以我會發布這個以防問題的意圖:

我相信有一些誤解,“獨特的密鑰容器中沒有兩個元素可以擁有相同的密鑰。”

看下面的代碼

//pseudocode
std::unordered_map<int, char> hashmap;
hashmap[5] = 'a';
hashmap[5] = 'b'; //replace 'a' with 'b', there is no collision being handled.

我認為Jerry的答案是指它用來將鍵縮小到適當的數組索引的內部系統。

如果你想要為你的類型(使用存儲桶)處理沖突,你需要std::unordered_multimap並且必須迭代

希望這個代碼可以在沒有我生成它的上下文的情況下讀取。 它基本上檢查以查看與散列關聯的存儲桶中的任何元素是否是我正在尋找的元素。

//sp is std::shared_ptr
//memo is std::unordered_multimap< int, sp<AStarNode> >

//there's probably multiple issues with this code in terms of good design (like using int keys rather than unsigned)

bool AStar_Incremental::hasNodeBeenVisited(sp<AStarNode> node)
{
    using UMIter = std::unordered_multimap<int, sp<AStarNode> >::iterator;

    bool bAlreadyVisited = false;

    //get all values for key in O(1*)
    int hash = WorldGrid::hashGrid(node->location);
    std::pair<UMIter, UMIter> start_end = memo.equal_range(hash); //bucket range
    UMIter start = start_end.first;
    UMIter end = start_end.second;

    //hopefully this is implemented to be O(m) where m is the bucket size.
    for(UMIter bucketIter = start; bucketIter != end; ++bucketIter)
    {
        sp<AStarNode> previousNode = bucketIter->second;
        sf::Vector2i& previousVisit = previousNode->location;
        if (previousVisit == node->location)
        {
            bAlreadyVisited = true;
            break;
        }
    }

    return bAlreadyVisited;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM