合并排序链接列表
时间:2020-03-05 18:38:56 来源:igfitidea点击:
我最近重新研究了一些基本知识,发现合并对链表进行排序是一个非常好的挑战。如果我们有一个好的实现,那么请在此处展示它。
解决方案
回答
我们可以使用合并排序的实现,并编写自己的函数以与链表进行交互,就好像它是数组一样。
回答
一种有趣的方法是维护堆栈,仅在堆栈上的列表具有相同数量的元素时才合并,否则将其推入列表,直到耗尽传入列表中的元素,然后合并堆栈。
回答
回答
大量基于以下网址的出色代码:http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
稍微修剪一下,然后整理一下:
typedef struct _aList { struct _aList* next; struct _aList* prev; // Optional. // some data } aList; aList *merge_sort_list(aList *list,int (*compare)(aList *one,aList *two)) { int listSize=1,numMerges,leftSize,rightSize; aList *tail,*left,*right,*next; if (!list || !list->next) return list; // Trivial case do { // For each power of two<=list length numMerges=0,left=list;tail=list=0; // Start at the start while (left) { // Do this list_len/listSize times: numMerges++,right=left,leftSize=0,rightSize=listSize; // Cut list into two halves (but don't overrun) while (right && leftSize<listSize) leftSize++,right=right->next; // Run through the lists appending onto what we have so far. while (leftSize>0 || (rightSize>0 && right)) { // Left empty, take right OR Right empty, take left, OR compare. if (!leftSize) {next=right;right=right->next;rightSize--;} else if (!rightSize || !right) {next=left;left=left->next;leftSize--;} else if (compare(left,right)<0) {next=left;left=left->next;leftSize--;} else {next=right;right=right->next;rightSize--;} // Update pointers to keep track of where we are: if (tail) tail->next=next; else list=next; // Sort prev pointer next->prev=tail; // Optional. tail=next; } // Right is now AFTER the list we just sorted, so start the next sort there. left=right; } // Terminate the list, double the list-sort size. tail->next=0,listSize<<=1; } while (numMerges>1); // If we only did one merge, then we just sorted the whole list. return list; }
注意:这是O(NLog(N))保证的,并且使用O(1)资源(没有递归,没有堆栈,什么也没有)。
回答
一个更简单/更清晰的实现可能是递归实现,从该实现中,NLog(N)的执行时间更加清晰。
typedef struct _aList { struct _aList* next; struct _aList* prev; // Optional. // some data } aList; aList* merge_sort_list_recursive(aList *list,int (*compare)(aList *one,aList *two)) { // Trivial case. if (!list || !list->next) return list; aList *right = list, *temp = list, *last = list, *result = 0, *next = 0, *tail = 0; // Find halfway through the list (by running two pointers, one at twice the speed of the other). while (temp && temp->next) { last = right; right = right->next; temp = temp->next->next; } // Break the list in two. (prev pointers are broken here, but we fix later) last->next = 0; // Recurse on the two smaller lists: list = merge_sort_list_recursive(list, compare); right = merge_sort_list_recursive(right, compare); // Merge: while (list || right) { // Take from empty lists, or compare: if (!right) { next = list; list = list->next; } else if (!list) { next = right; right = right->next; } else if (compare(list, right) < 0) { next = list; list = list->next; } else { next = right; right = right->next; } if (!result) { result=next; } else { tail->next=next; } next->prev = tail; // Optional. tail = next; } return result; }
注意:这具有递归的Log(N)存储要求。效果应该与我发布的其他策略大致相当。通过在while(列表&&右)同时运行merge循环,然后简单地追加剩余列表(由于我们实际上并不关心列表的末尾;知道它们已经足够就可以了),这是一种潜在的优化方法。