哪种数据结构在C中广泛使用?

时间:2011-04-08 11:39:37

标签: c data-structures dynamic

几天前,我问自己在 C 的函数中应该使用哪种数据结构。 我通常用 C ++ 编写,选择将落到std :: vector。

有一些可能的选择:

  • 静态(足够大)数组
  • 动态数组,在需要时增长(例如,将其大小加倍)
  • 一个自己的列表实现,作为结构,带有指针 next

最后一个选项似乎不寻常。有没有更大的项目在哪里 有人使用自己的结构像列表? 数组或自己之间的决定是否有一般规则 数据结构?

当我需要树形结构时,我不会想到只写一棵树。 有没有广泛使用的具有这种结构的库(比如boost for C ++)? 或者这被认为是不好的风格,因为你必须存储一个空*而不是 实际类型?

非常感谢您的体验!

7 个答案:

答案 0 :(得分:6)

不同的数据结构为插入,查找和其他操作提供了不同的计算复杂性。

以您的具体示例为例,数组和链表之间存在许多差异:

  • 按索引查找数组中为O(1),列表中为O(n);
  • 在列表中插入的是O(1)O(n)(取决于它们是否需要遍历),如果做得好,则会在一个数组中分摊O(1);
  • 数组中的删除是O(n),而某些类型的列表删除可以在O(1)时间内完成;
  • 数组提供更好的引用位置,从而提高缓存性能。

您可能会发现以下页面非常有用:http://essays.hexapodia.net/datastructures/

作为一般规则,在选择数据结构时,我首先考虑是否有充分的理由相信相关代码的性能会变得很重要:

  • 如果我不,我选择最简单的数据结构来完成这项工作,或者选择最适合最清晰代码的数据结构;
  • 如果我,我会仔细考虑我将对结构执行哪些操作并相应地进行选择,然后可能会进行分析。

关于优秀C数据结构库的建议,请查看Are there any open source C libraries with common data structures?

答案 1 :(得分:1)

这完全取决于您要对数据结构执行哪些操作。如果您将通过索引检索数据(例如,数据[3]),那么列表是一个可怕的想法,因为每次读取都需要您遍历列表。如果你将大量插入第一个位置(例如,data [0] = x),那么数组将会非常糟糕,因为你将为每次插入移动所有数据。

如果你打算使用std :: vector,那么动态数组可能是最好的替代品。但也许std :: vector不是正确的选择。

答案 2 :(得分:0)

动态链接列表广泛用于C,其中要存储的项目数量未知。

答案 3 :(得分:0)

Vector是一个动态数组,在内部实现为动态数组。我建议您使用向量,因为机器已经过优化以检索连续的内存位置,而链接列表将不会存储在连续的位置。

话虽如此,如果你不需要在你的用例中快速检索索引元素,那么你也可以去链接列表。链接列表也有一个好处,就是不要浪费空间而不像动态数组(通过当它即将充满时加倍)并且与数组相比,在开始时或元素之间插入也更便宜。

答案 4 :(得分:0)

每个人都有自己的优点和缺点。

  • 静态数组:非常适合在整个程序执行过程中不会改变其大小的查找表和数据。它们在程序启动时分配,因此您不必以任何方式管理此内存。缺点是您无法调整大小或释放静态数组 - 它会一直存在,直到程序终止。

  • 动态增长的数组:易于管理的数据结构几乎可以替代C ++中的向量数组。缺点是在运行时分配内存的开销,但如果你一次分配更大的块,这可以减轻。

  • 链接列表:如果要使用大量元素,请注意,因为在不使用内存池的情况下单独分配每个元素会导致内存浪费和碎片化。

答案 5 :(得分:0)

在纯C中我主要使用静态数组。它与嵌入式设备的编程有关,这些嵌入式设备在分配和释放内存方面存在问题 - 堆碎片。

但如果需要使用列表,我自己实现一个 - 有时它的实现基于静态数组(再次)。

我认为C语库可以提供更复杂的数据结构。 AFAIK glib被广泛使用,并至少提供链接列表。

答案 6 :(得分:0)

我记得我前段时间读过苹果公司的一份文件说这样的事情可以天真实施,其结构类似于:

struct {
    void *data; //other type rather than void is easier
    int length;
} MyArray;

MyArray *MyArrayCreate(){
    //mallocate memory
    return ...
}
void MyArrayRelease(){
    free(...);
}

实现一个检查数组长度的函数,它不够长,然后分配另一个足够大的数组,以前的数据将被复制到它并添加新的数据。

MyArrayInsertAt(MyArray *array, index, void *object){
    if (length < index){
        //mallocate again, copy data
        //update length
    }
    data[index] = object;
}

所以它可以这样使用:

MyArray *array = MyArrayCreate();
MyArrayInsertAt(array, 5, something);
MyArrayRelease(array); 

MyArrayInsertAt()函数不会为其性能赢得代价,但它可以成为没有高​​要求程序/应用程序的解决方案

我找不到链接......也许有人也读过这个链接?

增加: 我发现GNU NSMutableArray(Objective-C)方法的实现是在C中完成的,它们的作用与上面相同。每次必须添加一个对象时,它们会使数组的大小加倍,并且不适合数组。见第131至145行