我的任务是读取文件并对其进行排序,所有这些都使用单链表。我实现了合并排序,但是测试系统说大文件太慢了。我该如何优化呢?
void merge_sort(list *a, list *tmp, int n) {
int k, i, rcount;
list *cursor, *l, *r, *end;
k = n/2;
if(n == 1) {
return;
}
l = a;
end = list_get(a, k);
r = end;
merge_sort(a, tmp, k);
merge_sort(r, tmp, n - k);
rcount = k;
for(cursor = tmp, i = 0; i < n; cursor = cursor->next, i++) {
if((l != end) && (((rcount == n) || (strcmp(l->value, r->value) < 0)))) {
cursor->value = l->value;
l = l->next;
} else {
cursor->value = r->value;
r = r->next;
rcount++;
}
}
for(cursor = tmp, i = 0; i < n; cursor = cursor->next, a = a -> next, i++) {
a->value = cursor->value;
}
return;
}
答案 0 :(得分:3)
我假设要求是对列表进行排序,而不是对节点内的数据进行排序(这可以通过创建指向节点的指针数组并通过指针数组使用合并/快速排序来重新排列节点内的数据。)
使用自顶向下合并/快速排序对链表来说不是一个好方法,因为所有扫描都是为了模拟随机访问迭代器来递归拆分列表。
自下而上的方法要快得多。你可以使用4个指向节点的指针作为指向4个列表的指针,并实现类似磁带排序的东西,但这需要使用计数器来跟踪每个列表中运行的逻辑结束。维基文章:
http://en.wikipedia.org/wiki/Merge_sort#Use_with_tape_drives
使用小型(26到32)指针数组仍然更简单,更快捷。这是HP / Microsoft标准模板库中用于对列表进行排序的算法。维基文章:
http://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation_using_lists
示例代码。在我的系统上,英特尔2600K 3.4ghz,它可以在大约一秒钟内将伪随机32位无符号整数的400万个节点排序为数据。
/* prototype */
NODE * MergeLists(NODE *pSrc1, NODE *pSrc2);
/* sort list using array of pointers to first nodes of list */
/* aList[i] = NULL or ptr to list with 2 to the power i nodes */
#define NUMLISTS 32 /* size of array */
NODE * SortList(NODE *pList)
{
NODE * aList[NUMLISTS]; /* array of lists */
NODE * pNode;
NODE * pNext;
int i;
if(pList == NULL) /* check for empty list */
return NULL;
for(i = 0; i < NUMLISTS; i++) /* zero array */
aList[i] = NULL;
pNode = pList; /* merge nodes into array */
while(pNode != NULL){
pNext = pNode->next;
pNode->next = NULL;
for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
pNode = MergeLists(aList[i], pNode);
aList[i] = NULL;
}
if(i == NUMLISTS) /* don't go past end of array */
i--;
aList[i] = pNode;
pNode = pNext;
}
pNode = NULL; /* merge array into one list */
for(i = 0; i < NUMLISTS; i++)
pNode = MergeLists(aList[i], pNode);
return pNode;
}
/* mergelists - compare uses src2 < src1 */
/* instead of src1 <= src2 to be similar to C++ STL */
NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
if(pSrc1 == NULL)
return pSrc2;
if(pSrc2 == NULL)
return pSrc1;
while(1){
if(pSrc2->data < pSrc1->data){ /* if src2 < src1 */
*ppDst = pSrc2;
pSrc2 = *(ppDst = &(pSrc2->next));
if(pSrc2 == NULL){
*ppDst = pSrc1;
break;
}
} else { /* src1 <= src2 */
*ppDst = pSrc1;
pSrc1 = *(ppDst = &(pSrc1->next));
if(pSrc1 == NULL){
*ppDst = pSrc2;
break;
}
}
}
return pDst;
}