openssl lhash 数据结构哈希表
哈希表是一种数据结构,通过在记录的存储位置和它的关键字之间建立确定的对应关系,来快速查询表中的数据;
openssl lhash.h 为我们提供了哈希表OPENSSL_LHASH 的相关接口,我们可以直接使用,用来存放各种数据;
哈希表类似前面提到的栈,但是哈希表的优势是查询速度快。
1. lhash.h 提供的哈希表主要接口有
//创建哈希表,参数为两个回调函数,分别可自定义哈希值计算方法,排序方法
OPENSSL_LHASH *OPENSSL_LH_new(OPENSSL_LH_HASHFUNC h, OPENSSL_LH_COMPFUNC c);
//释放哈希表内存,但是不释放表中数据的内存,需要调用下面的doall方法遍历表中数据去释放 void OPENSSL_LH_free(OPENSSL_LHASH *lh);
//在表中插入一条记录,当表中有该数据时,会进行替换,成功返回插入的数据地址 void *OPENSSL_LH_insert(OPENSSL_LHASH *lh, void *data);
//从表中删除一条记录,成功返回删除的该数据地址 void *OPENSSL_LH_delete(OPENSSL_LHASH *lh, const void *data);
//从表中查询一条记录,参数为要查询数据的地址,成功返回表中该数据的地址 void *OPENSSL_LH_retrieve(OPENSSL_LHASH *lh, const void *data);
//遍历表中的数据记录,回调函数可处理遍历每条记录 void OPENSSL_LH_doall(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNC func);
//遍历表中的数据记录,多了一个arg参数,可看下面的测试 void OPENSSL_LH_doall_arg(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNCARG func, void *arg);
//计算一条数据的哈希值 unsigned long OPENSSL_LH_strhash(const char *c);
//哈希表中元素个数 unsigned long OPENSSL_LH_num_items(const OPENSSL_LHASH *lh);
//查看哈希表的状态,输出到FILE
void OPENSSL_LH_stats(const OPENSSL_LHASH *lh, FILE *fp);
//查看哈希表节点的状态,输出到FILE void OPENSSL_LH_node_stats(const OPENSSL_LHASH *lh, FILE *fp);
//查看哈希表节点的使用状态,输出到FILE void OPENSSL_LH_node_usage_stats(const OPENSSL_LHASH *lh, FILE *fp);
//以下接口为哈希表状态,输出到BIO void OPENSSL_LH_stats_bio(const OPENSSL_LHASH *lh, BIO *out); void OPENSSL_LH_node_stats_bio(const OPENSSL_LHASH *lh, BIO *out); void OPENSSL_LH_node_usage_stats_bio(const OPENSSL_LHASH *lh, BIO *out);
2. 测试代码
unsigned long hashff(void *hf) { printf("%s\n",hf); return 100; } int hashfCmp(int *a,int *b) { return *a > *b; } void printArg(int *a,char *b) { printf("doall_arg: %d %s\n",*a,b); } void printValue(int *value) { printf("doall: %d\n",*value); } int main(int argc, const char * argv[]) { OPENSSL_LHASH *lh = OPENSSL_LH_new(NULL, NULL); int item = 1; OPENSSL_LH_insert(lh, &item); int item2 = 10; OPENSSL_LH_insert(lh, &item2); int item3 = 5; OPENSSL_LH_insert(lh, &item3); //因为表中已经存在数据5,如果再插入,将会替换之前的数据5 int item4 = 5; int *ret=0; ret = OPENSSL_LH_insert(lh, &item4); if (*ret==item4) { printf("insert replace PASS\n"); } int *fd = 0; fd = OPENSSL_LH_retrieve(lh,&item2); if (*fd == item2) { printf("find value PASS\n"); } OPENSSL_LH_doall(lh, printValue); OPENSSL_LH_doall_arg(lh, printArg, "arg"); int *delRet = 0; delRet = OPENSSL_LH_delete(lh, &item4); if (*delRet==item4) { printf("delete value PASS\n"); } int numLen = OPENSSL_LH_num_items(lh); printf("len=%d\n"); OPENSSL_LH_stats(lh, stdout); OPENSSL_LH_free(lh); return 0; }
输出日志
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
insert replace PASS find value PASS doall: 10 doall: 1 doall: 5 doall_arg: 10 arg doall_arg: 1 arg doall_arg: 5 arg delete value PASS len=73832 num_items = 2 num_nodes = 8 num_alloc_nodes = 16 num_expands = 0 num_expand_reallocs = 0 num_contracts = 0 num_contract_reallocs = 0 num_hash_calls = 6 num_comp_calls = 3 num_insert = 3 num_replace = 1 num_delete = 1 num_no_delete = 0 num_retrieve = 1 num_retrieve_miss = 0 num_hash_comps = 6 Program ended with exit code: 0
测试使用 openssl 1.1.0c
参考:https://www.openssl.org/docs/man1.0.2/crypto/lhash.html