我正在努力实现一个快速排序功能来对单个链接列表进行排序。我必须使用什么算法才能完成此任务?对于链表,每次比较都需要最坏的情况O(N),而不是通常的数组O(1)。那么最坏的情况复杂性是什么呢?
总而言之,我需要对quicksort算法进行哪些修改以获得最佳排序算法以及算法的最坏情况复杂度?
谢谢!
我在下面有一个实现:
public static SingleLinkedList quickSort(SingleLinkedList list, SLNode first, SLNode last)
{
if (first != null && last != null)
{
SLNode p = partition(list, first, last) ;
quickSort(list,first,p) ;
quickSort(list,p.succ, last) ;
}
return list ;
}
public static SLLNode partition(SinlgleLinkedList list, SLNode first, SLNode last)
{
SLNode p = first ;
SLNode ptr = p.succ ;
while (ptr!=null)
{
if (ptr.data.compareToIgnoreCase(p.data)<0)
{
String pivot = p.data ;
p.data = ptr.data ;
ptr.data = p.succ.data ;
p.succ.data = pivot ;
p = p.succ ;
}
ptr = ptr.succ ;
}
return p ;
}
答案 0 :(得分:4)
对链接列表实现Mergesort更自然,但 可以非常好地进行快速排序。下面是我在几个应用程序中使用过的一个。
这是一个常见的神话,你不能有效地使用列表进行Quicksort。虽然需要仔细实施,但事实并非如此。
要回答您的问题,列表的Quicksort算法与数组基本相同。选择一个数据透视表(下面的代码使用列表的头部),分成两个关于数据透视表的列表,然后递归地对这些列表进行排序,并在中间附加数据结果。有一点不显而易见的是,如果为列表添加一个参数,并且在排序结果的尾部按原样添加参数,则可以在列表上没有额外传递的情况下完成追加操作。在基本情况下,附加此列表不需要任何工作。
事实证明,如果比较便宜,mergesort往往运行得更快,因为quicksort花费更多的时间摆弄指针。但是,如果比较费用昂贵,那么快速排序通常会运行得更快,因为它需要的更少。
如果NODE *list
是初始列表的头部,那么您可以使用
qs(list, NULL, &list);
这是排序代码。请注意,它的一大块是已排序列表的优化。如果这些情况很少发生,可以删除此优化。
void qs(NODE * hd, NODE * tl, NODE ** rtn)
{
int nlo, nhi;
NODE *lo, *hi, *q, *p;
/* Invariant: Return head sorted with `tl' appended. */
while (hd != NULL) {
nlo = nhi = 0;
lo = hi = NULL;
q = hd;
p = hd->next;
/* Start optimization for O(n) behavior on sorted and reverse-of-sorted lists */
while (p != NULL && LEQ(p, hd)) {
hd->next = hi;
hi = hd;
++nhi;
hd = p;
p = p->next;
}
/* If entire list was ascending, we're done. */
if (p == NULL) {
*rtn = hd;
hd->next = hi;
q->next = tl;
return;
}
/* End optimization. Can be deleted if desired. */
/* Partition and count sizes. */
while (p != NULL) {
q = p->next;
if (LEQ(p, hd)) {
p->next = lo;
lo = p;
++nlo;
} else {
p->next = hi;
hi = p;
++nhi;
}
p = q;
}
/* Recur to establish invariant for sublists of hd,
choosing shortest list first to limit stack. */
if (nlo < nhi) {
qs(lo, hd, rtn);
rtn = &hd->next;
hd = hi; /* Eliminated tail-recursive call. */
} else {
qs(hi, tl, &hd->next);
tl = hd;
hd = lo; /* Eliminated tail-recursive call. */
}
}
/* Base case of recurrence. Invariant is easy here. */
*rtn = tl;
}
答案 1 :(得分:1)
您可以使用quicksort并且不会丢失O(n * log(n))预期行为。诀窍很简单 - 将节点放入数组,对节点数组进行排序,以正确的顺序重新链接它们。
答案 2 :(得分:1)
这是一个java实现。它使用头部作为枢轴。这可以通过在附加右子列表之前避免扫描左子列表来进一步改进,但是它可以工作。这也是O(nLogn)。
public class QuickSortLinkedList {
public ListNode sortList(ListNode head) {
//Base Case
if(head == null || head.next == null)
return head;
//Partition Strategy
//Chose first element as pivot and move all elements smaller than the pivot at the end of LL
//So the order will be pivot, elements smaller than or equal to pivot, elements larger than pivot
//Example: 9,13,10,6,9,8,11 => 9,13,10,9,11,6,8 and the method will return a pointer to 11
ListNode partitionedElement = partition(head);
//The elements to the right of pivot were all smaller than pivot after partioned
//Example: LeftPartition = 6->8->null
ListNode leftPartition = partitionedElement.next;
//The elements to the left of pivot were all large , so they go in right partition
//Example: rightPartition = 9->13->10->9->11->null
ListNode rightPartition = head;
partitionedElement.next = null;
//But there can be edge cases
//Example: 3,5,3,4,5-null => after partition , list is unchanged and last element 5 is returned
//in this case leftPartition: 3->null and rightPartition 5,3,4,5-null
if(leftPartition == null){
leftPartition = head;
rightPartition = head.next;
head.next =null;
}
//Now Recursively sort
rightPartition = sortList(rightPartition);
leftPartition = sortList(leftPartition);
//After sorting append rightPartition to leftPartition
ListNode iterator = leftPartition;
while(iterator.next!=null)
iterator = iterator.next;
iterator.next = rightPartition;
return leftPartition;
}
private ListNode partition(ListNode head){
//Base case
if(head.next.next == null){
if(head.next.val>head.val)
return head.next;
else
return head;
}
else{
ListNode i = head.next;
ListNode pivot = head;
ListNode lastElementSwapped = (pivot.next.val>=pivot.val)?pivot.next:pivot;
while(i!=null && i.next !=null){
if(i.next.val >= pivot.val){
if(i.next == lastElementSwapped.next){
lastElementSwapped = lastElementSwapped.next;
}
else{
ListNode temp = lastElementSwapped.next;
lastElementSwapped.next = i.next;
i.next = i.next.next;
lastElementSwapped = lastElementSwapped.next;
lastElementSwapped.next = temp;
}
}
i = i.next;
}
return lastElementSwapped;
}
}
}