关于C语言中的Map(thinkvd 开发日志)
来源:互联网 发布:网络安全技术 知乎 编辑:程序博客网 时间:2024/06/06 13:23
开发中用过map,但一般都是C++的,对map的好处深有体会,尤其是QT中的QMap。C语言中的Map如何实现呢,看看高人写的吧
感觉与QT中的支持QVariant支持并转换还有许多差距,没有map["abc"] = 1000这样的方式直观易用。
http://www.koders.com/c/fidCDD7DA6132DC0D5232F0EEB2AA6C9A07F8584484.aspx
/* $Id: hashmap.c,v 1.17 2005/08/15 03:54:31 rjkaes Exp $ * * A hashmap implementation. The keys are case-insensitive NULL terminated * strings, and the data is arbitrary lumps of data. Copies of both the * key and the data in the hashmap itself, so you must free the original * key and data to avoid a memory leak. The hashmap returns a pointer * to the data when a key is searched for, so take care in modifying the * data as it's modifying the data stored in the hashmap. (In other words, * don't try to free the data, or realloc the memory. :) * * Copyright (C) 2002 Robert James Kaes (rjkaes@users.sourceforge.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "tinyproxy.h"#include "hashmap.h"#include "heap.h"/* * These structures are the storage for the hashmap. Entries are stored in * struct hashentry_s (the key, data, and length), and all the "buckets" are * grouped together in hashmap_s. The hashmap_s.size member is for * internal use. It stores the number of buckets the hashmap was created * with. */struct hashentry_s { char *key; void *data; size_t len; struct hashentry_s *prev, *next;};struct hashbucket_s { struct hashentry_s *head, *tail;};struct hashmap_s { unsigned int size; hashmap_iter end_iterator; struct hashbucket_s *buckets;};/* * A NULL terminated string is passed to this function and a "hash" value * is produced within the range of [0 .. size) (In other words, 0 to one * less than size.) * The contents of the key are converted to lowercase, so this function * is not case-sensitive. * * If any of the arguments are invalid a negative number is returned. */static inthashfunc(const char *key, unsigned int size){ uint32_t hash; if (key == NULL) return -EINVAL; if (size == 0) return -ERANGE; for (hash = tolower(*key++); *key != '/0'; key++) { uint32_t bit = (hash & 1) ? (1 << (sizeof(uint32_t) - 1)) : 0; hash >>= 1; hash += tolower(*key) + bit; } /* Keep the hash within the table limits */ return hash % size;}/* * Create a hashmap with the requested number of buckets. If "nbuckets" is * not greater than zero a NULL is returned; otherwise, a _token_ to the * hashmap is returned. * * NULLs are also returned if memory could not be allocated for hashmap. */hashmap_thashmap_create(unsigned int nbuckets){ struct hashmap_s *ptr; if (nbuckets == 0) return NULL; ptr = safecalloc(1, sizeof(struct hashmap_s)); if (!ptr) return NULL; ptr->size = nbuckets; ptr->buckets = safecalloc(nbuckets, sizeof(struct hashbucket_s)); if (!ptr->buckets) { safefree(ptr); return NULL; } /* This points to "one" past the end of the hashmap. */ ptr->end_iterator = 0; return ptr;}/* * Follow the chain of hashentries and delete them (including the data and * the key.) * * Returns: 0 if the function completed successfully * negative number is returned if "entry" was NULL */static inline intdelete_hashbucket(struct hashbucket_s *bucket){ struct hashentry_s *nextptr; struct hashentry_s *ptr; if (bucket == NULL || bucket->head == NULL) return -EINVAL; ptr = bucket->head; while (ptr) { nextptr = ptr->next; safefree(ptr->key); safefree(ptr->data); safefree(ptr); ptr = nextptr; } return 0;}/* * Deletes a hashmap. All the key/data pairs are also deleted. * * Returns: 0 on success * negative if a NULL "map" was supplied */inthashmap_delete(hashmap_t map){ unsigned int i; if (map == NULL) return -EINVAL; for (i = 0; i != map->size; i++) { if (map->buckets[i].head != NULL) { delete_hashbucket(&map->buckets[i]); } } safefree(map->buckets); safefree(map); return 0;}/* * Inserts a NULL terminated string (as the key), plus any arbitrary "data" * of "len" bytes. Both the key and the data are copied, so the original * key/data must be freed to avoid a memory leak. * The "data" must be non-NULL and "len" must be greater than zero. You * cannot insert NULL data in association with the key. * * Returns: 0 on success * negative number if there are errors */inthashmap_insert(hashmap_t map, const char *key, const void *data, size_t len){ struct hashentry_s *ptr; int hash; char *key_copy; void *data_copy; assert(map != NULL); assert(key != NULL); assert(data != NULL); assert(len > 0); if (map == NULL || key == NULL) return -EINVAL; if (!data || len < 1) return -ERANGE; hash = hashfunc(key, map->size); if (hash < 0) return hash; /* * First make copies of the key and data in case there is a memory * problem later. */ key_copy = safestrdup(key); if (!key_copy) return -ENOMEM; if (data) { data_copy = safemalloc(len); if (!data_copy) { safefree(key_copy); return -ENOMEM; } memcpy(data_copy, data, len); } else { data_copy = NULL; } ptr = safemalloc(sizeof(struct hashentry_s)); if (!ptr) { safefree(key_copy); safefree(data_copy); return -ENOMEM; } ptr->key = key_copy; ptr->data = data_copy; ptr->len = len; /* * Now add the entry to the end of the bucket chain. */ ptr->next = NULL; ptr->prev = map->buckets[hash].tail; if (map->buckets[hash].tail) map->buckets[hash].tail->next = ptr; map->buckets[hash].tail = ptr; if (!map->buckets[hash].head) map->buckets[hash].head = ptr; map->end_iterator++; return 0;}/* * Get an iterator to the first entry. * * Returns: an negative value upon error. */hashmap_iterhashmap_first(hashmap_t map){ assert(map != NULL); if (!map) return -EINVAL; if (map->end_iterator == 0) return -1; else return 0;}/* * Checks to see if the iterator is pointing at the "end" of the entries. * * Returns: 1 if it is the end * 0 otherwise */inthashmap_is_end(hashmap_t map, hashmap_iter iter){ assert(map != NULL); assert(iter >= 0); if (!map || iter < 0) return -EINVAL; if (iter == map->end_iterator) return 1; else return 0;}/* * Return a "pointer" to the first instance of the particular key. It can * be tested against hashmap_is_end() to see if the key was not found. * * Returns: negative upon an error * an "iterator" pointing at the first key * an "end-iterator" if the key wasn't found */hashmap_iterhashmap_find(hashmap_t map, const char *key){ unsigned int i; hashmap_iter iter = 0; struct hashentry_s *ptr; assert(map != NULL); assert(key != NULL); if (!map || !key) return -EINVAL; /* * Loop through all the keys and look for the first occurrence * of a particular key. */ for (i = 0; i != map->size; i++) { ptr = map->buckets[i].head; while (ptr) { if (strcasecmp(ptr->key, key) == 0) { /* Found it, so return the current count */ return iter; } iter++; ptr = ptr->next; } } return iter;}/* * Retrieve the data associated with a particular iterator. * * Returns: the length of the data block upon success * negative upon error */ssize_thashmap_return_entry(hashmap_t map, hashmap_iter iter, char **key, void **data){ unsigned int i; struct hashentry_s *ptr; hashmap_iter count = 0; assert(map != NULL); assert(iter >= 0); assert(iter != map->end_iterator); assert(key != NULL); assert(data != NULL); if (!map || iter < 0 || !key || !data) return -EINVAL; for (i = 0; i != map->size; i++) { ptr = map->buckets[i].head; while (ptr) { if (count == iter) { /* This is the data so return it */ *key = ptr->key; *data = ptr->data; return ptr->len; } ptr = ptr->next; count++; } } return -EFAULT;}/* * Searches for _any_ occurrences of "key" within the hashmap. * * Returns: negative upon an error * zero if no key is found * count found */ssize_thashmap_search(hashmap_t map, const char *key){ int hash; struct hashentry_s *ptr; ssize_t count = 0; if (map == NULL || key == NULL) return -EINVAL; hash = hashfunc(key, map->size); if (hash < 0) return hash; ptr = map->buckets[hash].head; /* All right, there is an entry here, now see if it's the one we want */ while (ptr) { if (strcasecmp(ptr->key, key) == 0) ++count; /* This entry didn't contain the key; move to the next one */ ptr = ptr->next; } return count;}/* * Get the first entry (assuming there is more than one) for a particular * key. The data MUST be non-NULL. * * Returns: negative upon error * zero if no entry is found * length of data for the entry */ssize_thashmap_entry_by_key(hashmap_t map, const char *key, void **data){ int hash; struct hashentry_s *ptr; if (!map || !key || !data) return -EINVAL; hash = hashfunc(key, map->size); if (hash < 0) return hash; ptr = map->buckets[hash].head; while (ptr) { if (strcasecmp(ptr->key, key) == 0) { *data = ptr->data; return ptr->len; } ptr = ptr->next; } return 0;}/* * Go through the hashmap and remove the particular key. * NOTE: This will invalidate any iterators which have been created. * * Remove: negative upon error * 0 if the key was not found * positive count of entries deleted */ssize_thashmap_remove(hashmap_t map, const char *key){ int hash; struct hashentry_s *ptr, *next; short int deleted = 0; if (map == NULL || key == NULL) return -EINVAL; hash = hashfunc(key, map->size); if (hash < 0) return hash; ptr = map->buckets[hash].head; while (ptr) { if (strcasecmp(ptr->key, key) == 0) { /* * Found the data, now need to remove everything * and update the hashmap. */ next = ptr->next; if (ptr->prev) ptr->prev->next = ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; if (map->buckets[hash].head == ptr) map->buckets[hash].head = ptr->next; if (map->buckets[hash].tail == ptr) map->buckets[hash].tail = ptr->prev; safefree(ptr->key); safefree(ptr->data); safefree(ptr); ++deleted; --map->end_iterator; ptr = next; continue; } /* This entry didn't contain the key; move to the next one */ ptr = ptr->next; } /* The key was not found, so return 0 */ return deleted;}
参考:
http://blog.csdn.net/cheungmine/archive/2007/11/20/1894219.aspx
- 关于C语言中的Map(thinkvd 开发日志)
- thinkvd 视频效果(Thinkvd开发日志)
- 关于创业合作方面的认识(thinkvd开发日志)
- 关于swf to video convert(thinkvd开发日志)
- DVD subtitle (thinkvd开发日志)
- thinkvd开发日志(2010.11.09)
- Qt QTabWidget的BUG(thinkvd开发日志)
- SDL内存泄漏跟踪(thinkvd开发日志)
- 音视频同步问题(thinkvd开发日志)
- thinkvd将支持rmvb转换 (开发日志)
- mingw下编译mplayer (thinkvd开发日志)
- 关于dvd subtitle与effect效果有冲突问题(thinkvd开发日志)
- 关于头文件变量重复定义问题怎么解决(thinkvd开发日志)
- DVD subtitle stream in SDL(thinkvd开发日志)
- SDL 共享内存存在问题(thinkvd开发日志)
- QMessageBox 窗口大小更改问题(thinkvd开发日志)
- Qt QImage图片透明设置(Thinkvd开发日志)
- 以顺其自然的思路写程序(Thinkvd开发日志)
- wordpress首页缩略图插件Get The Image
- WinCE6.0 DEVICEEMULATOR BSP的BatteryDriver驱动简析
- java 内存
- PHP中常用函数以及若干注意点的说明(三)
- nbu1704
- 关于C语言中的Map(thinkvd 开发日志)
- dir包含完整路徑
- jQuery Corner:圆角矩形原来如此简单[zT]
- xp
- List lst = new ArrayList();与ArrayList lst = new ArrayList();区别
- 常见问题小结
- fatal error C1083: Cannot open include file: 'uxtheme.h'的解决
- 映像劫持原理
- httpHandlers和httpModules接口介绍 (1)