我正在尝试找到一种以高效的方式在C中存储“密钥,值”对以便快速检索数据的方法。我一直在网上看,似乎没有一种快速简便的方法来存储它们,例如Java。我需要能够经常访问和更新值,并且还能够添加新密钥并按顺序对其进行排序。我已经阅读过使用qsort()
和bsearch()
来完成这些工作,但我不确定使用什么数据结构来存储它们。
答案 0 :(得分:3)
您正在寻找一个关联容器。 C中没有“直接”方式,因为标准库不提供任何数据结构。您可以尝试寻找提供功能的第三方库,或者推出自己的解决方案。
答案 1 :(得分:2)
我意识到这是一个旧线程,但我可能会有一些贡献,可能对寻求不太复杂的解决方案的其他人有用。
我已经以不同的方式做了好几次。如何完成取决于几个因素:
如果对1和2的答案为“是”,则可以非常直接。当对3的答案“无关紧要”,或者当最大对数不是太高时,我使用数组或动态分配的内存块作为数组。
在此方案中,有两个数组: - 索引数组(不是键) - 包含键名和值
的键/值对结构数组您还有一个跟踪键/值列表的结构,该列表包含(最低限度)指向索引和键/值结构数组的指针,当前定义的键/值对的数量以及键/值对的最大数量可以存储。
最初,键/值对的数量为0,索引数组中的每个数组元素都包含一个初始值(可以为零,但通常表示它未被使用,如-1),并且所有键/值对结构数组的元素被清零(没有名称,没有值)。
维护索引数组,以便索引值以正确的顺序引用另一个数组中的键/值对结构。插入和删除不会移动任何现有的对结构,只会移动索引。删除键/值对时,将包含它的结构清零。
当使用“qsort()”或其兄弟时,您的比较函数使用索引数组中的索引来访问相应键/值对的名称,并且您的交换函数交换索引数组中的索引值。插入执行重叠的就地复制(从结束到插入点)以将新键之后的键的索引拖放到索引数组中的一个位置,并且删除执行类似的向上移动以关闭删除的间隙关键是。
稍微快一点的版本,不再使用内存进行存储,使用C联合允许前向链索引存储在未使用的键/值对元素中,初始化将它们与“下一个免费”索引链接在一起在列表上下文中。这可以防止在插入新对时必须在列表中搜索空闲元素。当您需要一个空闲的键/值对对象时,使用存储在“next free”中的索引作为新元素,并将“next free”设置为刚刚声明的自由对象中的存储链索引。丢弃一对时,只需将“next free”值复制到释放对象的链索引中,并将释放对象的索引设置为“next free”的新值。
索引数组也可以使用指向存储器中的键/值结构的指针来实现。在这种情况下,自由对象列表中的“下一个空闲”和链接链接也成为指针。
上述方案适用于小键/值集大小和简单值类型。
答案 2 :(得分:1)
正如Baltasarq所说,C没有用于此目的的数据结构。但是,您可以使用基于struct的实现,该实现必须支持:初始化,获取,添加和删除操作。提出了一些好的设计here。
答案 3 :(得分:0)
一种非常快速且内存有效的方法是使用Judy数组。 只要你不害怕指针,它就很容易使用。
根据LGPL许可
可以安装在Debian / Ubuntu上: sudo apt-get install libjudy-dev
有一点需要注意,一个单词是原生CPU单词的长度。这使得它很快,但在使用Judy1或JudyL时可能会在32/64位机器之间产生可移植性。
可以使用以下类型:
Judy1 - maps an Index (word) to a bit
JudyL - maps an Index (word) to a Value (word/pointer)
JudySL - maps an Index (null terminated string) to a Value
JudyHS - maps an Index (array-of-bytes) of Length to a Value
使用字符串作为键的示例代码(JudySL):
#include <stdio.h>
#include <Judy.h>
#define DIE(x) { fprintf(stderr,"%s\n",x); exit(-1); }
int main() {
Pvoid_t PJArray = (PWord_t)NULL; // Judy array.
PWord_t PValue; // Judy array element.
Word_t Bytes; // size of JudySL array.
uint8_t key[100]; //max len for key is 100
const char *value1="Value One";
const char *value2="Value Two";
JSLI(PValue, PJArray, "key1"); // Insert key
if (PValue == PJERR) DIE("Out of memory\n");
*PValue=(Word_t)value1; // Set pointer to value
JSLI(PValue, PJArray, "key2"); // Insert key
if (PValue == PJERR) DIE("Out of memory\n");
*PValue=(Word_t)value2; // Set pointer to value
key[0]='\0'; // start with smallest string.
JSLF(PValue, PJArray, key); // get first key/value
while (PValue != NULL) {
printf("key=%s, value=%s\n",key,(char*)*PValue);
JSLN(PValue, PJArray, key); // get next key/value
}
JSLG(PValue, PJArray, "key2"); // lookup a key
printf("key2:%s\n",(char*)*PValue);
JSLFA(Bytes, PJArray); // free array
return 0;
}
编译:gcc judy_sample.c -o judy_sample -lJudy