标题:哈希表实现的hashmap,支持扩容减容,坛友帮忙测测
只看楼主
xyzdwf
Rank: 2
等 级:论坛游民
威 望:1
帖 子:52
专家分:10
注 册:2017-1-9
结帖率:88.89%
已结贴  问题点数:20 回复次数:23 
哈希表实现的hashmap,支持扩容减容,坛友帮忙测测
自己测试太难发现问题了,帮下忙啊
实现参考了这个文章 https://blog. 中的链地址法
程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

typedef struct ztl_hashmap_kv ztl_hashmap_kv_t;
typedef ztl_hashmap_kv_t* ztl_hashmap_kv_p;
struct ztl_hashmap_kv{
    char* key;
    size_t value;
    ztl_hashmap_kv_p next;
};

typedef struct ztl_hashmap ztl_hashmap_t;
typedef ztl_hashmap_t* ztl_hashmap_p;
struct ztl_hashmap{
    int size;
    int capacity;
    ztl_hashmap_kv_p* array;
};

ztl_hashmap_p ztl_hashmap_init(int capacity);
void ztl_hashmap_put(ztl_hashmap_p map, char* key, size_t value);
size_t ztl_hashmap_get(ztl_hashmap_p map,char* key);
size_t ztl_hashmap_remove(ztl_hashmap_p map, char* key);
static void ztl_hashmap_resize(ztl_hashmap_p map, int type);
void ztl_hashmap_destory(ztl_hashmap_p map);
uint64_t fnv1a(char* buf, size_t len);

ztl_hashmap_p ztl_hashmap_init(int capacity)
{
    ztl_hashmap_p map = calloc(1, sizeof(ztl_hashmap_t));
    map->size = 0;
    map->capacity = capacity;
    map->array = calloc(capacity, sizeof(ztl_hashmap_kv_p));
    return map;
}

void ztl_hashmap_put(ztl_hashmap_p map, char* key, size_t value)
{
    int hash = fnv1a(key, strlen(key))%map->capacity;
    ztl_hashmap_kv_p* kvp = map->array + hash;
    ztl_hashmap_kv_p kv = *kvp;
    if(kv){
        while(kv){
            if(0 == strcmp(key, kv->key)){
                kv->value = value;
                return;
            }
            if(kv->next){
                kv = kv->next;
            }else{
                ztl_hashmap_kv_p nkv = calloc(1, sizeof(ztl_hashmap_kv_t));
                nkv->key = key;
                nkv->value = value;
                kv->next = nkv;
                map->size++;
                break;
            }
        }
    }else{
        ztl_hashmap_kv_p nkv = calloc(1, sizeof(ztl_hashmap_kv_t));
        nkv->key = key;
        nkv->value = value;
        *kvp = nkv;
        map->size++;
    }
    ztl_hashmap_resize(map, 1);
}

int hashmap_getnum=0;
size_t ztl_hashmap_get(ztl_hashmap_p map,char* key)
{
    int hash = fnv1a(key, strlen(key))%map->capacity;
    ztl_hashmap_kv_p* kvp = map->array+hash;
    ztl_hashmap_kv_p kv = *kvp;
    hashmap_getnum = 0;
    if(kv){
        while(kv){ hashmap_getnum++;
            if(0 == strcmp(key, kv->key)){
                printf("hashmap get num: %d\n", hashmap_getnum);
                return kv->value;
            }
            if(kv->next){
                kv = kv->next;
            }else{
                break;
            }
            
        }
    }
    printf("hashmap get num: %d\n", hashmap_getnum);
    return -1;
}

size_t ztl_hashmap_remove(ztl_hashmap_p map, char* key)
{
    int hash = fnv1a(key, strlen(key))%map->capacity;
    ztl_hashmap_kv_p* kvp = map->array+hash;
    ztl_hashmap_kv_p kv = *kvp;
    if(kv){
        ztl_hashmap_kv_p prev=0;
        while(kv){
            if(0 == strcmp(key, kv->key)){
                if(prev){
                    if(kv->next)prev->next = kv->next;
                    else prev->next = 0;
                }else{
                    if(kv->next)*kvp = kv->next;
                    else *kvp = 0;
                }
                size_t rv = kv->value;
                free(kv);
                map->size--;
                ztl_hashmap_resize(map, 0);
                return rv;
            }
            if(kv->next){
                prev = kv;
                kv = kv->next;
            }else{
                break;
            }
            
        }
    }
    return -1;
}
//扩容与减容
static void ztl_hashmap_resize(ztl_hashmap_p map, int type)
{
    int osiz = map->size;
    int ocap = map->capacity;
    ztl_hashmap_kv_p* oarray = map->array;
    
    float s = osiz * 1.0;
    float c = ocap * 1.0;
    int ncap;
    if(type){
        if(s/c<0.8)return;
        ncap = ocap*1.51;
    }else{
        if(s/c>0.3)return;
        ncap = ocap*0.57;
    }
    map->size = 0;
    map->capacity = ncap;
    map->array = calloc(ncap, sizeof(ztl_hashmap_kv_p));
    //printf("ztl_hashmap_resize------->ocap: %d, osiz:%d, s/c: %f\n", ocap, osiz, s/c);
    
    for(int i=0; i<ocap; i++){
        ztl_hashmap_kv_p okv = *(oarray + i);
        while(okv){
            int hash = fnv1a(okv->key, strlen(okv->key))%map->capacity;
            ztl_hashmap_kv_p* kvp = map->array + hash;
            ztl_hashmap_kv_p kv = *kvp;
            if(kv){
                while(kv->next){
                    kv = kv->next;
                }
                kv->next = okv;
                map->size++;
            }else{
                *kvp = okv;
                map->size++;
            }
            ztl_hashmap_kv_p tkv = okv->next;
            okv->next = 0;
            okv = tkv;
        }
    }
    free(oarray);
}

void ztl_hashmap_destory(ztl_hashmap_p map)
{
    for(int i=0; i<map->capacity; i++){
        ztl_hashmap_kv_p kv = *(map->array + i);
        while(kv){
            ztl_hashmap_kv_p tkv = kv->next;
            free(kv);
            kv = tkv;
        }
    }
    
    free(map->array);
    free(map);
}

uint64_t fnv1a(char* buf, size_t len) 
{  
    uint64_t hv = 0xcbf29ce484222325ULL;
    char* bp = buf;  
    char* be = bp + len;  
    while (bp < be) {  
        hv ^= (uint64_t) *bp++;  
        hv += (hv << 1) + (hv << 4) + (hv << 5) +  
            (hv << 7) + (hv << 8) + (hv << 40);  
    }  
    return hv;  
}

int main(int argc, char** argv)
{
    ztl_hashmap_p map = ztl_hashmap_init(23);
    ztl_hashmap_put(map, "长烟一空",  111111);
    ztl_hashmap_put(map, "上下天光",  222222222);
    ztl_hashmap_put(map, "一碧万顷",  333333333);
    
    ztl_hashmap_put(map, "长烟一空", 7777777);

    ztl_hashmap_put(map, "abc", 1234);
    ztl_hashmap_put(map, "aac", 2345);
    ztl_hashmap_put(map, "acc", 3456);
    ztl_hashmap_put(map, "acca", 4567);
    
    printf("000----hashmap cap: %d, size: %d\n", map->capacity, map->size);
    
    for(int i=0; i<53; i++){
        char* str = calloc(10,sizeof(char));//动态内存存储字符串
        sprintf( str, "mapkey%d", i);
        ztl_hashmap_put(map, str, i+1);
    }
    
    printf("111----hashmap cap: %d, size: %d\n", map->capacity, map->size);
    
    printf("pl: %d, pr: %d, pb: %d\n\n",  
        (int)ztl_hashmap_get(map, "长烟一空"),  
        (int)ztl_hashmap_get(map, "上下天光"), 
        (int)ztl_hashmap_get(map, "一碧万顷")
    );
    
    printf(" %d, %d, %d, %d, %d\n\n",  
        (int)ztl_hashmap_get(map, "abc"),  
        (int)ztl_hashmap_get(map, "aac"), 
        (int)ztl_hashmap_get(map, "acc"),
        (int)ztl_hashmap_get(map, "acca"),
        (int)ztl_hashmap_get(map, "mapkey11")
    );
    
    for(int i=0; i<76; i++){
        char* str = calloc(10,sizeof(char));//动态内存存储字符串
        sprintf( str, "mapkey%d", i);
        ztl_hashmap_remove(map, str);
    }
    
    ztl_hashmap_remove(map, "acca");
    
    printf(" %d, %d, %d, %d, %d\n\n",  
        (int)ztl_hashmap_get(map, "abc"),  
        (int)ztl_hashmap_get(map, "aac"), 
        (int)ztl_hashmap_get(map, "acc"),
        (int)ztl_hashmap_get(map, "acca"),
        (int)ztl_hashmap_get(map, "mapkey11")
    );

    
//    printf("-------------------\n");
//    for(int i=0; i<map->capacity; i++){
//        ztl_hashmap_kv_p kv = *(map->array + i);
//        while(kv){
//            printf("%s = %d\n", kv->key, (int)kv->value);
//            kv = kv->next;
//        }
//        
//    }
    
    printf("222----hashmap cap: %d, size: %d\n", map->capacity, map->size);
    
    ztl_hashmap_destory(map);
    
    return 0;
}


[此贴子已经被作者于2021-8-31 15:08编辑过]

搜索更多相关主题的帖子: int key map char next 
2021-08-31 15:02
xyzdwf
Rank: 2
等 级:论坛游民
威 望:1
帖 子:52
专家分:10
注 册:2017-1-9
得分:0 
测试发现个以前不知道的printf后面的动态参数,是从最后一个参数执行的,以前是真没注意啊
比如下面的printf最先获取的是mapkey11的值,难道和编译器有关?我用的gcc10.3

    printf(" %d, %d, %d, %d, %d\n\n",  
        (int)ztl_hashmap_get(map, "abc"),  
        (int)ztl_hashmap_get(map, "aac"),
        (int)ztl_hashmap_get(map, "acc"),
        (int)ztl_hashmap_get(map, "acca"),
        (int)ztl_hashmap_get(map, "mapkey11")
    );
2021-08-31 16:10
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
得分:20 
//online parser: https://www.bccn.net/run/

printf calling convention __cdecl push params into stack from R 2 L

程序代码:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) 
{
    
    printf("%c, %d, %s, %p", 'X', 125, "hello world", main);
    
    system("gcc -S *.c -o v.s");
    system("cat v.s");

    return 0;
}

    .file    "6666578.c"
    .section    .rodata
.LC0:
    .string    "hello world"
.LC1:
    .string    "%c, %d, %s, %p"
.LC2:
    .string    "gcc -S *.c -o v.s"
.LC3:
    .string    "cat v.s"
    .text
    .globl    main
    .type    main, @function
main:
.LFB2:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movl    $main, %r8d
    movl    $.LC0, %ecx
    movl    $125, %edx
    movl    $88, %esi
    movl    $.LC1, %edi
    movl    $0, %eax
    call    printf

    movl    $.LC2, %edi
    call    system
    movl    $.LC3, %edi
    call    system
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size    main, .-main
    .ident    "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits
X, 125, hello world, 0x400566

[此贴子已经被作者于2021-8-31 16:39编辑过]

2021-08-31 16:38
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
得分:0 
https://docs.

Argument-passing order    Right to left.
2021-08-31 16:55
xyzdwf
Rank: 2
等 级:论坛游民
威 望:1
帖 子:52
专家分:10
注 册:2017-1-9
得分:0 
回复 3楼 自由而无用
是和操作系统的调用有关系啊,动态参数要入栈出栈,以前都不知道啊
2021-08-31 17:02
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
得分:0 
//online parser: https://www.bccn.net/run/
程序代码:
#include <stdio.h>

int main(int argc, char *argv[])
{
    void *p, *q;
    int i;
    
    p = &argc;
    q = argv[0];
    
    printf("argc = %p, argv[0] = %p\n", p, q);
    (p > q) ? puts("CC: L2R") : puts("CC: R2L");
    
    //test argv
    printf("file name = %s, %d\n", argv[i], i);
    printf("file name = %s, %d", argv[i], i++);
    
    return 0;
}

argc = 0x7fff2e990d1c, argv[0] = 0x7fff2e992ed2
CC: R2L
file name = ./7305408.out, 0
file name = (null), 0
2021-08-31 17:15
xyzdwf
Rank: 2
等 级:论坛游民
威 望:1
帖 子:52
专家分:10
注 册:2017-1-9
得分:0 
回复 6楼 自由而无用
原来如此,所有函数调用的后面参数的地址都在前面,听你这么一说才明白c语言函数参数在内存如何存放的,谢谢了
2021-08-31 17:26
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
以下是引用xyzdwf在2021-8-31 16:10:10的发言:

测试发现个以前不知道的printf后面的动态参数,是从最后一个参数执行的,以前是真没注意啊
比如下面的printf最先获取的是mapkey11的值,难道和编译器有关?我用的gcc10.3

    printf(" %d, %d, %d, %d, %d\n\n",  
        (int)ztl_hashmap_get(map, "abc"),  
        (int)ztl_hashmap_get(map, "aac"),
        (int)ztl_hashmap_get(map, "acc"),
        (int)ztl_hashmap_get(map, "acca"),
        (int)ztl_hashmap_get(map, "mapkey11")
    );


参数评估顺序 和 参数压栈顺序 毫无关系。

参数压栈顺序 与 C++ 毫无关系,所以C++也不需要管它。

参数评估顺序 在C++中是“实现定义行为”,但倘若 值评估 和 副作用 依赖参数评估顺序,则其是“未定义行为”。
即使不谈C++标准,事实上gcc/vc都不能保证“最先获取的是mapkey11”,否则编译器就失去了优化能力。
当然你的代码因为足够简单,且外部也没有函数参数相关操作,所以让评估顺序与压栈顺序相一致可避免临时存储。
2021-08-31 23:14
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
得分:0 
compiler : this is the way!
pg: first in last service what an excellent logic! we dont need any brains!
propaganda: optimization is a privileged class, and leeks will always be leeks!

question: which class are u in ? humanity or no humanity

[此贴子已经被作者于2021-9-1 07:54编辑过]

2021-09-01 07:47
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
得分:0 
dont use ass to follow standard, this is my way.
2021-09-01 08:13



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-506714-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.122147 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved