linux c实现通用hash表

5 篇文章 0 订阅
4 篇文章 0 订阅

通用哈希散列表C语言实现

此博客只有代码,hash表概念等,请自行学习。此次hash中使用链表为本人所写。后续改写此hash表,使用内核链表,详情请查看下一个博客。

代码块

common.h:

#pragma once
#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#endif

hash.h

#pragma once
#ifndef _HASH_H_
#define _HASH_H_

/*此方法采用的是连地址法*/

/*为了不将hash结构暴露在外面,所以就必须typedef*/
typedef struct hash hash_t;
//这是一个hash函数指针,对用户来说应该需要使用一个合适的hash函数
//第一个参数unsigned int指的是桶的大小 第二个参数是key值
typedef unsigned int(*hash_func_t)(unsigned int,void *);

/*返回的是hash表指针,创建hash表*/
hash_t *hash_alloc(unsigned int,hash_func_t);
void *hash_lookup_entry(hash_t *,void *,unsigned int );

void hash_add_entry(hash_t *, void *, unsigned int ,
    void *, unsigned int );
void hash_free_entry(hash_t *,void *,int );


#endif /*_HASH_H_*/

hash.c

#include "hash.h"
#include "common.h"
//必须在前面声明typedef
typedef struct hash_node {
    void *key;//查找依据
    void *data;//数据块,一般是结构体
    struct hash_node *prev;
    struct hash_node *next;
}hash_node_t;
struct hash {
    unsigned int buckets;//桶的个数(大小)
    hash_func_t hash_func;//hash函数指针
    hash_node_t **nodes;//hash表中存放的链表地址
};
//由于获得桶,和得到node节点的接口并不需要外部看见,所以定义成两个内部函数
/*根据key,得到桶*/
hash_node_t **hash_get_buckets(hash_t *hash,void *key);
/*根据key得到node节点*/
hash_node_t * hash_get_node_by_key(hash_t *hash,void *key,unsigned int key_size);
//创建hash表
hash_t *hash_alloc(unsigned int buckets, hash_func_t hash_func)
{
    hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
    hash->buckets = buckets;
    hash->hash_func = hash_func;
    unsigned int size = buckets * sizeof(hash_node_t *);
    hash->nodes = (hash_node_t **)malloc(size);
    memset(hash->nodes,0x00, size);
    return hash;
}
//判断
void* hash_lookup_entry(hash_t *hash, void *key, unsigned int key_size)
{
    hash_node_t  *node = hash_get_node_by_key(hash,key, key_size);
    if (NULL == node) return NULL;
    return node->data;
}
//添加hash节点
void hash_add_entry(hash_t *hash, void *key, unsigned int key_size,void *data, unsigned int data_size)
{
    //首先需要查找看此数据项是否存在,如果存在则表明重复了,需要返回
    if (hash_lookup_entry(hash, key, key_size)) {
        printf("duplicate hash key\n");
        return;
    }
    //创建节点,申请内存
    hash_node_t *node = (hash_node_t*)malloc(sizeof(hash_node_t));
    node->next = NULL;
    node->prev = NULL;
    node->key = malloc(key_size);
    memcpy(node->key,key,key_size);
    node->data = malloc(data_size);
    memcpy(node->data, data, data_size);
    //采用头插法,将节点插入到hash表中
    //1.首先得取到桶
    hash_node_t **bucket = hash_get_buckets(hash,key);
    //如果没有节点
    if (*bucket == NULL) {
        *bucket = node;
    }
    else {
        node->next = *bucket;
        (*bucket)->prev = node;
        *bucket = node;
    }
}
//释放节点
void hash_free_entry(hash_t *hash, void *key, int key_size)
{
    //释放节点首先得找到节点,
    hash_node_t *node = hash_get_node_by_key(hash,key,key_size);
    if (node == NULL) return;
    if (node->prev) {
        node->prev->next = node->next;
    }
    else{
        //如果是第一个节点,就必须获得桶节点
        hash_node_t **bucket = hash_get_buckets(hash,key);
        *bucket = node->next;
    }
    if (node->next) {
        node->next->prev = node->prev;
    }
    free(node->key);
    free(node->data);
    free(node);
}
//根据key得到buckets号
hash_node_t **hash_get_buckets(hash_t *hash, void *key)
{
    unsigned int buckets = hash->hash_func(hash->buckets,key);
    if (buckets >= hash->buckets){
        printf("bad buckets loockup\n");
    }
    return &(hash->nodes[buckets]);
}
//通过key值,得到node节点
hash_node_t * hash_get_node_by_key(hash_t *hash, void *key, unsigned int key_size) 
{
    hash_node_t **buckets = hash_get_buckets(hash,key);
    hash_node_t *node = *buckets;
    if (node == NULL) return NULL;
    //没有找到,有那两种可能,一种是节点就不存在,另一种是没有找到
    while (node != NULL && memcmp(node->key, key, key_size) != 0) {
        node = node->next;
    }
    return node;
}

main.c

#include "common.h"
#include "hash.h"

typedef struct student_t {
    int eno;
    char *name;
    unsigned int age;
}student;

//编写hash函数
unsigned int hash_func(unsigned int bucktes, void *key)
{
    return *((unsigned int*)(key)) % bucktes;
}
int main(int argc, char *argv[])
{
    student stu_arry[] = {
        { 23,"aaa",20 },
        { 63,"bbb",30 },
        { 56,"ccc",40 },
        { 78,"gfr",20 },
        { 59,"bhk",30 },
        { 42,"cki",90 }
    };
    //首先创建hash table,
    hash_t *hash = hash_alloc(80, hash_func);
    //将数据添加进hash table;
    int size = sizeof(stu_arry) / sizeof(stu_arry[0]);
    int i = 0;
    for (i = 0; i < size; i++)
    {
        hash_add_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno),
            &(stu_arry[i]), sizeof((stu_arry[i])));
    }
    //查找打印
    printf("......................add end...............\n");
    student *st = NULL;
    for (i = 0; i < size; i++)
    {
        st = (student*)hash_lookup_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno));
        if (st) {
            printf("st : eno %-10d  name : %-10s  age : %-10d\n", st->eno, st->name, st->age);
        }
        else {
            printf("no node \n");
        }
    }
    for (i = 0; i < size; i++)
    {
        hash_free_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno));
    }
    printf("......................free end...............\n");
    for (i = 0; i < size; i++)
    {
        st = (student*)hash_lookup_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno));
        if (st) {
            printf("st : eno %-10d  name : %-10s  age : %-10d\n", st->eno, st->name, st->age);
        }
        else {
            printf("no node \n");
        }
    }
    system("pause");
    return 0;
}

此代码在linux 与vs上均测试通过。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用哈希实现俩字符串的映射。具体步骤如下: 1. 定义一个哈希,用来存储键值对。 2. 遍历第一个字符串中的每一个字符,并将其作为键存入哈希中,值为第二个字符串中对应位置的字符。 3. 遍历第二个字符串中的每一个字符,并将其作为键存入哈希中,值为第一个字符串中对应位置的字符。 4. 最后遍历哈希,输出所有的键值对即可。 下面是示例代码实现: ``` #include <stdio.h> #include <string.h> #define MAX_SIZE 100 int main() { char str1[MAX_SIZE], str2[MAX_SIZE]; int len1, len2, i; char map[MAX_SIZE][2]; printf("请输入第一个字符串:"); fgets(str1, MAX_SIZE, stdin); len1 = strlen(str1) - 1; // 减去末尾的换行符 printf("请输入第二个字符串:"); fgets(str2, MAX_SIZE, stdin); len2 = strlen(str2) - 1; // 减去末尾的换行符 if (len1 != len2) { printf("两个字符串长度不相等,无法映射。\n"); return 0; } for (i = 0; i < len1; i++) { map[i][0] = str1[i]; map[i][1] = str2[i]; } printf("映射结果为:\n"); for (i = 0; i < len1; i++) { printf("%c-%c ", map[i][0], map[i][1]); } printf("\n"); return 0; } ``` 注意:这里使用了 fgets() 函数来读取用户输入的字符串,而不是 scanf() 函数,因为 scanf() 函数会在遇到空格或换行符时停止读取,而 fgets() 函数会读取整个字符串,包括空格和换行符。 ### 回答2: 在Linux C中实现两个字符串的映射,可以使用哈希实现。哈希是一种常用的数据结构,它可以将键值对以键的哈希值为索引存储在中,可以快速地进行查找操作。 首先,我们需要定义一个哈希的结构体,包括的大小、存储数据的数组和一个哈希函数。 ```c #define TABLE_SIZE 1000 typedef struct { char* key; char* value; } KeyValuePair; typedef struct { int size; KeyValuePair table[TABLE_SIZE]; } HashMap; ``` 然后,我们需要实现一个哈希函数,它能够将字符串映射到哈希中的对应位置。 ```c int hash(char* str) { unsigned long hash = 5381; int c; while ((c = *str++)) { hash = ((hash << 5) + hash) + c; } return hash % TABLE_SIZE; } ``` 接下来,我们可以实现向哈希中插入键值对和查找键对应的值的函数。 ```c void insert(HashMap* map, char* key, char* value) { int index = hash(key); KeyValuePair* pair = &map->table[index]; pair->key = strdup(key); pair->value = strdup(value); } char* getValue(HashMap* map, char* key) { int index = hash(key); KeyValuePair* pair = &map->table[index]; if (pair->key != NULL && strcmp(pair->key, key) == 0) { return pair->value; } return NULL; } ``` 最后,我们可以通过调用这些函数来实现字符串的映射。 ```c int main() { HashMap map; map.size = TABLE_SIZE; insert(&map, "apple", "苹果"); insert(&map, "banana", "香蕉"); char* value = getValue(&map, "apple"); if (value != NULL) { printf("%s\n", value); // 输出:苹果 } value = getValue(&map, "grape"); if (value != NULL) { printf("%s\n", value); } else { printf("没有找到对应的映射\n"); // 输出:没有找到对应的映射 } return 0; } ``` 通过以上的代码,我们可以快速地在Linux C中实现俩字符串的映射,并且能够在需要时快速地获取对应的映射值。 ### 回答3: 在Linux的C语言中实现俩字符串的映射可以使用哈希来存储键值对。哈希是一种高效的数据结构,可以通过哈希函数将字符串转换成唯一的索引,在常数时间内查找和插入操作。 首先,我们需要定义一个哈希的结构体,包含两个成员:数组和数组长度。数组的每个元素是一个链,用来解决哈希冲突问题。 接下来,我们需要实现哈希函数,将字符串转换成哈希的索引。一个简单的哈希函数是将字符串的ASCII码相加,然后取余操作来得到索引值。 然后,我们需要实现插入操作。通过哈希函数计算出索引值后,将键值对插入到对应的链中。如果链中已经存在相同的键,则更新该键对应的值。 最后,我们可以实现查找操作。同样通过哈希函数计算出索引值后,遍历链,找到对应的键值对。如果找到了对应的键,则返回对应的值,否则返回空。 通过以上的步骤,我们就可以在Linux的C语言中实现俩字符串的映射。使用哈希可以高效地进行插入和查找操作,提高程序的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值