การใช้แฮชแมปส่วนหัวเดียวอย่างง่ายสำหรับ C/C++
เพียง #include "hashmap.h"
ไว้ในโค้ดของคุณ!
คอมไพเลอร์ที่รองรับในปัจจุบันคือ gcc, clang และ msvc
แพลตฟอร์มที่รองรับในปัจจุบัน ได้แก่ Linux, macOS และ Windows
แฮชแมปถูกสร้างขึ้นมาเพื่อทำงานกับคีย์ข้อมูลใดๆ ก็ได้ คุณเพียงแค่ระบุตัวชี้และขนาด จากนั้นมันจะแฮชข้อมูลนั้น แฮชเริ่มต้นคือตัวแปร crc32 ที่ใช้ฮาร์ดแวร์ภายในหากเป็นไปได้ และผู้เปรียบเทียบเริ่มต้นเพียงใช้ memcmp
ดังนั้นจึงแนะนำให้แนะนำให้เว้นระยะห่างจากช่องว่างภายในคีย์ struct
หากต้องการสร้าง hashmap ให้เรียกใช้ฟังก์ชัน hashmap_create
:
const unsigned initial_size = 2 ;
struct hashmap_s hashmap ;
if ( 0 != hashmap_create ( initial_size , & hashmap )) {
// error!
}
พารามิเตอร์ initial_size
จะกำหนดขนาดเริ่มต้นของแฮชแมปเท่านั้น ซึ่งสามารถขยายได้หากคีย์หลายคีย์กระทบรายการแฮชเดียวกัน ขนาดของแฮชแมปจะถูกปัดเศษขึ้นด้วยกำลังที่ใกล้ที่สุดของ 2 ซึ่งอยู่เหนือขนาด initial_size
ที่ระบุ
นอกจากนี้ยังมีฟังก์ชันการสร้างเพิ่มเติม 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 ให้ใช้ฟังก์ชัน 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 ให้ใช้ฟังก์ชัน hashmap_get
:
void * const element = hashmap_get ( & hashmap , "x" , strlen ( "x" ));
if ( NULL == element ) {
// error!
}
ฟังก์ชันจะส่งคืนค่า NULL
หากไม่พบองค์ประกอบ โปรดทราบว่าคีย์ที่ใช้ในการรับองค์ประกอบไม่จำเป็นต้องเป็นตัวชี้เดียวกับที่ใช้ในการวางองค์ประกอบในแฮชแมป - แต่ส่วนของสตริงจะต้องตรงกันจึงจะเกิด Hit
หากต้องการลบรายการออกจาก hashmap ให้ใช้ฟังก์ชัน hashmap_remove
:
if ( 0 != hashmap_remove ( & hashmap , "x" , strlen ( "x" ))) {
// error!
}
ฟังก์ชันจะส่งกลับค่าที่ไม่ใช่ศูนย์หากไม่พบองค์ประกอบ โปรดทราบว่าคีย์ที่ใช้ในการรับองค์ประกอบไม่จำเป็นต้องเป็นตัวชี้เดียวกับที่ใช้ในการวางองค์ประกอบในแฮชแมป - แต่ส่วนของสตริงจะต้องตรงกันจึงจะเกิด Hit
คุณสามารถวนซ้ำองค์ประกอบทั้งหมดที่เก็บไว้ใน hashmap ด้วยฟังก์ชัน hashmap_iterate
:
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 ให้ใช้ฟังก์ชัน 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/