【数据结构】哈希

1. 哈希表

1.1 Makefile

.PHONY: clean

CC = gcc
CFLAGS = -g -Wall -DDEBUG
EXTRA_FLAGS = -DUSE_SQUARE_DECTIVE

# match *.c
SOURCE = $(wildcard ./*.c)
# replace * with *.c
BIN = $(patsubst %.c, %, $(notdir $(SOURCE)))

$(BIN): $(SOURCE)
	$(CC) $(CFLAGS) $(EXTRA_FLAGS) $(SOURCE) -o $@

clean:
	rm -rf $(BIN)

1.2 hash_table.h

#ifndef __HASH_TABLE_H__
#define __HASH_TABLE_H__

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef int key_t;
typedef int value_t;

typedef struct {
    key_t key;
    value_t value;
} kv_pair_t;

// 哈希表里存储数据的状态
typedef enum {
    EMPTY_DATA = 0, // 之前没有存过数
    EXIST_DATA, // 目前存在数
    DELETED_DATA // 曾经存在数,现在被删除了
} state_e;

typedef enum {
    HASH_TABLE_OK                               = 0,
    HASH_TABLE_NOT_FOUND                        = -0x0001,
    HASH_TABLE_ERR_NULL_POINTER                 = -0x0002,
    HASH_TABLE_ERR_CREATE_HEAP_FAILED           = -0x0003,
    HASH_TABLE_NO_CAPACITY                      = -0x0004,
    HASH_TABLE_ERR_EXPANSION_FAILED             = -0x0005,
    HASH_TABLE_ERR_UNKNOWN                      = -0X0006
} hash_table_error_code_e;

// 哈希表里每个数据的类型
typedef struct {
    state_e state;
    kv_pair_t kv_data;
} hash_data_t;

typedef size_t (*hash_func_handler)(key_t, size_t);

// 哈希表
typedef struct {
    hash_data_t *hash_data; // 实际存储空间
    size_t capacity; // 容量
    size_t size; // 实际已存储的数据个数
    hash_func_handler hash_func; // 哈希函数
} hash_table_t;

// 取模函数
size_t mod_func(key_t key, size_t capacity);
// 哈希表的初始化
hash_table_error_code_e hash_table_init(hash_table_t *hash_table,
                                        size_t capacity,
                                        hash_func_handler hash_func);

size_t get_hash_table_capacity(const hash_table_t *hash_table);

size_t get_hash_table_size(const hash_table_t *hash_table);

void print_hash_table(const hash_table_t *hash_table);
// 哈希表的查找,如果找到了则返回下标,没找到的话返回 (size_t)-1
size_t hash_table_find_by_key(const hash_table_t *hash_table, key_t key);

value_t get_value_by_key(const hash_table_t *hash_table, key_t key);

hash_table_error_code_e hash_table_insert_kv_pair(hash_table_t *hash_table,
                                                  key_t key,
                                                  value_t value);

hash_table_error_code_e hash_table_remove_by_key(hash_table_t *hash_table, key_t key);

void hash_table_destroy(hash_table_t *hash_table);

#ifdef __cplusplus
}
#endif

#endif // __HASH_TABLE_H__

1.3 hash_table.c

#include "hash_table.h"

static size_t get_next_prime_number(size_t num)
{
    size_t i = 0;
    static const size_t prime_list[] = {
        11ul, 23ul, 37ul, 47ul,
        53ul, 97ul, 193ul, 389ul, 769ul,
        1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
        49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
        1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
        50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
        1610612741ul, 3221225473ul, 4294967291ul
    };

    for (i = 0; i < sizeof(prime_list) / sizeof(size_t); ++i) {
        if (prime_list[i] >= num) {
            return prime_list[i];
        }
    }

    return (size_t)-1;
}

size_t mod_func(key_t key, size_t capacity)
{
    return (size_t)key % capacity;
}

#ifdef USE_SQUARE_DECTIVE
static size_t square_dective(size_t index, size_t capacity, size_t times)
{
    return mod_func(index + times * times, capacity);
}
#else
static size_t linear_dective(size_t index, size_t capacity)
{
    return mod_func(++index, capacity);
}
#endif /// USE_SQUARE_DECTIVE

hash_table_error_code_e hash_table_init(hash_table_t *hash_table,
                                        size_t capacity,
                                        hash_func_handler hash_func)
{
    hash_table_error_code_e ret = HASH_TABLE_OK;
    size_t i = 0;

    do {
        if (NULL == hash_table) {
            printf("hash_table is NULL\n");
            ret = HASH_TABLE_ERR_NULL_POINTER;
            break;
        }

        capacity = get_next_prime_number(capacity);
        if ((size_t)-1 == capacity) {
            printf("get_next_prime_number fail\n");
            ret = HASH_TABLE_NO_CAPACITY;
            break;
        }

        hash_table->hash_data = (hash_data_t *)calloc(1, sizeof(hash_data_t) * capacity);
        if (NULL == hash_table->hash_data) {
            perror("calloc hash_table->hash_data fail");
            ret = HASH_TABLE_ERR_CREATE_HEAP_FAILED;
            break;
        }

        hash_table->size = 0;
        hash_table->capacity = capacity;
        hash_table->hash_func = hash_func;

        for (i = 0; i < capacity; ++i) {
            hash_table->hash_data[i].state = EMPTY_DATA;
        }
    } while (0);

    return ret;
}

size_t get_hash_table_capacity(const hash_table_t *hash_table)
{
    return hash_table ? hash_table->capacity : 0;
}

size_t get_hash_table_size(const hash_table_t *hash_table)
{
    return hash_table ? hash_table->size : 0;
}

char *enum_state_2_strings(state_e state)
{
    char *state_strings = NULL;

    switch (state) {
    case EMPTY_DATA:
        state_strings = "EMPTY";
        break;
    case EXIST_DATA:
        state_strings = "EXIST";
        break;
    case DELETED_DATA:
        state_strings = "DELETE";
        break;
    default:
        break;
    }

    return state_strings;
}

void print_hash_table(const hash_table_t *hash_table)
{
    if (NULL == hash_table || NULL == hash_table->hash_data) {
        printf("hash_table or hash_table->hash_data is NULL\n");
        return;
    }

    size_t i = 0, capacity = get_hash_table_capacity(hash_table);
    for (i = 0; i < capacity; ++i) {
        printf("hash table[%zu] ===> state: %s, key: %d, value: %d\n",
                i,
                enum_state_2_strings(hash_table->hash_data[i].state),
                hash_table->hash_data[i].kv_data.key,
                hash_table->hash_data[i].kv_data.value);
    }
}

size_t hash_table_find_by_key(const hash_table_t *hash_table, key_t key)
{
    if (NULL == hash_table) {
        printf("hash_table is NULL\n");
        return (size_t)HASH_TABLE_NOT_FOUND;
    }

#ifdef USE_SQUARE_DECTIVE
    size_t start = 0, times = 1;
#endif /// USE_SQUARE_DECTIVE

    size_t index = hash_table->hash_func(key, hash_table->capacity);

    while (EMPTY_DATA != hash_table->hash_data[index].state) {
        if ((key == hash_table->hash_data[index].kv_data.key)
                && (EXIST_DATA == hash_table->hash_data[index].state)) {
            printf("same key = %d, exist data\n", key);
            return index;
        } else {
#ifndef USE_SQUARE_DECTIVE
            /* 线性探测 */
            index = linear_dective(index, hash_table->capacity);
#else
            /* 二次探测 */
            index = square_dective(start, hash_table->capacity, times);
            ++times;
#endif /// USE_SQUARE_DECTIVE
        }
    }

    printf("%s not found %d\n", __func__, key);
    return (size_t)HASH_TABLE_NOT_FOUND;
}

value_t get_value_by_key(const hash_table_t *hash_table, key_t key)
{
    value_t value = INT_MIN;
    hash_table_error_code_e ret = hash_table_find_by_key(hash_table, key);

    if ((size_t)HASH_TABLE_NOT_FOUND != ret) {
        value = hash_table->hash_data[ret].kv_data.value;
    }

    return value;
}

static hash_table_error_code_e rehash(hash_table_t *hash_table)
{
    hash_table_error_code_e ret = HASH_TABLE_OK;

    do {
        if (NULL == hash_table) {
            printf("hash_table is NULL\n");
            ret = HASH_TABLE_ERR_NULL_POINTER;
            break;
        }

        // 负载因子是 0.7
        if ((hash_table->size) * 10 / (hash_table->capacity) < 7) {
            printf("hash_table do not need rehash\n");
            break;
        }

        size_t i = 0;
        hash_table_t new_hash_table;
        size_t capacity = hash_table->capacity * 2;

        if (HASH_TABLE_OK != hash_table_init(&new_hash_table, capacity, hash_table->hash_func)) {
            printf("hash_table_init new_hash_table fail\n");
            ret = HASH_TABLE_ERR_UNKNOWN;
            break;
        }

        for (i = 0; i < hash_table->capacity; ++i) {
            // rehash 后,才会把之前 DELETED_DATA 状态的数据删除,
            // 对于 EXIST_DATA 状态的数据,需要重新赋值给新的哈希表
            if (EXIST_DATA == hash_table->hash_data[i].state) {
                if (HASH_TABLE_OK != hash_table_insert_kv_pair(&new_hash_table,
                                                               hash_table->hash_data[i].kv_data.key,
                                                               hash_table->hash_data[i].kv_data.value)) {
                    printf("hash_table_insert_kv_pair fail\n");
                    return HASH_TABLE_ERR_UNKNOWN;
                }
            }
        }

        free(hash_table->hash_data);
        hash_table->hash_data = new_hash_table.hash_data;
        hash_table->capacity = new_hash_table.capacity;
    } while (0);

    return ret;
}

hash_table_error_code_e hash_table_insert_kv_pair(hash_table_t *hash_table,
                                                  key_t key,
                                                  value_t value)
{
    hash_table_error_code_e ret = HASH_TABLE_OK;

    do {
        if (NULL == hash_table) {
            printf("hash_table is NULL\n");
            ret = HASH_TABLE_ERR_NULL_POINTER;
            break;
        }

        if (HASH_TABLE_OK != rehash(hash_table)) {
            printf("rehash fail\n");
            ret = HASH_TABLE_ERR_EXPANSION_FAILED;
            break;
        }

        size_t index = hash_table->hash_func(key, hash_table->capacity);

#ifdef USE_SQUARE_DECTIVE
        size_t times = 1, start = index;
#endif /// USE_SQUARE_DECTIVE

        while (EXIST_DATA == hash_table->hash_data[index].state) {
            // hash table 不允许插入 相同的 key
            if ((key == hash_table->hash_data[index].kv_data.key)) {
                return HASH_TABLE_NOT_FOUND;
            } else {
#ifndef USE_SQUARE_DECTIVE
                /* 线性探测 */
                index = linear_dective(index, hash_table->capacity);
#else
                /* 二次探测 */
                index = square_dective(start, hash_table->capacity, times);
                ++times;
#endif /// USE_SQUARE_DECTIVE
            }
        }

        hash_table->hash_data[index].kv_data.key = key;
        hash_table->hash_data[index].kv_data.value = value;
        hash_table->hash_data[index].state = EXIST_DATA;
        ++hash_table->size;
    } while (0);

    return ret;
}

hash_table_error_code_e hash_table_remove_by_key(hash_table_t *hash_table, key_t key)
{
    if (NULL == hash_table) {
        printf("hash_table is NULL\n");
        return HASH_TABLE_ERR_NULL_POINTER;
    }

    size_t index = hash_table->hash_func(key, hash_table->capacity);

#ifdef USE_SQUARE_DECTIVE
    size_t times = 1, start = index;
#endif /// USE_SQUARE_DECTIVE

    while (EMPTY_DATA != hash_table->hash_data[index].state) {
        if ((key == hash_table->hash_data[index].kv_data.key)
                && (EXIST_DATA == hash_table->hash_data[index].state)) {
            hash_table->hash_data[index].state = DELETED_DATA;
            --hash_table->size;
            return HASH_TABLE_OK;
        } else {
#ifndef USE_SQUARE_DECTIVE
            /* 线性探测 */
            index = linear_dective(index, hash_table->capacity);
#else
            /* 二次探测 */
            index = square_dective(start, hash_table->capacity, times);
            ++times;
#endif /// USE_SQUARE_DECTIVE
        }
    }

    return HASH_TABLE_NOT_FOUND;
}

void hash_table_destroy(hash_table_t *hash_table)
{
    if (NULL == hash_table) {
        printf("hash_table is NULL\n");
        return;
    }

    free(hash_table->hash_data);
    hash_table->hash_data = NULL;
    hash_table->capacity = 0;
    hash_table->size = 0;
}

1.4 test_hash_table.c

#include "hash_table.h"

#include <time.h>

void test()
{
    srand((unsigned int)time(NULL));

    int i = 0;
    hash_table_t hash_table;

#ifndef USE_SQUARE_DECTIVE
    /* 测试线性探测法 */
    int numbers[] = {1, 19, 38, 27, 19, 30, 20, 73, 126, 13};
#else
    /* 测试二次探测法 */
    int numbers[] = {0, 11, 22, 33, 44};
#endif /// USE_SQUARE_DECTIVE

    printf("hash table init\n");
    if (HASH_TABLE_OK != hash_table_init(&hash_table,
                                         sizeof(numbers) / sizeof(int),
                                         mod_func)) {
        printf("hash_table_init fail\n");
        return;
    }

    printf("\nprint hash_table\n");
    print_hash_table(&hash_table);
    printf("hash table capacity: %zu\n", get_hash_table_capacity(&hash_table));
    printf("hash table size: %zu\n", get_hash_table_size(&hash_table));

    for (i = 0; i < sizeof(numbers) / sizeof(int); ++i) {
        size_t index = hash_table_find_by_key(&hash_table, numbers[i]);
        printf("index: %zu, numbers[%d]: %d\n", index, i, numbers[i]);

        if ((size_t)HASH_TABLE_NOT_FOUND == index) {
            int random_num = rand() % 100 + 1;
            printf("random num: %d\n", random_num);
            if (HASH_TABLE_OK != hash_table_insert_kv_pair(&hash_table,
                                                           numbers[i],
                                                           random_num)) {
                printf("hash_table_insert_kv_pair failed, key: %d, value: %d\n",
                        numbers[i], random_num);
            }
        }
    }

#ifndef USE_SQUARE_DECTIVE
    printf("\nhash_table[%d]: %d\n", 1, get_value_by_key(&hash_table, 1));
    printf("\nhash_table[%d]: %d\n", 19, get_value_by_key(&hash_table, 19));
    printf("hash_table[%d]: %d\n", 72, get_value_by_key(&hash_table, 72));
    printf("hash_table[%d]: %d\n", 33, get_value_by_key(&hash_table, 33));
#else
    printf("\nhash_table[%d]: %d\n", 11, get_value_by_key(&hash_table, 11));
    printf("\nhash_table[%d]: %d\n", 33, get_value_by_key(&hash_table, 33));
    printf("hash_table[%d]: %d\n", 15, get_value_by_key(&hash_table, 15));
#endif /// USE_SQUARE_DECTIVE

    printf("\nprint hash_table\n");
    print_hash_table(&hash_table);
    printf("hash table capacity: %zu\n", get_hash_table_capacity(&hash_table));
    printf("hash table size: %zu\n", get_hash_table_size(&hash_table));

    if (HASH_TABLE_OK != hash_table_remove_by_key(&hash_table, 45)) {
        printf("hash_table_remove_by_key failed, key: %d\n", 45);
    }
    printf("\nprint hash_table\n");
    print_hash_table(&hash_table);

#ifndef USE_SQUARE_DECTIVE
    if (HASH_TABLE_OK != hash_table_remove_by_key(&hash_table, 19)) {
        printf("hash_table_remove_by_key failed, key: %d\n", 19);
    }
#else
    if (HASH_TABLE_OK != hash_table_remove_by_key(&hash_table, 44)) {
        printf("hash_table_remove_by_key failed, key: %d\n", 44);
    }
#endif /// USE_SQUARE_DECTIVE
    printf("\nprint hash_table\n");
    print_hash_table(&hash_table);

    if (HASH_TABLE_OK != hash_table_insert_kv_pair(&hash_table, 179, 666)) {
        printf("hash_table_insert_kv_pair failed, key: %d, value: %d\n", 179, 666);
    }
    printf("\nprint hash_table\n");
    print_hash_table(&hash_table);

    printf("\nhash_table[%d]: %d\n", 179, get_value_by_key(&hash_table, 179));

    printf("\nhash table destroy\n");
    hash_table_destroy(&hash_table);

    printf("hash table capacity: %zu\n", get_hash_table_capacity(&hash_table));
    printf("hash table size: %zu\n", get_hash_table_size(&hash_table));
}

int main(void)
{
    test();

    return 0;
}

2. 哈希桶

2.1 Makefile

.PHONY: clean

CC = gcc
CFLAGS = -g -Wall -DDEBUG

# match *.c
SOURCE = $(wildcard ./*.c)
# replace * with *.c
BIN = $(patsubst %.c, %, $(notdir $(SOURCE)))

$(BIN): $(SOURCE)
	$(CC) $(CFLAGS) $(SOURCE) -o $@

clean:
	rm -rf $(BIN)

2.2 hash_bucket.h

#ifndef __HASH_BUCKET_H__
#define __HASH_BUCKET_H__

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef int key_t;
typedef int value_t;

typedef struct {
    key_t key;
    value_t value;
} kv_pair_t;

typedef enum {
    HASH_BUCKET_OK                               = 0,
    HASH_BUCKET_NOT_FOUND                        = -0x0001,
    HASH_BUCKET_ERR_NULL_POINTER                 = -0x0002,
    HASH_BUCKET_ERR_CREATE_HEAP_FAILED           = -0x0003,
    HASH_BUCKET_NO_CAPACITY                      = -0x0004
} hash_bucket_error_code_e;

// 哈希桶里每个数据的类型
typedef struct hash_data_s {
    kv_pair_t kv_data;
    struct hash_data_s *next;
} hash_data_t;

typedef size_t (*hash_func_handler)(key_t, size_t);

// 哈希桶
typedef struct {
    hash_data_t **hash_data; // 实际存储空间, 即 指针数组
    size_t capacity; // 容量
    size_t size; // 实际已存储的数据个数
    hash_func_handler hash_func; // 哈希函数
} hash_bucket_t;

// 取模函数
size_t mod_func(key_t key, size_t capacity);
// 哈希桶的初始化
hash_bucket_error_code_e hash_bucket_init(hash_bucket_t *hash_bucket,
                                          size_t capacity,
                                          hash_func_handler hash_func);

size_t get_hash_bucket_capacity(const hash_bucket_t *hash_bucket);

size_t get_hash_bucket_size(const hash_bucket_t *hash_bucket);

void print_hash_bucket(const hash_bucket_t *hash_bucket);
// 哈希桶的查找,如果找到了则返回头指针,没找到的话返回 NULL
hash_data_t *hash_bucket_find_by_key(const hash_bucket_t *hash_bucket, key_t key);

value_t get_value_by_key(const hash_bucket_t *hash_bucket, key_t key);

hash_bucket_error_code_e hash_bucket_insert_kv_pair(hash_bucket_t *hash_bucket,
                                                    key_t key,
                                                    value_t value);

hash_bucket_error_code_e hash_bucket_remove_by_key(hash_bucket_t *hash_bucket, key_t key);

void hash_bucket_destroy(hash_bucket_t *hash_bucket);

#ifdef __cplusplus
}
#endif

#endif // __HASH_BUCKET_H__

2.3 hash_bucket.c

#include "hash_bucket.h"

static size_t get_next_prime_number(size_t num)
{
    size_t i = 0;
    static const size_t prime_list[] = {
        53ul, 97ul, 193ul, 389ul, 769ul,
        1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
        49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
        1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
        50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
        1610612741ul, 3221225473ul, 4294967291ul
    };

    for (i = 0; i < sizeof(prime_list) / sizeof(size_t); ++i) {
        if (prime_list[i] >= num) {
            return prime_list[i];
        }
    }

    return (size_t)-1;
}

size_t mod_func(key_t key, size_t capacity)
{
    return (size_t)key % capacity;
}

hash_bucket_error_code_e hash_bucket_init(hash_bucket_t *hash_bucket,
                                          size_t capacity,
                                          hash_func_handler hash_func)
{
    hash_bucket_error_code_e ret = HASH_BUCKET_OK;
    size_t i = 0;

    do {
        if (NULL == hash_bucket) {
            printf("hash_bucket is NULL\n");
            ret = HASH_BUCKET_ERR_NULL_POINTER;
            break;
        }

        capacity = get_next_prime_number(capacity);
        if ((size_t)-1 == capacity) {
            printf("get_next_prime_number fail\n");
            ret = HASH_BUCKET_NO_CAPACITY;
            break;
        }

        hash_bucket->hash_data = (hash_data_t **)calloc(1, sizeof(hash_data_t *) * capacity);
        if (NULL == hash_bucket->hash_data) {
            perror("calloc hash_bucket->hash_data fail");
            ret = HASH_BUCKET_ERR_CREATE_HEAP_FAILED;
            break;
        }

        hash_bucket->size = 0;
        hash_bucket->capacity = capacity;
        hash_bucket->hash_func = hash_func;

        for (i = 0; i < capacity; ++i) {
            // 存放头指针
            hash_bucket->hash_data[i] = NULL;
        }

    } while (0);

    return ret;
}

size_t get_hash_bucket_capacity(const hash_bucket_t *hash_bucket)
{
    return hash_bucket ? hash_bucket->capacity : 0;
}

size_t get_hash_bucket_size(const hash_bucket_t *hash_bucket)
{
    return hash_bucket ? hash_bucket->size : 0;
}

void print_hash_bucket(const hash_bucket_t *hash_bucket)
{
    if (NULL == hash_bucket || NULL == hash_bucket->hash_data) {
        printf("hash_bucket or hash_bucket->hash_data is NULL\n");
        return;
    }

    size_t i = 0, capacity = get_hash_bucket_capacity(hash_bucket);
    hash_data_t *cur = NULL;

    for (i = 0; i < capacity; ++i) {
        printf("hash bucket[%zu] -> ", i);

        for (cur = hash_bucket->hash_data[i]; NULL != cur; cur = cur->next) {
            printf("{%d : %d} -> ", cur->kv_data.key, cur->kv_data.value);
        }

        printf("NULL\n");
    }
}

hash_data_t *hash_bucket_find_by_key(const hash_bucket_t *hash_bucket, key_t key)
{
    hash_data_t *cur = NULL;

    if (NULL == hash_bucket) {
        printf("hash_bucket is NULL\n");
        return NULL;
    }

    size_t index = hash_bucket->hash_func(key, hash_bucket->capacity);
    for (cur = hash_bucket->hash_data[index]; NULL != cur; cur = cur->next) {
        if (key == cur->kv_data.key) {
            return cur;
        }
    }

    printf("not found %d\n", key);
    return NULL;
}

value_t get_value_by_key(const hash_bucket_t *hash_bucket, key_t key)
{
    value_t value = INT_MIN;
    hash_data_t *found = hash_bucket_find_by_key(hash_bucket, key);

    if (NULL != found) {
        return found->kv_data.value;
    }

    return value;
}

hash_bucket_error_code_e hash_bucket_insert_kv_pair(hash_bucket_t *hash_bucket,
                                                    key_t key,
                                                    value_t value)
{
    hash_bucket_error_code_e ret = HASH_BUCKET_OK;

    do {
        if (NULL == hash_bucket) {
            printf("hash_bucket is NULL\n");
            ret = HASH_BUCKET_ERR_NULL_POINTER;
            break;
        }

        size_t index = hash_bucket->hash_func(key, hash_bucket->capacity);
        hash_data_t *cur = NULL, *new_hash_data = NULL;

        for (cur = hash_bucket->hash_data[index]; NULL != cur; cur = cur->next) {
            if (key == cur->kv_data.key) {
                return HASH_BUCKET_NOT_FOUND;
            }
        }

        new_hash_data = (hash_data_t *)calloc(1, sizeof(hash_data_t));
        if (NULL == new_hash_data) {
            perror("calloc new_hash_data fail");
            ret = HASH_BUCKET_ERR_CREATE_HEAP_FAILED;
            break;
        }

        new_hash_data->kv_data.key = key;
        new_hash_data->kv_data.value = value;
        ++hash_bucket->size;

        // 头插
        new_hash_data->next = hash_bucket->hash_data[index];
        hash_bucket->hash_data[index] = new_hash_data;
    } while (0);

    return ret;
}

hash_bucket_error_code_e hash_bucket_remove_by_key(hash_bucket_t *hash_bucket, key_t key)
{
    if (NULL == hash_bucket) {
        printf("hash_bucket is NULL\n");
        return HASH_BUCKET_ERR_NULL_POINTER;
    }

    size_t index = hash_bucket->hash_func(key, hash_bucket->capacity);
    hash_data_t *cur = NULL, *tmp_hash_data = NULL, *next_hash_data = NULL;

    for (cur = hash_bucket->hash_data[index]; NULL != cur; cur = next_hash_data) {
        next_hash_data = cur->next;

        if (key == cur->kv_data.key) {
            if (NULL == tmp_hash_data) {
                // 头删
                hash_bucket->hash_data[index] = next_hash_data;
            } else {
                tmp_hash_data->next = next_hash_data;
            }

            free(cur);
            --hash_bucket->size;
            return HASH_BUCKET_OK;
        } else {
            tmp_hash_data = cur;
        }
    }

    return HASH_BUCKET_NOT_FOUND;
}

void hash_bucket_destroy(hash_bucket_t *hash_bucket)
{
    if (NULL == hash_bucket) {
        printf("hash_bucket is NULL\n");
        return;
    }

    size_t i = 0;
    hash_data_t *cur = NULL, *next_data = NULL;

    for (i = 0; i < hash_bucket->capacity; ++i) {
        for (cur = hash_bucket->hash_data[i]; NULL != cur; cur = next_data) {
            next_data = cur->next;
            free(cur);
        }
    }

    free(hash_bucket->hash_data);
    hash_bucket->hash_data = NULL;
    hash_bucket->capacity = 0;
    hash_bucket->size = 0;
}

2.4 test_hash_bucket.c

#include "hash_bucket.h"

#include <time.h>

void test()
{
    hash_bucket_t hash_bucket;
    size_t i = 0;
    hash_data_t *found = NULL;
    int numbers[] = {1, 23, 46, 53, 106, 34, 11, 2, 34, 55};

    srand((unsigned int)time(NULL));

    printf("hash bucket init\n");
    if (HASH_BUCKET_OK != hash_bucket_init(&hash_bucket,
                                           sizeof(numbers) / sizeof(int),
                                           mod_func)) {
        printf("hash_bucket_init fail\n");
        return;
    }

    printf("\nprint hash_bucket\n");
    print_hash_bucket(&hash_bucket);
    printf("hash table capacity: %zu\n", get_hash_bucket_capacity(&hash_bucket));
    printf("hash table size: %zu\n", get_hash_bucket_size(&hash_bucket));

    for (i = 0; i < sizeof(numbers) / sizeof(int); ++i) {
        found = hash_bucket_find_by_key(&hash_bucket, numbers[i]);

        if (NULL == found) {
            int random_num = rand() % 100 + 1;
            printf("random num: %d\n", random_num);

            if (HASH_BUCKET_OK != hash_bucket_insert_kv_pair(&hash_bucket,
                                                             numbers[i],
                                                             random_num)) {
                printf("hash_bucket_insert_kv_pair failed, key: %d, value: %d\n",
                        numbers[i], random_num);
            }
        }
    }

    printf("\nhash_bucket[%d]: %d\n", 55, get_value_by_key(&hash_bucket, 55));
    printf("hash_bucket[%d]: %d\n", 33, get_value_by_key(&hash_bucket, 33));

    printf("\nprint hash_bucket\n");
    print_hash_bucket(&hash_bucket);
    printf("hash table capacity: %zu\n", get_hash_bucket_capacity(&hash_bucket));
    printf("hash table size: %zu\n", get_hash_bucket_size(&hash_bucket));

    printf("\nhash_bucket_remove_by_key\n");
    if (HASH_BUCKET_OK != hash_bucket_remove_by_key(&hash_bucket, 1)) {
        printf("hash_bucket_remove_by_key failed, key: %d\n", 1);
    }

    if (HASH_BUCKET_OK != hash_bucket_remove_by_key(&hash_bucket, 106)) {
        printf("hash_bucket_remove_by_key failed, key: %d\n", 106);
    }

    printf("\nprint hash_bucket\n");
    print_hash_bucket(&hash_bucket);
    printf("hash table capacity: %zu\n", get_hash_bucket_capacity(&hash_bucket));
    printf("hash table size: %zu\n", get_hash_bucket_size(&hash_bucket));

    printf("\nhash bucket destroy\n");
    hash_bucket_destroy(&hash_bucket);

    printf("hash table capacity: %zu\n", get_hash_bucket_capacity(&hash_bucket));
    printf("hash table size: %zu\n", get_hash_bucket_size(&hash_bucket));
}

int main(void)
{
    test();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值