使用 GLib 列表

GLib 提供了几种用于存储数据集合的容器类型:GListGSListGPtrArrayGArray

过去,在所有需要存储数据序列或集合的情况下,使用 GList 是一种常见的做法。 这样做是不明智的:在大多数情况下,您应该始终优先使用 GPtrArrayGPtrArray 具有更低的内存开销(相当于列表的三分之一到一半),更好的缓存局部性,以及所有常见操作的相同或更低的算法复杂度。 只有在处理有序数据时,GList 才可能更合适,而这些数据需要在数组的任意索引处进行代价高昂的插入。 但是,如果您的有序数据集很大,您可能需要使用 GSequence,它是一种更高效的数据存储。

如果使用链表,请务必保持其操作的复杂度较低,使用标准的计算机科学复杂度分析。 任何使用 g_list_nth()g_list_nth_data() 的操作几乎肯定是不正确的。

例如,对 GList 进行迭代应该使用链接指针来实现,而不是递增索引

// some_list is a GList defined elsewhere
for (GList *l = some_list; l != NULL; l = l->next)
  {
    YourDataType *element_data = l->data;

    // Do something with @element_data
  }

使用递增索引会导致性能二次方下降(O(N²) 而不是 O(N))

// some_list is a GList defined elsewhere

// g_list_length() will iterate the list to determine its length
for (guint i = 0; i < g_list_length (some_list); i++)
  {
    // g_list_nth_data() will iterate the list to retrieve the data
    YourDataType *element_data = g_list_nth_data (some_list, i);

    // Do something with @element_data
  }

上述代码中的性能损失来自 g_list_length()g_list_nth_data(),它们都遍历列表以执行其操作。

使用 GPtrArray 实现上述内容与第一个(正确)GList 示例具有相同的复杂度,但具有更好的缓存局部性和更低的内存消耗,因此对于大量元素,性能会更好

// some_array is a GPtrArray defined elsewhere
for (guint i = 0; i < some_array->len; i++)
  {
    YourDataType *element_data = g_ptr_array_index (some_array, i);

    // Do something with @element_data
  }