C 调试合并排序
我需要对双链接列表进行排序。根据万能的维基百科,合并排序是实现这一目标的方法 递归算法工作得相当好,但在我编写通用实现时,性能可能是一个问题 为数组移植迭代版本会降低性能,因为重新扫描列表以将其划分为子列表的速度很慢;对于任何感兴趣的人-以下是代码:C 调试合并排序,c,debugging,mergesort,C,Debugging,Mergesort,我需要对双链接列表进行排序。根据万能的维基百科,合并排序是实现这一目标的方法 递归算法工作得相当好,但在我编写通用实现时,性能可能是一个问题 为数组移植迭代版本会降低性能,因为重新扫描列表以将其划分为子列表的速度很慢;对于任何感兴趣的人-以下是代码: static void sort(struct linked_list *list, int (*cmp)(const void *, const void *)) { size_t slice_size = 1; for(
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 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;
}
我在这里遗漏了什么?基于堆栈的方法
/* ... */
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);
}
/* ... */
/**/
结构片堆栈[32];
大小\u t top=-1;
结构节点*当前=列表->第一;
对于(;当前;当前=当前->下一步)
{
堆栈[++top]=(结构片){current,1};
对于(;top&&stack[top-1]。大小基于堆栈的方法
/* ... */
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);
}
/* ... */
/**/
结构片堆栈[32];
大小\u t top=-1;
结构节点*当前=列表->第一;
对于(;当前;当前=当前->下一步)
{
堆栈[++top]=(结构片){current,1};
对于(;top&&stack[top-1]。大小是否需要将节点复制到列表的末尾?
那么,insert\u before()
调用是什么
insert_before(node, list, NULL);
这会把list->first
和node->prev
搞得一团糟。您是否需要将节点复制到列表的末尾?
那么,insert\u before()
调用是什么
insert_before(node, list, NULL);
这会把list->first
和node->prev
搞得一团糟,我现在已经运行了你的代码,并在注释掉下面指示的行后让它开始工作
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; /* possible bug? */
/* ^^^^^^^^^^^^^^^^^^^ */
这也适用于您吗?我现在已经运行了您的代码,并在注释掉下面指示的行后使其正常工作
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; /* possible bug? */
/* ^^^^^^^^^^^^^^^^^^^ */
这也适用于您吗?正如Kris所要求的,这里是递归版本(使用其他示例中的merge函数的标准mergesort):
静态结构节点*合并(结构链接列表*列表,
int(*cmp)(常数无效*,常数无效*),
结构节点*左,结构节点*右,大小\u t右\u计数)
{
结构节点*头部;
如果(cmp(左->数据,右->数据)下一步;
}
其他的
{
头部=右侧;
结构节点*节点=右侧;
右=右->下一步;
删除_节点(节点,列表);
在(节点,列表,左侧)之前插入_;
--右u计数;
}
while(左!=右和右计数)
{
如果(cmp(左->数据,右->数据)下一步;
其他的
{
结构节点*节点=右侧;
右=右->下一步;
删除_节点(节点,列表);
在(节点,列表,左侧)之前插入_;
--右u计数;
}
}
回流头;
}
静态结构节点*合并排序(结构链接列表*列表,
int(*cmp)(常量无效*,常量无效*),结构节点*头,大小
{
如果(尺寸<2)返回头;
大小\ t左\计数=大小/2;
大小\u t右\u计数=大小-左\u计数;
结构节点*尾部=头部;
大小计数=左计数;
而(计数--)tail=tail->next;
返回合并(列表、cmp、,
合并排序(列表、cmp、头部、左侧计数),
合并排序(列表、cmp、尾部、右计数),
右(右);;
}
静态无效排序(结构链接列表*列表,
int(*cmp)(常数无效*,常数无效*)
{
合并排序(列表、cmp、列表->第一,列表->大小);
}
正如Kris所要求的,这里是递归版本(使用其他示例中的merge函数的标准mergesort):
静态结构节点*合并(结构链接列表*列表,
int(*cmp)(常数无效*,常数无效*),
结构节点*左,结构节点*右,大小\u t右\u计数)
{
结构节点*头部;
如果(cmp(左->数据,右->数据)下一步;
}
其他的
{
头部=右侧;
结构节点*节点=右侧;
右=右->下一步;
删除_节点(节点,列表);
在(节点,列表,左侧)之前插入_;
--右u计数;
}
while(左!=右和右计数)
{
如果(cmp(左->数据,右->数据)下一步;
其他的
{
结构节点*节点=右侧;
右=右->下一步;
删除_节点(节点,列表);
在(节点,列表,左侧)之前插入_;
--右u计数;
}
}
回流头;
}
静态结构节点*合并排序(结构链接列表*列表,
int(*cmp)(常量无效*,常量无效*),结构节点*头,大小
{
如果(尺寸<2)返回头;
大小\ t左\计数=大小/2;
大小\u t右\u计数=大小-左\u计数;
结构节点*尾部=头部;
大小计数=左计数;
而(计数--)tail=tail->next;
返回合并(列表、cmp、,
合并排序(列表、cmp、头部、左侧计数),
合并排序(列表、cmp、尾部、右计数),
右(右);;
}
静态无效排序(结构链接列表*列表,
int(*cmp)(常数无效*,常数无效*)
{
合并排序(列表、cmp、列表->第一,列表->大小);
}
我自己发现了错误:
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);
}
多亏了pmg的努力:我为此投了一些票。我自己发现了错误:
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);
}
多亏了pmg的努力:我为此增加了一些投票。afaik这是正确的:只有当堆栈上至少有两个列表时,才能向下合并,即在第一次迭代时不合并检查top
是否超过限制:assert(top<(sizeof stack/sizeof stack[0])-1)
afaik这是正确的:只有在堆栈上至少有两个列表时才能向下合并,即在第一次迭代时不合并检查top
是否超出限制:assert(top<(sizeof stack/sizeof stack[0])-1);
我认为这样的调用不会发生-我将在()
为了确保……我认为这样的调用不会发生-我将在insert_before()中添加一些调试输出
为了确保……似乎有效——但我不明白为什么:当我合并前两个列表并丢弃右列表时,左列表的大小不应该增加右列表的大小吗?doesn不起作用:我得到了一个无休止的大输入大小循环;简单的解决方法是添加一个检查