C 实现ArrayMap字典映射

    字典映射是最重要的基础工具。我并没有使用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 here

	if (guess == low)
	{
		// find guess is smaller than key in ArrayStrMap insert value after
		// or ArrayStrMap empty
		guess++;
	}

	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 empty
		guess++;
	}

	// when ArrayStrMap empty guess is 0, so we -1
	return -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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质?你是否想成为一名资深开发人员,想开发别人做不了的高性能程序?你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹? 那么C++就是你个人能力提升,职业之路进阶的不二之选。【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署;2.吊打一切关于C++的笔试面试题;3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块基础篇本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。进阶篇本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。提升篇:本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值