我经常通过索引指针列表对链表进行排序。要构建一个,需要分配相当于节点数 (N) * 节点指针大小的内存。这个概念很简单。
注意:这个算法是用 C 语言编写的,因为我不完全确定 OP 是否打算将其归类为 C++ 问题(谁 hell 使用 C++ 中的链表和你的标准容器处置??)
- 确定列表中的节点数 (N)
- 为N个节点指针分配一个指针数组。
- 用列表中的每个节点指针加载指针数组。 IE。遍历列表,并在指针数组的每个槽中放置一个指针,并随行递增。
- 将此节点指针数组发送到您的排序算法(我喜欢运行时库
qsort(),因为它是标准配备的)。
- 排序后,遍历整个指针数组(少一个),设置每个节点的“下一个”指针指向后面的那个。最后一个将其“next”指针设置为 NULL。
- 将头指针设置为指针数组中的第一个指针[0]。
- 释放指针数组的内存
您的链接列表已排序。
假设你的节点是这样的:
struct node
{
..data fields..
int keyField; // << determines sort order
struct node *next;
};
确定列表中的节点数。我假设你有一个可以做到这一点的 proc,这很简单:
size_t list_count(struct node* head)
{
size_t count = 0;
while (head)
{
++count;
head = head->next;
}
return count;
}
分配一个与列表大小相同的指针数组,其中 nItems 是大于 1 的列表节点计数(与长度为 0 或 1 的列表无关):
struct node **ptrs = malloc(sizeof(*ptrs)*nItems);
用列表中的所有项目填充指针数组:
struct node *ptr = head;
size_t i=0;
for (;i<nItems;++i,ptr = ptr->next)
ptrs[i] = ptr;
现在使用适当的比较功能将其发送至qsort()。下面是一个基于我们结构中的keyField 排序的比较函数示例:
int compare_node_ptrs(const void* left, const void* right)
{
struct node *l = *(struct node**)left;
struct node *r = *(struct node**)right;
return l->keyField - r->keyField;
}
调用 qsort() 看起来像这样:
qsort(ptrs, nItems, sizeof(*ptrs), compare_node_ptrs);
现在遍历整个列表。重新连接“下一个”指针:
for (i=0;i<(nItems-2);++i)
ptrs[i]->next = ptrs[i+1];
ptrs[nItems-1] = NULL;
重新连接头指针。
head = ptrs[0];
最后,释放指针数组。
free(ptrs);
您的链接列表已排序。
Sidebar 合并排序是我所知道的唯一一种 O(nlogn) 算法,它可以对链表进行排序而无需增加空间要求。一个通用的解决方案原型如下:
mergesort_list(void **head, size_t offset_ptr, int(*comp)(void*,void*))
head: address of the head pointer.
offset_ptr: offset in bytes from a node ptr where the 'link' pointer can be found.
comp: comparison function.