簡體   English   中英

選擇哪種容器進行海量數據快速搜索/插入?

[英]What container to choose for fast search/insert with huge amounts of data?

所以這是一個思想實驗。 我想收集大量的結構,例如:

struct
{
    KeyType key;
    ValueType value;
}

而且我需要通過鍵快速訪問並快速插入新值。

我不會使用std :: map cuz,因為它對於一種結構和大量數據而言都具有太大的內存開銷,這可能太過誇張了。 對?

因此,接下來我將考慮使用已排序的std :: vector和binary_search。 搜索很好,但是向向量添加新值將太慢。 假設您需要在已排序數組的開頭添加一個新值,則必須將數據直接移動到aaaaaAAAALOT!

如果我使用雙端隊列怎么辦? 據我所知,它對於push_back / push_front具有O(1),但對於插入仍然具有O(n)(因為無論如何它都必須移動數據,但是要減少數據)。

問題是:

1)在實際情況下,在雙端隊列中插入數據的O(n)是否比矢量中的O(n)快得多?

2)當您向Deque插入值並且應該放入的存儲桶已滿時,會發生什么?

3)如果您需要存儲大量數據並需要兩個快速操作(搜索和插入),是否還有另一種更好的容器類型?

謝謝!

我不會使用std :: map cuz,因為它對於一種結構和大量數據而言都具有太大的內存開銷,這可能太過誇張了。 對?

這取決於結構的大小...結構越大,開銷占總內存使用的比例就越小。 例如,一個std::map實現可能每個元素平均說出20個字節的整理數據(我剛剛整理了這個-在您自己的系統上衡量),因此,如果您的結構大小在數百個字節中-誰在乎... ? 但是,如果該結構包含2個intsints很大比例。

因此,接下來我將考慮使用已排序的std :: vector和binary_search。 搜索很好,但是向向量添加新值將太慢。 假設您需要在已排序數組的開頭添加一個新值,則必須將數據直接移動到aaaaaAAAALOT!

完全不合適...

1)在實際情況下,在雙端隊列中插入數據的O(n)是否比矢量中的O(n)快得多?

由於deque可能是固定大小的數組的向量,因此插入意味着將所有元素都拖向容器的最近端。 改組的緩存效率可能會略低一點,但是如果將其插入更靠近容器的前端,則可能仍會更快地結束。

2)當您向Deque插入值並且應該放入的存儲桶已滿時,會發生什么?

如上,它需要改組,溢出:

  • 最后一個元素成為下一個“存儲桶”的第一個元素,將所有這些元素移動並溢出到下一個存儲桶,依此類推。

  • 第一個元素成為上一個存儲桶的最后一個元素,將所有這些元素移動並溢出到下一個存儲桶,依此類推。

3)如果您需要存儲大量數據並需要兩個快速操作(搜索和插入),是否還有另一種更好的容器類型?

unordered_map ,它實現為哈希圖。 如果您有小的對象(例如,少於20個或30個字節)或對元素數量有固定的限制,通常可以使用自定義代碼輕松勝過unordered_map ,但是除非表訪問控制了您應用程序的性能,否則很少值得付出努力。性能至關重要。

3)如果您需要存儲大量數據並需要兩個快速操作(搜索和插入),是否還有另一種更好的容器類型?

考慮使用std::unordered_map ,它是哈希映射的實現。 在一般情況下,插入,查找和刪除都是O(1)。 假設您只會根據項目的確切關鍵字來尋找項目; 如果您的搜索可能具有不同的約束,則您可能需要不同的結構,或者您需要多個映射來將要搜索的各種鍵映射到相應的對象。

這就要求KeyType有一個可用的哈希函數,它可以作為標准庫的一部分,也可以由您提供。

沒有可以為您提供世界上最好的容器。 就像您說的那樣,您希望以最少的存儲元素所需的空間來實現最佳查找/插入。

下面是您可以考慮用於實現的容器列表:-

矢量:-

優勢:

1) Space is allocated only for holding data. 
2) Good for random access.
3) Container of choice if insertions/deletions are not in the middle of the container.

弱點:-

1) poor performance if insertions/deletions are at the middle.
2) rellocations happen if reserve is not used properly.

要求:-

如果插入/刪除在容器的開頭和結尾,請在向量上選擇雙端隊列。

地圖:-

劣勢於載體:-

1) more space is allocated for holding pointers.

優於向量的優勢:-

1) better insertions/deletions/lookup as compared to vector.

如果使用std::unordered_map ,則這些字典操作將攤銷O(1)。

首先,為了直接回答您的問題:

1)在實際情況下,在雙端隊列中插入數據的O(n)是否比矢量中的O(n)快得多?

與矢量相比,必須移動的元素數量(平均)只有一半。 但是,由於數據存儲在不連續的內存中,因此它實際上可能會更糟,因此復制/移動相同數量的元素的效率要低得多(例如,不能通過單個內存復制操作來實現)。

2)當您向Deque插入值並且應該放入的存儲桶已滿時,會發生什么?

至少對於gnu gcc Libstdc ++實現,除第一個和最后一個桶之外的每個存儲桶總是滿的。 我相信,在中間插入意味着所有元素都被移動/復制到較近端(前端或后端)一個插槽,並且效果在所有存儲桶中波動,直到到達第一個或最后一個。

總之,唯一的情況是std :: deque始終比vector好,這是如果您將它用作(增加)隊列(僅從前端或后端插入和刪除元素),而這正是實現優化的目的。 並未針對中間插入進行優化。

3)如果您需要存儲大量數據並需要兩個快速操作(搜索和插入),是否還有另一種更好的容器類型?

正如其他人已經說過的:像std :: unordered_map這樣的哈希表是您要查找的數據結構。

但是據我所知,std :: unordered_map如果是的話,則是次優的實現,因為它使用存儲桶來解決哈希沖突,並且這些存儲桶被實現為鏈接列表( 是Chandler Carruth的有趣演講不同數據結構性能的一般主題)。 對於大數據結構上的隨機訪問,緩存局部性的影響應該小得多,因此在您的情況下這可能不是一個大問題。

最后,我想說一句,如果您的值和鍵類型是小的POD,並且取決於您的龐大集合的大小(我們是在談論幾百萬甚至數十億個元素)還是實際上您必須插入/刪除元素的頻率,仍然可能存在簡單的std :: vector勝過其他任何STL容器的情況。 因此,一如既往:如果您的思想實驗成為現實,請嘗試並進行測量。

暫無
暫無

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

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