C语言实现通用数据结构之通用映射(HashMap)

 更新时间:2021年11月26日 17:38:53   作者:swwlqw  
这篇文章主要为大家详细介绍了C语言实现通用数据结构之通用映射,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了C语言实现通用数据结构之通用映射的具体代码,供大家参考,具体内容如下

这是在通用链表的基础上实现的映射,关于链表的实现参见:C语言实现通用数据结构之通用链表

注意映射中只存储了key和value的指针,没有储存实际的数据。

对于新的key类型来说,需要自定义HashCode函数和equal函数。

在HashSet的实现中给出了几个常见的hashCode函数和equal函数。参见:c语言实现通用数据结构(四):通用集合。

头文件:myHashMap.h

#ifndef MYHASHMAP_H_INCLUDED
#define MYHASHMAP_H_INCLUDED
#include "myList.h"
 
#define DEFAULT_INITIAL_CAPACITY 16
#define DEFAULT_LOAD_FACTOR 0.75f
 
typedef struct entry
{
    void * key;
    void * value;
} Entry;
 
typedef struct myHashMap
{
    int size;   //大小
    int initialCapacity; //初始容量
    float loadFactor;   //加载因子
    int (*hashCode)(void *key);
    int (*equal)(void *key1,void *key2);
    MyList ** entryList;
} MyHashMap;
 
typedef struct myHashMapEntryIterator
{
    int index;       //第几个链表
    MyHashMap *map;
    MyNode *current;
    int count;        //第几个数据
} MyHashMapEntryIterator;
 
//创建HashMap
MyHashMap *createMyHashMap(int (*hashCode)(void *key),int (*equal)(void *key1,void *key2));
 
//使用全部参数创建HashMap
MyHashMap *createMyHashMapForAll(int initialCapacity,float loadFactor,int (*hashCode)(void *key),int (*equal)(void *key1,void *key2));
 
//释放HashMap
void freeMyHashMap(MyHashMap * map);
 
//是否包含某个key
int myHashMapContainsKey(MyHashMap *const map,void * const key);
 
//增加一条映射
void myHashMapPutData(MyHashMap *const map,void * const key,void * const value);
 
//通过key得到数据,如果没有数据则返回null
void* myHashMapGetDataByKey(MyHashMap * const map,void *const key);
 
//数据的容量
int myHashMapGetSize(const MyHashMap * const map);
 
//创建Entry迭代器
MyHashMapEntryIterator* createMyHashMapEntryIterator( MyHashMap *const map);
 
//释放Entry迭代器
void freeMyHashMapEntryIterator(MyHashMapEntryIterator* iterator);
 
//Entry迭代器是否有下一个
int myHashMapEntryIteratorHasNext(MyHashMapEntryIterator* iterator);
 
//遍历下一个Entry元素
Entry* myHashMapEntryIteratorNext(MyHashMapEntryIterator* iterator);
 
//删除一条数据,返回是否删除成功
int myHashMapRemoveDataByKey(MyHashMap *const map,void * const key);
 
//遍历
void myHashMapOutput(MyHashMap *map, void(*pt)(Entry*));
 
#endif // MYHASHMAP_H_INCLUDED

源文件:  myHashMap.c

#include "myHashMap.h"
#include <stdlib.h>
 
//某条Entry链表上是否包含某个key值。
Entry* listContainsEntry(MyList * list, void * key,
  int(*equal)(void *key1, void *key2)) {
 MyListIterator* it = createMyListIterator(list);
 while (myListIteratorHasNext(it)) {
  Entry * entry = (Entry *) (myListIteratorNext(it));
  if (entry->key == key || (equal != NULL && (*equal)(entry->key, key))) {
   return entry;
  }
 }
 freeMyListIterator(it);
 return NULL;
}
 
void rebuildMyHashMap(MyHashMap * map) {
 int newSize = map->initialCapacity * 2;
 MyList **newentryList = (MyList **) malloc(sizeof(MyList*) * newSize);
 for (int i = 0; i < newSize; i++) {
  newentryList[i] = createMyList();
 }
 MyHashMapEntryIterator* it = createMyHashMapEntryIterator(map);
 while (myHashMapEntryIteratorHasNext(it)) {
  Entry * entry = myHashMapEntryIteratorNext(it);
  int hasCode = (*(map->hashCode))(entry->key);
  hasCode %= newSize;
  if (hasCode < 0)
   hasCode += newSize;
  myListInsertDataAtLast(newentryList[hasCode], entry);
 }
 freeMyHashMapEntryIterator(it);
 for (int i = 0; i < map->initialCapacity; i++) {
  freeMyList(map->entryList[i]);
 }
 free(map->entryList);
 map->entryList = newentryList;
 map->initialCapacity = newSize;
}
 
//创建HashMap
MyHashMap *createMyHashMap(int(*hashCode)(void *key),
  int(*equal)(void *key1, void *key2)) {
 MyHashMap *re = (MyHashMap *) malloc(sizeof(MyHashMap));
 re->size = 0;
 re->loadFactor = DEFAULT_LOAD_FACTOR;
 re->initialCapacity = DEFAULT_INITIAL_CAPACITY;
 re->entryList = (MyList **) malloc(sizeof(MyList*) * re->initialCapacity);
 re->hashCode = hashCode;
 re->equal = equal;
 for (int i = 0; i < re->initialCapacity; i++) {
  re->entryList[i] = createMyList();
 }
 return re;
}
 
//使用全部参数创建HashMap
MyHashMap *createMyHashMapForAll(int initialCapacity, float loadFactor,
  int(*hashCode)(void *key), int(*equal)(void *key1, void *key2)) {
 MyHashMap *re = createMyHashMap(hashCode, equal);
 re->initialCapacity = initialCapacity;
 re->loadFactor = loadFactor;
 return re;
}
 
//是否包含某个key
int myHashMapContainsKey(MyHashMap * const map, void * const key) {
 int hasCode = (*(map->hashCode))(key);
 hasCode %= map->initialCapacity;
 if (hasCode < 0)
  hasCode += map->initialCapacity;
 Entry * re = listContainsEntry(map->entryList[hasCode], key, map->equal);
 return re != NULL;
}
 
//增加一条映射
void myHashMapPutData(MyHashMap * const map, void * const key,
  void * const value) {
 int hasCode = (*(map->hashCode))(key);
 hasCode %= map->initialCapacity;
 if (hasCode < 0)
  hasCode += map->initialCapacity;
 Entry * re = listContainsEntry(map->entryList[hasCode], key, map->equal);
 if (re == NULL) {
  Entry * entry = (Entry*) malloc(sizeof(Entry));
  entry->key = key;
  entry->value = value;
  myListInsertDataAtLast(map->entryList[hasCode], entry);
  (map->size)++;
  if (map->size > map->initialCapacity * map->loadFactor) {
   rebuildMyHashMap(map);
  }
 } else {
  re->value = value;
 }
}
 
//通过key得到数据,如果没有数据则返回null
void* myHashMapGetDataByKey(MyHashMap * const map, void * const key) {
 int hasCode = (*(map->hashCode))(key);
 hasCode %= map->initialCapacity;
 if (hasCode < 0)
  hasCode += map->initialCapacity;
 Entry * re = listContainsEntry(map->entryList[hasCode], key, map->equal);
 if (re == NULL) {
  return NULL;
 }
 return re->value;
}
 
//数据的容量
int myHashMapGetSize(const MyHashMap * const map) {
 return map->size;
}
 
//创建Entry迭代器
MyHashMapEntryIterator* createMyHashMapEntryIterator(MyHashMap * const map) {
 MyHashMapEntryIterator* re = (MyHashMapEntryIterator*) malloc(
   sizeof(MyHashMapEntryIterator));
 re->count = 0;
 re->index = 0;
 re->map = map;
 re->current = map->entryList[0]->first;
 return re;
}
 
//释放Entry迭代器
void freeMyHashMapEntryIterator(MyHashMapEntryIterator* iterator) {
 free(iterator);
}
 
//Entry迭代器是否有下一个
int myHashMapEntryIteratorHasNext(MyHashMapEntryIterator* iterator) {
 return iterator->count < iterator->map->size;
}
 
//遍历下一个Entry元素
Entry* myHashMapEntryIteratorNext(MyHashMapEntryIterator* iterator) {
 (iterator->count)++;
 while (!(iterator->current)) {
  (iterator->index)++;
  iterator->current = iterator->map->entryList[iterator->index]->first;
 }
 Entry * re = (Entry *) iterator->current->data;
 iterator->current = iterator->current->next;
 return re;
}
 
//删除一条数据,返回是否删除成功
int myHashMapRemoveDataByKey(MyHashMap * const map, void * const key) {
 int hasCode = (*(map->hashCode))(key);
 hasCode %= map->initialCapacity;
 if (hasCode < 0)
  hasCode += map->initialCapacity;
 MyListIterator* it = createMyListIterator(map->entryList[hasCode]);
 int re = 0;
 while (myListIteratorHasNext(it)) {
  Entry * entry = (Entry *) (myListIteratorNext(it));
  if ((*(map->equal))(entry->key, key)) {
   myListRemoveDataAt(map->entryList[hasCode], it->count - 1);
   re = 1;
   (map->size)--;
   break;
  }
 }
 freeMyListIterator(it);
 return re;
}
 
void myFree(Entry * p){
    free(p);
}
 
//释放HashMap
void freeMyHashMap(MyHashMap * map) {
 myHashMapOutput(map, myFree);
 for (int i = 0; i < map->initialCapacity; i++) {
  freeMyList(map->entryList[i]);
 }
 free(map->entryList);
 free(map);
}
 
//遍历
void myHashMapOutput(MyHashMap *map, void(*pt)(Entry*)) {
 MyHashMapEntryIterator* iterator = createMyHashMapEntryIterator(map);
 while (myHashMapEntryIteratorHasNext(iterator)) {
  pt(myHashMapEntryIteratorNext(iterator));
 }
 freeMyHashMapEntryIterator(iterator);
}

测试文件

/*************************
*** File main.c
*** test for MyHashMap
**************************/
#include <stdio.h>
#include <stdlib.h>
#include "myEqual.h"
#include "myHashCode.h"
#include "myHashMap.h"
 
#define S 10
 
char* strs[S]=
{
    "abc",
    "qq",
    "hello",
    "abc",
    "lmy",
    "ab",
    "qq",
    "lqw",
    "sww",
    "lqw"
};
 
 
int main()
{
 
    int*  data = malloc(sizeof(int)* S);
    for (int i=0; i<S; i++)
    {
        data[i]=i;
    }
 
    //创建映射需要指定两个函数,hashCode函数和equal函数。
    MyHashMap * map = createMyHashMap(myHashCodeString, myEqualString);
 
    //插入数据
    for (int i=0; i<S; i++)
    {
        myHashMapPutData(map, strs[i], &data[i]);
    }
 
    //输出大小
    printf("size=%d\n",myHashMapGetSize(map));
 
    //测试删除
    myHashMapRemoveDataByKey(map,"qq");
    myHashMapRemoveDataByKey(map,"ab");
    myHashMapRemoveDataByKey(map,"qwert");
 
    //输出大小
    printf("after remove size=%d\n",myHashMapGetSize(map));
 
    //遍历
    MyHashMapEntryIterator * it = createMyHashMapEntryIterator(map);
    while(myHashMapEntryIteratorHasNext(it))
    {
        Entry * pp= myHashMapEntryIteratorNext(it);
        char * key = pp-> key;
        int * value = pp->value;
        printf("%s(%d)\n", key, *value);
    }
    //释放遍历器
    freeMyHashMapEntryIterator(it);
 
    //释放映射
    freeMyHashMap(map);
 
    //释放数据
    free(data);
    return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C++高级数据结构之线段树

    C++高级数据结构之线段树

    这篇文章主要介绍了C++高级数据结构之线段树,文章围绕主题的相关资料展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • 如何配置 Sublime Text4为 C++ 编辑器

    如何配置 Sublime Text4为 C++ 编辑器

    这篇文章主要介绍了配置Sublime Text4为C++编辑器,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • C++位操作实战掩码、提取与组装

    C++位操作实战掩码、提取与组装

    在C++编程中,位操作是基础而强大的技术,允许在二进制级别上操作数据,对性能优化、内存节省和底层硬件控制至关重要,文章探讨了掩码操作、字节提取与组装等技术,并介绍了bitset类模板的使用,帮助处理二进制数据,通过实例解析如何设置、清除、检查特定位
    2024-10-10
  • C++中 set的用法

    C++中 set的用法

    这篇文章主要介绍了C++中 set的用法,set的内部使用了红黑树对所有的元素进行了排序。在树结构当中,我们通常使用的都是<key, value>的形式。下面我们来看看该内容的具体情况,需要的朋友也可以参考一下
    2021-11-11
  • C语言PlaySound函数使用方法

    C语言PlaySound函数使用方法

    这篇文章介绍了C语言PlaySound函数的使用方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • C++ 中 socket编程实例详解

    C++ 中 socket编程实例详解

    这篇文章主要介绍了C++ 中 socket编程实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • 在VC中隐藏控制台程序窗口的实现代码

    在VC中隐藏控制台程序窗口的实现代码

    大家都知道,当编写一个win32 console application时,当运行此类程序的时候默认情况下会有一个类似dos窗口的console窗口,但是有的时候我们只想在程序中运行一段功能代码,不希望显示这个console窗口,让代码执行完毕之后程序自动退出
    2013-04-04
  • 详解应用程序与驱动程序通信DeviceIoControl

    详解应用程序与驱动程序通信DeviceIoControl

    这种通信方式,就是驱动程序和应用程序自定义一种IO控制码,然后调用DeviceIoControl函数,IO管理器会产生一个MajorFunction为IRP_MJ_DEVICE_CONTROL,MinorFunction为自己定义的控制码的IRP,系统就调用相应的处理IRP_MJ_DEVICE_CONTROL的派遣函数
    2021-06-06
  • Effective C++ 入门学习笔记

    Effective C++ 入门学习笔记

    这篇文章主要介绍了Effective C++ 入门学习笔记,需要的朋友可以参考下
    2023-08-08
  • 基于Windows API分解路径问题的详解

    基于Windows API分解路径问题的详解

    本篇文章是对Windows API分解路径进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论