C 实现ArrayMap字典映射
来源:互联网 发布:网络大电影拍摄团队 编辑:程序博客网 时间:2024/06/05 17:09
字典映射是最重要的基础工具。我并没有使用hash做散列映射,而是使用了简单直接的二分查找。其主要的思路如下:
- 使用字符串的长度,进行二分查找存储
- 如果字符长度相等,使用字符串的字典顺序,进行二分查找存储
- 缓存字符串的长度,用来减少字符串长度的计算函数调用
- 元素是有序的存储在一个动态数组里
- 提供一套元素的访问方法
- 实现依赖 C 实现泛型ArrayList数组
首先看结构
typedef struct{const char* key;/** strlen(key) + 1 include '\0' */int keyLength;/** * ArrayStrMap value pointer * value data copy into ArrayStrMapElement */void* valuePtr;}ArrayStrMapElement;typedef struct{ArrayList arrayList[1];/** ArrayStrMap value type sizeof */int typeSize;}ArrayStrMap;
ArrayStrMapElement 代表了存储的一个元素,valuePtr 指向传入存储的元素结构,可以看到缓存了key和key length。ArrayStrMap是用了ArrayList来存储数据,每个数据就是一个ArrayStrMapElement,typeSize是valuePtr指向元素的结构大小。
一系列元素访问接口如下:
typedef struct{ArrayStrMap* (*Create) (int typeSize);void (*Init) (int typeSize, ArrayStrMap* outArrayStrMap);ArrayStrMap* (*CreateWithCapacity) (int typeSize, int capacity);void (*InitWithCapacity) (int typeSize, int capacity, ArrayStrMap* outArrayStrMap);/** * Release member memory space */void (*Release) (ArrayStrMap* arrayStrMap);/** * Put key and value from valuePtr into ArrayStrMap * valuePtr point to value * return valuePtr in ArrayStrMap */void* (*Put) (ArrayStrMap* arrayStrMap, const char* key, void* valuePtr);/** * Get valuePtr by key, if no key found return defaultValuePtr */void* (*Get) (ArrayStrMap* arrayStrMap, const char* key, void* defaultValuePtr);/** * Set new value from valuePtr by key , return valuePtr in ArrayStrMap */void* (*Set) (ArrayStrMap* arrayStrMap, const char* key, void* valuePtr);/** * Remove value by key * return true success, false failed */bool (*TryRemove) (ArrayStrMap* arrayStrMap, const char* key);/** * Clear all value, reset size 0, and keep memory space */void (*Clear) (ArrayStrMap* arrayStrMap);/** * Insert value from valuePtr at index, the possible index may be -getIndex() - 1 * return valuePtr in ArrayStrMap */void* (*InsertAt) (ArrayStrMap* arrayStrMap, const char* key, int index, void* valuePtr);/** * Get index of key, if negative not found then return -insertIndex - 1 * so insert index is -getIndex() - 1 */int (*GetIndex) (ArrayStrMap* arrayStrMap, const char* key);/** * Get key at index */const char* (*GetKey) (ArrayStrMap* arrayStrMap, int index);/** * Get valuePtr at index */void* (*GetAt) (ArrayStrMap* arrayStrMap, int index);/** * Put value from valuePtr at index * return valuePtr in ArrayStrMap */void* (*PutAt) (ArrayStrMap* arrayStrMap, int index, void* valuePtr);/** * Remove value at index */void (*RemoveAt) (ArrayStrMap* arrayStrMap, int index);}_AArrayStrMap_;extern _AArrayStrMap_ AArrayStrMap[1];
实现代码如下:
#define CheckIndex(tag, index, elements) \ALog_A(index >= 0 && index < elements->size, "ArrayStrMap " tag " index = %d, size = %d, invalid", index, elements->size)#define CheckInsertIndex(tag, index, elements) \ALog_A(index >= 0 && index <= elements->size, "ArrayStrMap " tag " index = %d, size = %d, invalid", index, elements->size)#define BinarySearch(key) \ArrayList* elements = arrayStrMap->arrayList; \int keyLength = (int) strlen(key) + 1; \int high = elements->size; \int low = -1; \int guess = -1; \int cmp = -1; \ \while (high - low > 1) \ { \guess = (high + low) >> 1; /** not consider integer overflow */ \ArrayStrMapElement* element = AArrayList_Get(elements, guess, ArrayStrMapElement*); \int elementKeyLength = element->keyLength; \ \if (elementKeyLength < keyLength) \ { \low = guess; \} \ else if (elementKeyLength > keyLength) \ { \high = guess; \} \ else if (elementKeyLength == keyLength) \ { \cmp = memcmp(element->key, key, keyLength); \if (cmp < 0) \ { \low = guess; \} \else if (cmp > 0) \{ \high = guess; \} \else if (cmp == 0) \{ \/** cmp 0 means find the key */ \break; \} \} \ }// -----------------------------------------------------------------------------------------static void* Put(ArrayStrMap* arrayStrMap, const char* key, void* valuePtr){BinarySearch(key);ALog_A(cmp != 0, "ArrayStrMap put key = %s, has already exist", key);int typeSize = arrayStrMap->typeSize;ArrayStrMapElement* element = (ArrayStrMapElement*) malloc(sizeof(ArrayStrMapElement) + typeSize + keyLength);element->keyLength = keyLength;element->valuePtr = (char*) element + sizeof(ArrayStrMapElement);memcpy(element->valuePtr, valuePtr, typeSize);element->key = (char*) element->valuePtr + typeSize;memcpy((void*) element->key, key, keyLength);// if guess == high find guess is bigger than key in ArrayStrMap insert value hereif (guess == low){// find guess is smaller than key in ArrayStrMap insert value after// or ArrayStrMap emptyguess++;}AArrayList->Insert(elements, guess, &element); return element->valuePtr;}static void* Get(ArrayStrMap* arrayStrMap, const char* key, void* defaultValuePtr){BinarySearch(key);return cmp == 0 ? AArrayList_Get(elements, guess, ArrayStrMapElement*)->valuePtr : defaultValuePtr;}static void* Set(ArrayStrMap* arrayStrMap, const char* key, void* valuePtr){BinarySearch(key);ALog_A(cmp == 0, "ArrayStrMap set key = %s, has not exist", key);void* elementValuePtr = AArrayList_Get(elements, guess, ArrayStrMapElement*)->valuePtr;memcpy(elementValuePtr, valuePtr, arrayStrMap->typeSize);return elementValuePtr;}static bool TryRemove(ArrayStrMap* arrayStrMap, const char* key){BinarySearch(key);if (cmp == 0){free(AArrayList_Get(elements, guess, ArrayStrMapElement*));AArrayList->Remove(elements, guess);return true;}return false;}static void Clear(ArrayStrMap* arrayStrMap){ArrayList* elements = arrayStrMap->arrayList;for (int i = 0; i < elements->size; i++){free(AArrayList_Get(elements, i, ArrayStrMapElement*));}AArrayList->Clear(elements);}static void* InsertAt(ArrayStrMap* arrayStrMap, const char* key, int index, void* valuePtr){ArrayList* elements = arrayStrMap->arrayList;CheckInsertIndex("InsertAt", index, elements);int keyLength = (int) strlen(key) + 1;int typeSize = arrayStrMap->typeSize;ArrayStrMapElement* element = (ArrayStrMapElement*) malloc(sizeof(ArrayStrMapElement) + typeSize + keyLength);element->keyLength = keyLength;element->valuePtr = (char*) element + sizeof(ArrayStrMapElement);memcpy(element->valuePtr, valuePtr, typeSize);element->key = (char*) element->valuePtr + typeSize;memcpy((void*) element->key, key, keyLength);AArrayList->Insert(elements, index, &element);return element->valuePtr;}static int GetIndex(ArrayStrMap* arrayStrMap, const char* key){BinarySearch(key);if (cmp == 0){return guess;}if (guess == low){// find guess is smaller than key in ArrayStrMap or ArrayStrMap emptyguess++;}// when ArrayStrMap empty guess is 0, so we -1return -guess - 1;}static const char* GetKey(ArrayStrMap* arrayStrMap, int index){ArrayList* elements = arrayStrMap->arrayList;CheckIndex("GetKey", index, elements);return AArrayList_Get(elements, index, ArrayStrMapElement*)->key;}static void* GetAt(ArrayStrMap* arrayStrMap, int index){ArrayList* elements = arrayStrMap->arrayList;CheckIndex("GetAt", index, elements);return AArrayList_Get(elements, index, ArrayStrMapElement*)->valuePtr;}static void* PutAt(ArrayStrMap* arrayStrMap, int index, void* valuePtr){ArrayList* elements = arrayStrMap->arrayList;CheckIndex("PutAt", index, elements);ArrayStrMapElement* element = AArrayList_Get(elements, index, ArrayStrMapElement*);memcpy(element->valuePtr, valuePtr, arrayStrMap->typeSize);return element->valuePtr;}static void RemoveAt(ArrayStrMap* arrayStrMap, int index){ArrayList* elements = arrayStrMap->arrayList;CheckIndex("RemoveAt", index, elements);free(AArrayList_Get(elements, index, ArrayStrMapElement*));AArrayList->Remove(elements, index);}static void Release(ArrayStrMap* arrayStrMap){ArrayList* elements = arrayStrMap->arrayList;for (int i = 0; i < elements->size; i++){free(AArrayList_Get(elements, i, ArrayStrMapElement*));}AArrayList->Release(elements);}static void InitWithCapacity(int typeSize, int capacity, ArrayStrMap* outArrayStrMap){if (capacity == 0){AArrayList->Init(sizeof(ArrayStrMapElement*), outArrayStrMap->arrayList);}else{AArrayList->InitWithCapacity(sizeof(ArrayStrMapElement*), capacity, outArrayStrMap->arrayList);}outArrayStrMap->typeSize = typeSize;}static ArrayStrMap* CreateWithCapacity(int typeSize, int capacity){ArrayStrMap* arrayStrMap = (ArrayStrMap*) malloc(sizeof(ArrayStrMap));InitWithCapacity(typeSize, capacity, arrayStrMap);return arrayStrMap;}static void Init(int typeSize, ArrayStrMap* outArrayStrMap){InitWithCapacity(typeSize, 0, outArrayStrMap);}static ArrayStrMap* Create(int typeSize){return CreateWithCapacity(typeSize, 0);}_AArrayStrMap_ AArrayStrMap[1] ={Create,Init,CreateWithCapacity,InitWithCapacity,Release,Put,Get,Set,TryRemove,Clear,InsertAt,GetIndex,GetKey,GetAt,PutAt,RemoveAt,};#undef CheckIndex#undef BinarySearch#undef CheckInsertIndex
同样会提供宏定义的快捷操作:
/** The type is the ArrayStrMap value type */#define ArrayStrMap(valueType) ArrayStrMap/** * Get key in ArrayStrMapElement by valuePtr with typeSize */#define AArrayStrMap_GetKey(valuePtr, typeSize) \((const char*) ((char*) valuePtr + typeSize))/** * Init constant ArrayStrMap, as element in ArrayStrmap array * use like ArrayStrmap arr[1] = AArrayStrMap_Init(type, increment) */#define AArrayStrMap_Init(type, increment) \{ \{ \AArayList_Init(ArrayStrMapElement*, increment), \sizeof(type), \ } \}
在实际的使用中,效率不错。虽然没有hash那样的常数级的查找,但hash会有冲突的问题,以及计算hash的运算。二分查找,50个元素需要1 - 6次查找,100个元素需要 1 - 7次查询,1000个元素需要 1 - 10次查找,10000个元素需要1 - 14次查找。通常情况下都是50个元素以内的查找。
1 0
- C 实现ArrayMap字典映射
- 字典问题---c实现
- C 字典实现
- ArrayMap
- SparseArray、ArrayMap 实现原理学习
- 字典树C语言实现
- C++Builder实现内存映射
- 利用字典实现Python中简单的ORM映射
- 映射类型 字典 (python)
- Python中的映射:字典
- Python映射之字典
- Python映射类型:字典
- Solidity 字典映射Mappings
- 字典映射代替switch
- UNIX下c实现pipe descriptors映射
- HashMap和ArrayMap实现原理的区别以及各自优势
- 字典(C#)
- c# 字典
- SQL多表查询和查询一个表中某字段值相同的数据
- CSS+JS控制字体闪烁
- js中的异常处理try...catch使用介绍
- 309.leetcode Best Time to Buy and Sell Stock with Cooldown(medium)[动态规划]
- Ubuntu 14.04下安装ns2.35
- C 实现ArrayMap字典映射
- SQL优化---SQL执行的先后顺序
- 损失函数、正则化、交叉验证
- python theano中的shared variable
- php匹配字符串URL并替换为超链接
- 算法时间复杂度的计算
- bash 编程杂项
- 关于Android Studio中点9图的编译错误问题
- (第10讲)二叉搜索树