C語言uthash介紹


介紹

uthash是C語言比較優秀的開源代碼。它實現了常見的hash函數,例如插入、查找、刪除等功能。它支持C語言的任意數據類型做為key值,無論是基本數據類型還是自定義的struct,但是不同類型的key其操作接口方式略有不同,而且它甚至可以采用多個值作為key。由於該代碼采用宏的方式實現,所有的實現代碼都在uthash.h文件中,因此只需要在自己的代碼中包含"uthash.h"頭文件即可。

uthash最初是Troy D. Hanson的個人使用方便的目標,放到了SourceForge,后來因為受歡迎下載量比較大,就放到了GitHub吧。

uthash是遵從BSD開源協議,可供個人、商業和組織自由使用。

hash操作

官方文檔詳細介紹了uthash的使用。這里提煉一些基本信息。
https://troydhanson.github.io/uthash/userguide.html

定義hash結構體

在你定義的hash結構體中嵌入UT_hash_handle。哈希表中是通過指針操作的,不會進行移動和復制對象,因此不必擔心速度和內存問題。

#include "uthash.h"

struct my_struct {
    int id; /* key */
    char name[10];
    UT_hash_handle hh; /* makes this structure hashable */
};

key的類型

uthash支持任意類型的key,包括整型、字符串、指針、結構體等。如果key類型不同,那么add和find函數有不同的接口,但是HASH_DELETE和HASH_SORT不區分key類型。結構體的一個或者多個成員構成,結構體指針本身作為

hash操作接口

macro arguments
HASH_ADD_INT (head, keyfield_name, item_ptr)
HASH_REPLACE_INT (head, keyfield_name, item_ptr, replaced_item_ptr)
HASH_FIND_INT (head, key_ptr, item_ptr)
HASH_ADD_STR (head, keyfield_name, item_ptr)
HASH_REPLACE_STR (head, keyfield_name, item_ptr, replaced_item_ptr)
HASH_FIND_STR (head, key_ptr, item_ptr)
HASH_ADD_PTR (head, keyfield_name, item_ptr)
HASH_REPLACE_PTR (head, keyfield_name, item_ptr, replaced_item_ptr)
HASH_FIND_PTR (head, key_ptr, item_ptr)
HASH_DEL (head, item_ptr)
HASH_SORT (head, cmp)
HASH_COUNT (head)

舉例

#include <stdio.h>   /* gets */
#include <stdlib.h>  /* atoi, malloc */
#include <string.h>  /* strcpy */
#include "uthash.h"

struct my_struct {
    int id; /* key */
    char name[10];
    UT_hash_handle hh; /* makes this structure hashable */
};

struct my_struct *users = NULL; /* must have a global pointer */

void add_user(int user_id, char *name) {
    struct my_struct *s;

    HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */
    if (s == NULL) {
        s = (struct my_struct *)malloc(sizeof *s);
        s->id = user_id;
        HASH_ADD_INT(users, id, s); /* id: name of key field */
    }
    strcpy(s->name, name);
}

struct my_struct *find_user(int user_id) {
    struct my_struct *s;

    HASH_FIND_INT(users, &user_id, s); /* s: output pointer */
    return s;
}

void delete_user(struct my_struct *user) {
    HASH_DEL(users, user); /* user: pointer to deletee */
    free(user);
}

/* 排序 */
int name_sort(struct my_struct *a, struct my_struct *b) {
    return strcmp(a->name, b->name);
}

int id_sort(struct my_struct *a, struct my_struct *b) {
    return (a->id - b->id);
}

void sort_by_name() {
    HASH_SORT(users, name_sort);
}

void sort_by_id() {
    HASH_SORT(users, id_sort);
}

list操作

utlist提供了鏈表的操作,支持三種鏈表:單鏈表、雙鏈表、循環雙鏈表

  • queue:uthash暫時沒有單獨提供隊列的實現,可借用LL_APPEND、LL_DELETE來實現queue的功能。進一步的使用LL_INSERT_INORDER函數進行有序插入,可實現優先隊列的功能。

官方文檔詳細介紹了utlist的使用。在源碼中包含utlist.h頭文件即可。
https://troydhanson.github.io/uthash/utlist.html

定義list結構體

在你定義的list中嵌入next、prev指針,就可實現單鏈表或者雙鏈表。

typedef struct element {
    char *name;
    struct element *prev; /* needed for a doubly-linked list only */
    struct element *next; /* needed for singly- or doubly-linked lists */
} element;

list操作接口

支持list的頭插法和尾插法的插入接口、查詢接口、刪除接口、遍歷、排序等。

  • 頭插法:Prepend意味着在現有的列表頭(如果有的話)前面插入一個元素,將列表頭更改為新元素。
  • 尾插法:Append意味着在列表的末尾添加一個元素,因此它成為新的尾元素。
  • 連接兩個鏈表:Concatenate接受兩個正確構造的列表,並將第二個列表附加到第一個列表。
  • 任意插入:要在任意元素(而不是列表頭)之前添加前綴,請使用prepend ELEM宏族。要在任意元素元素之后添加元素而不是列表頭,請使用append ELEM宏族。
Singly-linked Doubly-linked Circular, doubly-linked
LL_PREPEND(head,add); DL_PREPEND(head,add); CDL_PREPEND(head,add);
LL_PREPEND_ELEM(head,ref,add); DL_PREPEND_ELEM(head,ref,add); CDL_PREPEND_ELEM(head,ref,add);
LL_APPEND_ELEM(head,ref,add); DL_APPEND_ELEM(head,ref,add); CDL_APPEND_ELEM(head,ref,add);
LL_REPLACE_ELEM(head,del,add); DL_REPLACE_ELEM(head,del,add); CDL_REPLACE_ELEM(head,del,add);
LL_APPEND(head,add); DL_APPEND(head,add); CDL_APPEND(head,add);
LL_INSERT_INORDER(head,add,cmp); DL_INSERT_INORDER(head,add,cmp); CDL_INSERT_INORDER(head,add,cmp);
LL_CONCAT(head1,head2); DL_CONCAT(head1,head2); ``
LL_DELETE(head,del); DL_DELETE(head,del); CDL_DELETE(head,del);
LL_SORT(head,cmp); DL_SORT(head,cmp); CDL_SORT(head,cmp);
LL_FOREACH(head,elt) {…} DL_FOREACH(head,elt) {…} CDL_FOREACH(head,elt) {…}
LL_FOREACH_SAFE(head,elt,tmp) {…} DL_FOREACH_SAFE(head,elt,tmp) {…} CDL_FOREACH_SAFE(head,elt,tmp1,tmp2) {…}
LL_SEARCH_SCALAR(head,elt,mbr,val); DL_SEARCH_SCALAR(head,elt,mbr,val); CDL_SEARCH_SCALAR(head,elt,mbr,val);
LL_SEARCH(head,elt,like,cmp); DL_SEARCH(head,elt,like,cmp); CDL_SEARCH(head,elt,like,cmp);
LL_LOWER_BOUND(head,elt,like,cmp); DL_LOWER_BOUND(head,elt,like,cmp); CDL_LOWER_BOUND(head,elt,like,cmp);
LL_COUNT(head,elt,count); DL_COUNT(head,elt,count); CDL_COUNT(head,elt,count);

array操作

utarray實現了動態數組的功能。可存儲整型數組和字符串,也可自定義其他類型。主要功能包括:插入,查找、刪除等。

  • queue:可通過array實現queue功能(utarray_push_back、utarray_erase);但是沒有不能實現優先隊列。

https://troydhanson.github.io/uthash/utarray.html

utarray操作接口

utarray_new(UT_array *a, UT_icd *icd) allocate a new array
utarray_free(UT_array *a) free an allocated array
utarray_init(UT_array *a,UT_icd *icd) init an array (non-alloc)
utarray_done(UT_array *a) dispose of an array (non-allocd)
utarray_reserve(UT_array *a,int n) ensure space available for n more elements
utarray_push_back(UT_array *a,void *p) push element p onto a
utarray_pop_back(UT_array *a) pop last element from a
utarray_extend_back(UT_array *a) push empty element onto a
utarray_len(UT_array *a) get length of a
utarray_eltptr(UT_array *a,int j) get pointer of element from index
utarray_eltidx(UT_array *a,void *e) get index of element from pointer
utarray_insert(UT_array *a,void *p, int j) insert element p to index j
utarray_inserta(UT_array *a,UT_array *w, int j) insert array w into array a at index j
utarray_resize(UT_array *dst,int num) extend or shrink array to num elements
utarray_concat(UT_array *dst,UT_array *src) copy src to end of dst array
utarray_erase(UT_array *a,int pos,int len) remove len elements from a[pos]..a[pos+len-1]
utarray_clear(UT_array *a) clear all elements from a, setting its length to zero
utarray_sort(UT_array *a,cmpfcn *cmp) sort elements of a using comparison function
utarray_find(UT_array *a,void *v, cmpfcn *cmp) find element v in utarray (must be sorted)
utarray_front(UT_array *a) get first element of a
utarray_next(UT_array *a,void *e) get element of a following e (front if e is NULL)
utarray_prev(UT_array *a,void *e) get element of a before e (back if e is NULL)
utarray_back(UT_array *a) get last element of a

舉例

#include <stdio.h>
#include "utarray.h"

int main() {
  UT_array *nums;
  int i, *p;

  utarray_new(nums,&ut_int_icd);
  for(i=0; i < 10; i++) utarray_push_back(nums,&i);

  for(p=(int*)utarray_front(nums);
      p!=NULL;
      p=(int*)utarray_next(nums,p)) {
    printf("%d\n",*p);
  }

  utarray_free(nums);

  return 0;
}

string操作

utstring實現了動態字符串的功能。
https://troydhanson.github.io/uthash/utstring.html

utstring操作接口

utstring_new(s) allocate a new utstring
utstring_renew(s) allocate a new utstring (if s is NULL) otherwise clears it
utstring_free(s) free an allocated utstring
utstring_init(s) init a utstring (non-alloc)
utstring_done(s) dispose of a utstring (non-alloc)
utstring_printf(s,fmt,…) printf into a utstring (appends)
utstring_bincpy(s,bin,len) insert binary data of length len (appends)
utstring_concat(dst,src) concatenate src utstring to end of dst utstring
utstring_clear(s) clear the content of s (setting its length to 0)
utstring_len(s) obtain the length of s as an unsigned integer
utstring_body(s) get char* to body of s (buffer is always null-terminated)
utstring_find(s,pos,str,len) forward search from pos for a substring
utstring_findR(s,pos,str,len) reverse search from pos for a substring

舉例

#include <stdio.h>
#include "utstring.h"

int main() {
    UT_string *s;

    utstring_new(s);
    utstring_printf(s, "hello world!" );
    printf("%s\n", utstring_body(s));

    utstring_free(s);
    return 0;
}

stack操作

首先要在自己的結構體中定義next指針
https://troydhanson.github.io/uthash/utstack.html

stack操作接口

STACK_PUSH(stack,add); push add onto stack
STACK_POP(stack,elt); pop stack and save previous top as elt
STACK_COUNT(stack,tmp,count); get number of elements into count
STACK_TOP(stack) return stack

舉例

struct item {
     int id;
     struct item *next;
};

struct item *stack = NULL;  /* 定義頭指針 */

int main() {
     int count;
     struct item *tmp;
     struct item *item = malloc(sizeof *item);
     item->id = 42;
     STACK_COUNT(stack, tmp, count); assert(count == 0); /* 當前棧個數為0 */

     STACK_PUSH(stack, item); /* push一個元素 */
     STACK_COUNT(stack, tmp, count); assert(count == 1); /* 當前棧個數為1 */

     STACK_POP(stack, item); /* pop一個元素 */
     free(item);
     STACK_COUNT(stack, tmp, count); assert(count == 0); /* 當前棧個數為0 */
}

ringbuffer循環隊列

utringbuffer實現了循環鏈表的相關操作。 環形緩沖區數據類型支持構造、銷毀、迭代和填充,但不支持彈出; 一旦環形緩沖區達到滿容量,填充新元素會自動彈出並銷毀最舊的元素。 環形緩沖區中包含的元素可以是任何簡單的數據類型或結構。

ringbuffer操作接口

utringbuffer_new(UT_ringbuffer *a, int n, UT_icd *icd) allocate a new ringbuffer
utringbuffer_free(UT_ringbuffer *a) free an allocated ringbuffer
utringbuffer_init(UT_ringbuffer *a, int n, UT_icd *icd) init a ringbuffer (non-alloc)
utringbuffer_done(UT_ringbuffer *a) dispose of a ringbuffer (non-alloc)
utringbuffer_clear(UT_ringbuffer *a) clear all elements from a, making it empty
utringbuffer_push_back(UT_ringbuffer *a, element *p) push element p onto a
utringbuffer_len(UT_ringbuffer *a) get length of a
utringbuffer_empty(UT_ringbuffer *a) get whether a is empty
utringbuffer_full(UT_ringbuffer *a) get whether a is full
utringbuffer_eltptr(UT_ringbuffer *a, int j) get pointer of element from index
utringbuffer_eltidx(UT_ringbuffer *a, element *e) get index of element from pointer
utringbuffer_front(UT_ringbuffer *a) get oldest element of a
utringbuffer_next(UT_ringbuffer *a, element *e) get element of a following e (front if e is NULL)
utringbuffer_prev(UT_ringbuffer *a, element *e) get element of a before e (back if e is NULL)
utringbuffer_back(UT_ringbuffer *a) get newest element of a

舉例

此例程創建了一個大小為7個int的循序buffer,填充10個數字,只有最后7個數字被保存下來了。

#include <stdio.h>
#include "utringbuffer.h"

int main() {
  UT_ringbuffer *history;
  int i, *p;

  utringbuffer_new(history, 7, &ut_int_icd);
  for(i=0; i < 10; i++) utringbuffer_push_back(history, &i);

  for (p = (int*)utringbuffer_front(history);
       p != NULL;
       p = (int*)utringbuffer_next(history, p)) {
    printf("%d\n", *p);  /* prints "3 4 5 6 7 8 9" */
  }

  for (i=0; i < utringbuffer_len(history); i++) {
    p = utringbuffer_eltptr(history, i);
    printf("%d\n", *p);  /* prints "3 4 5 6 7 8 9" */
  }

  utringbuffer_free(history);

  return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM