|
Packit |
1470ea |
|
|
Packit |
1470ea |
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2003/XInclude" type="topic" id="glist" xml:lang="de">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<link type="guide" xref="index#specific-how-tos"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<credit type="author copyright">
|
|
Packit |
1470ea |
<name>Philip Withnall</name>
|
|
Packit |
1470ea |
<email its:translate="no">philip.withnall@collabora.co.uk</email>
|
|
Packit |
1470ea |
<years>2015</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>Linked lists and container types</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
|
|
Packit |
1470ea |
<mal:name>Mario Blättermann</mal:name>
|
|
Packit |
1470ea |
<mal:email>mario.blaettermann@gmail.com</mal:email>
|
|
Packit |
1470ea |
<mal:years>2016</mal:years>
|
|
Packit |
1470ea |
</mal:credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
|
|
Packit |
1470ea |
<mal:name>Christian Kirbach</mal:name>
|
|
Packit |
1470ea |
<mal:email>christian.kirbach@gmail.com</mal:email>
|
|
Packit |
1470ea |
<mal:years>2016</mal:years>
|
|
Packit |
1470ea |
</mal:credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>GList</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="glist-usage">
|
|
Packit |
1470ea |
<title>Verwendung von GList</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GLib provides several container types for sets of data:
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Doubly-Linked-Lists.html">GList </link>,
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Singly-Linked-Lists.html">GSList </link>,
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Pointer-Arrays.html">GPtrArray </link> and
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Arrays.html">GArray </link>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
It has been common practice in the past to use GList in all situations
|
|
Packit |
1470ea |
where a sequence or set of data needs to be stored. This is inadvisable —
|
|
Packit |
1470ea |
in most situations, a GPtrArray should be used instead. It has lower
|
|
Packit |
1470ea |
memory overhead (a third to a half of an equivalent list), better cache
|
|
Packit |
1470ea |
locality, and the same or lower algorithmic complexity for all common
|
|
Packit |
1470ea |
operations. The only typical situation where a GList may be more
|
|
Packit |
1470ea |
appropriate is when dealing with ordered data, which requires expensive
|
|
Packit |
1470ea |
insertions at arbitrary indexes in the array.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
If linked lists are used, be careful to keep the complexity of operations
|
|
Packit |
1470ea |
on them low, using standard CS complexity analysis. Any operation which
|
|
Packit |
1470ea |
uses
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/2.30/glib-Doubly-Linked-Lists.html#g-list-nth">g_list_nth() </link> or
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/2.30/glib-Doubly-Linked-Lists.html#g-list-nth-data">g_list_nth_data() </link>
|
|
Packit |
1470ea |
is almost certainly wrong. For example, iteration over a GList should be
|
|
Packit |
1470ea |
implemented using the linking pointers, rather than a incrementing index:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GList *some_list, *l;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
for (l = some_list; l != NULL; l = l->next)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
gpointer element_data = l->data;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Do something with @element_data. */
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Using an incrementing index instead results in a quadratic decrease in
|
|
Packit |
1470ea |
performance (O(N^2) rather than O(N)):
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GList *some_list;
|
|
Packit |
1470ea |
guint i;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* This code is inefficient and should not be used in production. */
|
|
Packit |
1470ea |
for (i = 0; i < g_list_length (some_list); i++)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
gpointer element_data = g_list_nth_data (some_list, i);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Do something with @element_data. */
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The performance penalty comes from g_list_length() and
|
|
Packit |
1470ea |
g_list_nth_data() which both traverse the list
|
|
Packit |
1470ea |
(O(N)) to perform their operations.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Implementing the above with a GPtrArray has the same complexity as the
|
|
Packit |
1470ea |
first (correct) GList implementation, but better cache locality and lower
|
|
Packit |
1470ea |
memory consumption, so will perform better for large numbers of elements:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GPtrArray *some_array;
|
|
Packit |
1470ea |
guint i;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
for (i = 0; i < some_array->len; i++)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
gpointer element_data = some_array->pdata[i];
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Do something with @element_data. */
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</page>
|