gpt4 book ai didi

c - 调试合并排序

转载 作者:太空宇宙 更新时间:2023-11-04 07:42:59 25 4
gpt4 key购买 nike

我需要对一个双向链表进行排序。根据全能的维基百科,合并排序是实现这一目标的方法。

递归算法工作得相当好,但由于我正在编写通用实现,性能可能是个问题。

移植数组的迭代版本会降低性能,因为重新扫描列表以将其划分为子列表很慢;对于任何感兴趣的人 - 这是代码:

static void sort(struct linked_list *list,
int (*cmp)(const void *, const void *))
{
size_t slice_size = 1;
for(; slice_size < list->size; slice_size *= 2)
{
struct node *tail = list->first;
while(tail)
{
struct node *head = tail;

size_t count = slice_size;
while(tail && count--) // performance killer
tail = tail->next;

count = slice_size;
while(head != tail && tail && count)
{
if(cmp(head->data, tail->data) <= 0)
head = head->next;
else
{
struct node *node = tail;
tail = tail->next;
remove_node(node, list);
insert_before(node, list, head);
--count;
}
}

while(tail && count--) // performance killer
tail = tail->next;
}
}
}

但是还有另一个使用基于堆栈的方法的迭代版本:

struct slice
{
struct node *head;
size_t size;
};

static void sort(struct linked_list *list,
int (*cmp)(const void *, const void *))
{
if(list->size < 2) return;

struct slice stack[32];
size_t top = -1;
struct node *current = list->first;

for(; current; current = current->next)
{
stack[++top] = (struct slice){ current, 1 };
for(; top && stack[top-1].size <= stack[top].size; --top)
merge_down(list, cmp, stack + top);
}

for(; top; --top)
merge_down(list, cmp, stack + top);
}

这会将大小为 1 的列表压入堆栈并向下合并,只要顶部列表的大小大于或等于其前身。

不幸的是,对于某些输入列表,某处存在错误,merge_down() 将无法通过健全性检查:

static void merge_down(struct linked_list *list,
int (*cmp)(const void *, const void *), struct slice *top)
{
struct node *right = top->head;
size_t count = top->size;

--top;

struct node *left = top->head;
top->size += count;

{
// sanity check: count nodes in right list
int i = count;
struct node *node = right;
for(; i--; node = node->next) if(!node)
{
puts("too few right nodes");
exit(0);
}
}

// determine merged list's head
if(cmp(left->data, right->data) <= 0)
{
top->head = left;
left = left->next;
}
else
{
top->head = right;
struct node *node = right;
right = right->next;
remove_node(node, list);
insert_before(node, list, left);
--count;
}

while(left != right && count)
{
if(cmp(left->data, right->data) <= 0)
left = left->next;
else
{
struct node *node = right;
right = right->next;
remove_node(node, list);
insert_before(node, list, left);
--count;
}
}
}

链表实现也可能相关:

struct node
{
struct node *prev;
struct node *next;
long long data[]; // use `long long` for alignment
};

struct linked_list
{
struct _list _list; // ignore
size_t size;
struct node *first;
struct node *last;
};

static void insert_before(struct node *node, struct linked_list *list,
struct node *ref_node)
{
if(ref_node)
{
node->next = ref_node;
node->prev = ref_node->prev;
if(ref_node->prev) ref_node->prev->next = node;
else list->first = node;
ref_node->prev = node;
}
else // empty list
{
node->next = NULL;
node->prev = NULL;
list->first = node;
list->last = node;
}
++list->size;
}

static void remove_node(struct node *node, struct linked_list *list)
{
if(node->prev) node->prev->next = node->next;
else list->first = node->next;
if(node->next) node->next->prev = node->prev;
else list->last = node->prev;
--list->size;
}

我在这里错过了什么?

最佳答案

你是否需要将节点复制到列表的末尾?
那么 insert_before() 调用是什么?

insert_before(node, list, NULL);

那会弄乱 list->firstnode->prev

关于c - 调试合并排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1491688/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com