在普通C中存储键值对

时间:2013-03-25 21:10:51

标签: c dictionary

我正在尝试找到一种以高效的方式在C中存储“密钥,值”对以便快速检索数据的方法。我一直在网上看,似乎没有一种快速简便的方法来存储它们,例如Java。我需要能够经常访问和更新值,并且还能够添加新密钥并按顺序对其进行排序。我已经阅读过使用qsort()bsearch()来完成这些工作,但我不确定使用什么数据结构来存储它们。

4 个答案:

答案 0 :(得分:3)

您正在寻找一个关联容器。 C中没有“直接”方式,因为标准库不提供任何数据结构。您可以尝试寻找提供功能的第三方库,或者推出自己的解决方案。

答案 1 :(得分:2)

我意识到这是一个旧线程,但我可能会有一些贡献,可能对寻求不太复杂的解决方案的其他人有用。

我已经以不同的方式做了好几次。如何完成取决于几个因素:

  1. 您是否知道需要跟踪的键/值对的最大数量?
  2. 是否所有类型的值都相同?
  3. 这需要多快?
  4. 如果对1和2的答案为“是”,则可以非常直接。当对3的答案“无关紧要”,或者当最大对数不是太高时,我使用数组或动态分配的内存块作为数组。

    在此方案中,有两个数组:   - 索引数组(不是键)   - 包含键名和值

    的键/值对结构数组

    您还有一个跟踪键/值列表的结构,该列表包含(最低限度)指向索引和键/值结构数组的指针,当前定义的键/值对的数量以及键/值对的最大数量可以存储。

    最初,键/值对的数量为0,索引数组中的每个数组元素都包含一个初始值(可以为零,但通常表示它未被使用,如-1),并且所有键/值对结构数组的元素被清零(没有名称,没有值)。

    维护索引数组,以便索引值以正确的顺序引用另一个数组中的键/值对结构。插入和删除不会移动任何现有的对结构,只会移动索引。删除键/值对时,将包含它的结构清零。

    当使用“qsort()”或其兄弟时,您的比较函数使用索引数组中的索引来访问相应键/值对的名称,并且您的交换函数交换索引数组中的索引值。插入执行重叠的就地复制(从结束到插入点)以将新键之后的键的索引拖放到索引数组中的一个位置,并且删除执行类似的向上移动以关闭删除的间隙关键是。

    稍微快一点的版本,不再使用内存进行存储,使用C联合允许前向链索引存储在未使用的键/值对元素中,初始化将它们与“下一个免费”索引链接在一起在列表上下文中。这可以防止在插入新对时必须在列表中搜索空闲元素。当您需要一个空闲的键/值对对象时,使用存储在“next free”中的索引作为新元素,并将“next free”设置为刚刚声明的自由对象中的存储链索引。丢弃一对时,只需将“next free”值复制到释放对象的链索引中,并将释放对象的索引设置为“next free”的新值。

    索引数组也可以使用指向存储器中的键/值结构的指针来实现。在这种情况下,自由对象列表中的“下一个空闲”和链接链接也成为指针。

    上述方案适用于小键/值集大小和简单值类型。

答案 2 :(得分:1)

正如Baltasarq所说,C没有用于此目的的数据结构。但是,您可以使用基于struct的实现,该实现必须支持:初始化,获取,添加和删除操作。提出了一些好的设计here

答案 3 :(得分:0)

一种非常快速且内存有效的方法是使用Judy数组。 只要你不害怕指针,它就很容易使用。

http://judy.sourceforge.net/

根据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