【发布时间】:2020-09-18 04:21:06
【问题描述】:
在一个双向链表的实现中,我使用了典型的结构:
struct node
{
void *data;
struct node *prev;
struct node *next;
};
我还将在 O(1) 时间内插入列表末尾,因此我还有另一个 struct 存储 head 和 tail:
struct linklist
{
struct node *head;
struct node *tail;
size_t size;
};
该程序对所有插入和删除操作都按预期工作,但我的排序功能有问题,我正在使用合并排序算法,据我了解它是最有效或最有效的排序算法之一列表,算法运行良好:
static struct node *split(struct node *head)
{
struct node *fast = head;
struct node *slow = head;
while ((fast->next != NULL) && (fast->next->next != NULL))
{
fast = fast->next->next;
slow = slow->next;
}
struct node *temp = slow->next;
slow->next = NULL;
return temp;
}
static struct node *merge(struct node *first, struct node *second, int (*comp)(const void *, const void *))
{
if (first == NULL)
{
return second;
}
if (second == NULL)
{
return first;
}
if (comp(first->data, second->data) < 0)
{
first->next = merge(first->next, second, comp);
first->next->prev = first;
first->prev = NULL;
return first;
}
else
{
second->next = merge(first, second->next, comp);
second->next->prev = second;
second->prev = NULL;
return second;
}
}
static struct node *merge_sort(struct node *head, int (*comp)(const void *, const void *))
{
if ((head == NULL) || (head->next == NULL))
{
return head;
}
struct node *second = split(head);
head = merge_sort(head, comp);
second = merge_sort(second, comp);
return merge(head, second, comp);
}
但我不知道如何更新list->tail 的地址:
void linklist_sort(struct linklist *list, int (*comp)(const void *, const void *))
{
list->head = merge_sort(list->head, comp);
// list->tail is no longer valid at this point
}
当然我可以在订购后浏览整个列表并通过蛮力更新list->tail,但我想知道是否有更好的方法来做到这一点。
我设法使用循环列表解决了这个问题,但我想避免改变程序的结构。
【问题讨论】:
-
合并排序的工作原理是拆分列表,但在保持顺序的同时将所有术语分配给同一侧,然后您换边并开始将术语分配给另一侧。然后合并两边,重复直到将列表拆分为一个列表。但是在这里,您将每个节点分配给不同的一侧...您正在扰乱列表...根本没有排序...您在合并阶段所做的所有排序在拆分部分都被破坏了。
标签: c linked-list mergesort