一種用於 C/C++ 的簡單單標頭雜湊圖實作。
只需在程式碼中#include "hashmap.h"
即可!
目前支援的編譯器有 gcc、clang 和 msvc。
目前支援的平台有 Linux、macOS 和 Windows。
哈希映射可與任何任意資料鍵一起使用 - 您只需提供指標和大小,它就會對該資料進行雜湊處理。如果可能的話,預設雜湊器是使用硬體內在函數的 crc32 變體,預設比較器僅使用memcmp
,因此建議將結構鍵中的任何填充清除。
若要建立 hashmap,請呼叫hashmap_create
函數:
const unsigned initial_size = 2 ;
struct hashmap_s hashmap ;
if ( 0 != hashmap_create ( initial_size , & hashmap )) {
// error!
}
initial_size
參數僅設定哈希映射的初始大小 - 如果多個鍵命中相同的雜湊條目,則該大小可能會增長。哈希圖的大小向上捨去到所提供的initial_size
之上最接近的2的冪。
還有一個擴充創建函數hashmap_create_ex
:
struct hashmap_s hashmap ;
struct hashmap_create_options_s options ;
memset ( & options , 0 , sizeof ( options ));
// You can set a custom hasher that the hashmap should use.
options . hasher = & my_hasher ;
// You can set a custom comparer that the hashmap should for comparing keys.
options . comparer = & my_comparer ;
// You can also specify the initial capacity of the hashmap.
options . initial_capacity = 42 ;
if ( 0 != hashmap_create_ex ( options , & hashmap )) {
// error!
}
若要將項目放入雜湊圖中,請使用hashmap_put
函數:
int meaning_of_life = 42 ;
char question = 6 * 8 ;
if ( 0 != hashmap_put ( & hashmap , "life" , strlen ( "life" ), & meaning_of_life )) {
// error!
}
if ( 0 != hashmap_put ( & hashmap , "?" , strlen ( "?" ), & question )) {
// error!
}
請注意,在同一雜湊圖中可以存在不同類型的多個條目。哈希映射不是類型化的 - 它可以儲存任何void*
資料作為鍵的值。
若要從哈希映射中取得條目,請使用hashmap_get
函數:
void * const element = hashmap_get ( & hashmap , "x" , strlen ( "x" ));
if ( NULL == element ) {
// error!
}
如果未找到該元素,則函數將傳回NULL
。請注意,用於獲取元素的鍵不必與用於將元素放入哈希圖中的指標相同 - 但字串切片必須匹配才能發生命中。
若要從雜湊圖中刪除條目,請使用hashmap_remove
函數:
if ( 0 != hashmap_remove ( & hashmap , "x" , strlen ( "x" ))) {
// error!
}
如果未找到該元素,則函數將傳回非零值。請注意,用於獲取元素的鍵不必與用於將元素放入哈希圖中的指標相同 - 但字串切片必須匹配才能發生命中。
您可以使用hashmap_iterate
函數迭代儲存在 hashmap 中的所有元素:
static int iterate ( void * const context , void * const value ) {
// If the value is 42...
if ( 42 == * ( int * ) value ) {
// Store into our user-provided context the value.
* ( void * * ) context = value ;
// Return 0 to tell the iteration to stop here.
return 0 ;
}
// Otherwise tell the iteration to keep going.
return 1 ;
}
int * value ;
if ( 0 != hashmap_iterate ( & hashmap , iterate , & value )) {
if ( * value != 42 ) {
// error!
}
} else {
// if we got here it means we never found 42 in the hashmap
}
您可以透過從回調函數傳回非零來提前退出雜湊圖的迭代 - 也許您想處理並刪除雜湊圖中的所有元素或僅搜尋特定值。否則,如果回調返回零,則迭代將包含整個哈希圖。
在某些應用程式中,例如需要列印雜湊圖的內容,除了值之外,您還需要存取鍵和鍵長度。為此,增加了第二個迭代器,稱為hashmap_iterate_pairs
。
此外,從回呼函數傳回 -1 允許自動刪除目前項目。當將動態分配的物件儲存到映射並需要在銷毀映射時釋放記憶體時,這尤其方便。
int log_and_free_all ( void * const context , struct hashmap_element_s * const e ) {
int counter ;
for ( counter = 0 ; counter < e -> key_len ; counter ++ ) {
fputc ( e -> key [ counter ], ( FILE ) context );
}
fprintf (( FILE ) context , "=%s pair has been freedn" , ( char * ) e -> data );
free ( e -> data );
return -1 ;
}
void shut_down () {
if ( 0 != hashmap_iterate_pairs ( & hash , log_and_free_all , ( void * ) log )) {
fprintf ( stderr , "failed to deallocate hashmap entriesn" );
}
fclose ( log );
hashmap_destroy ( & hash );
}
若要取得已放入哈希映射的條目數,請使用hashmap_num_entries
函數:
unsigned num_entries = hashmap_num_entries ( & hashmap );
若要取得 hashmap 中分配的實際桶數(容量),請使用hashmap_capacity
函數:
unsigned num_entries = hashmap_capacity ( & hashmap );
要在使用完雜湊圖後銷毀它,請使用hashmap_destroy
函數:
hashmap_destroy ( & hashmap );
這段程式碼幾乎完全是由令人敬畏的 Pete Warden 編寫的,基於 Elliott Back 現已不復存在的部落格文章。作者應用了以下進一步的變更:
這是發佈到公共領域的免費且不受阻礙的軟體。
任何人都可以為任何目的(商業或非商業)以任何方式以原始程式碼形式或編譯的二進位檔案自由複製、修改、發布、使用、編譯、銷售或散佈本軟體。
在承認版權法的司法管轄區,本軟體的作者將軟體中的任何及所有版權權益奉獻給公共領域。我們做出這種奉獻是為了廣大公眾的利益,而不是為了我們的繼承人和繼任者的利益。我們希望這種奉獻成為永久放棄版權法規定的本軟體所有當前和未來權利的公開行為。
本軟體以「現況」提供,不提供任何明示或暗示的保證,包括但不限於適銷性、特定用途的適用性和不侵權的保證。在任何情況下,作者均不對因本軟體或本軟體的使用或其他交易而產生或與之相關的任何索賠、損害或其他責任負責,無論是合約行為、侵權行為或其他行為。
欲了解更多信息,請參閱http://unlicense.org/