在glib库中,双向链表的排序是采用归并排序的方法
代码如下:
主要函数g_list_sort_real中,while循环表示l1每前进一步,l2就前进2步,故最终得到l2指向链表中间的节点。之后调用g_list_sort_merge去合并排序这两个子链表。如果两个子链表点已经排好序,那么直接合并排序。
最核心的合并排序过程代码如下:
此排序过程有点类似于STL中的set容器的set_*算法,所以说,这个过程有个前提就是2个链表l1和l2必须是已经排序的。
代码如下:
GList *
g_list_sort (GList *list,
GCompareFunc compare_func)
{
return g_list_sort_real (list, (GFunc) compare_func, NULL);
}
static GList*
g_list_sort_real (GList *list,
GFunc compare_func,
gpointer user_data)
{
GList *l1, *l2;
if (!list)
return NULL;
if (!list->next)
return list;
l1 = list;
l2 = list->next;
while ((l2 = l2->next) != NULL)
{
if ((l2 = l2->next) == NULL)
break;
l1 = l1->next;
}
l2 = l1->next; // 指向链表中间节点
l1->next = NULL;
return g_list_sort_merge (g_list_sort_real (list, compare_func, user_data),
g_list_sort_real (l2, compare_func, user_data),
compare_func,
user_data);
}
主要函数g_list_sort_real中,while循环表示l1每前进一步,l2就前进2步,故最终得到l2指向链表中间的节点。之后调用g_list_sort_merge去合并排序这两个子链表。如果两个子链表点已经排好序,那么直接合并排序。
最核心的合并排序过程代码如下:
static GList *
g_list_sort_merge (GList *l1,
GList *l2,
GFunc compare_func,
gpointer user_data)
{
GList list, *l, *lprev;
gint cmp;
l = &list;
lprev = NULL;
while (l1 && l2)
{
cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
if (cmp <= 0)
{
l->next = l1;
l1 = l1->next;
}
else
{
l->next = l2;
l2 = l2->next;
}
l = l->next;
l->prev = lprev;
lprev = l;
}
l->next = l1 ? l1 : l2;
l->next->prev = l;
return list.next;
}
此排序过程有点类似于STL中的set容器的set_*算法,所以说,这个过程有个前提就是2个链表l1和l2必须是已经排序的。
细看整个排序过程的代码,其实此算法也可以用于单链表的排序过程(因为它并没有利用prev域)。
如果你阅读过STL源代码的话,STL的std::list用的也是归并排序。它开辟了16个list内存空间,不过采用的是迭代的解法。