单链表上的递归快速排序的基本情况

时间:2011-03-31 01:50:48

标签: java algorithm list recursion quicksort

我正试图在单链表上绕过一个递归的快速排序。什么是基本情况,当我到达它以便函数“倒带”并打印排序列表时我需要做什么?这是一些代码,但我认为这是非常错误的......

public static void qSort(SLLNode first, SLLNode last)
{
    SLLNode pivot = first ;
    SLLNode head = pivot.succ ;
    if (first!=last)
    {   
        while (head!=null)
        {
            if (head.data.compareToIgnoreCase(pivot.data)<0)
            {
                pivot.succ = head.succ ;
                head.succ = first ;
                first = head ;
                qSort(first, pivot) ;
                qSort(head, last) ;
            }
            qSort(first, pivot) ;
            qSort(head, last) ;
            }
        }
}

重新解释我的问题:当我到达基本案例first==last时,我需要做什么?如何使递归倒回并生成排序列表?

这是我更新的代码:

public static void qSort(SLLNode first, SLLNode last)
    {
        if (first==last)
        {
            return ;
        }
        SLLNode pivot = first ;
        SLLNode head = pivot.succ ;

        while (head!=null)
        {
            if (head.data.compareToIgnoreCase(pivot.data)<0)
            {
                pivot.succ = head.succ ;
                head.succ = first ;
                first = head ;
                qSort(first, pivot) ;
                qSort(head, last) ;
            }
            qSort(first, pivot) ;
            qSort(head, last) ;
        }
    }

5 个答案:

答案 0 :(得分:2)

一般

有关快速排序的一般性评论,您应该查看quick-sort algorithm on Wikipedia。简而言之,如果您使用partition辅助函数将列表置于一个状态,其中所有小于您的轴点的状态位于其左侧,并且大于枢轴点的所有内容都位于其右侧,则会更容易。然后,您可以使用数据透视表的两侧递归调用快速排序。

EJP也有一个非常好的观点。我没有在链表上看到快速排序。

让我们无论如何

我看到使用链表快速排序的方式,算法类似于

def qsort(head, tail)
    if head == tail
        return
    pivot = tail
    current = head
    while current != pivot
        if current.value < pivot.value
            move/prepend current to head of the list
        else
            move/append current to tail of the list
        current = current.next
    qsort(head, pivot-1)
    qsort(pivot, tail)

这有点棘手,因为你必须跟踪pivot - 1,这对于单链表来说并不是很自然。而且,上述算法并不真正考虑相同的元素。但一般的想法是,你最终会得到比pivot更少的东西,以及比它更大的所有东西,然后再为双方再次呼叫qsort

您的代码

让我们通过一个简单的案例来运行你的程序。

A->B->C->D
F        L

是我们的开始。

SLLNode pivot = first ;
SLLNode head = pivot.succ ;

给我们

A->B->C->D
F  H     L
P  

假设if (head.data.compareToIgnoreCase(pivot.data)<0)对于给定列表当前状态的每个元素都是真的。

所以我们输入if语句,然后执行

pivot.succ = head.succ ;

A->C->D  B->C
F     L  H
P

head.succ = first ;

B->A->C->D
H  F     L
   P 

first = head ;

B->A->C->D
H  P     L
F 

这给了我们

A->B->C->D
F  H     L
P

B->A->C->D  
H  P     L
F

如果我有这个权利,那么请致电

qSort(head, last);

应该可能是

qSort(pivot, last);

因此,您不会再次在整个列表中调用qSort。在递归调用qSort之前,似乎您可能希望继续浏览列表,直到小于枢轴的所有内容都在其左侧。

答案 1 :(得分:2)

调查Quicksort链接列表是一件有用的事情。在研究任何算法时,了解绝对必要的内容非常重要。

在这种情况下,人们发现不需要随机访问迭代器。事实上,前向迭代器就足够了。 Stepanov与STL合作的很多工作就是提炼出这些信息。

这是C ++中的一个简单实现。抱歉改变了语言。 我只是交换数据而不是节点指针。做后者与Quicksort无关。

是的,我知道我选择的枢轴元素会导致问题。 可以在第一个和最后一个之间找到距离d,然后在[0,d)范围内选择一个随机数x。现在将指针初始化为前x次,并将其数据与第一个指向的数据交换。

struct Node
{
    Node(int d) : data(d), next(0) {}
    ~Node() { delete next; }
    Node* next;
    int data;
};

void Quicksort(Node* first, Node* last)
{
    if (first == last)
    {
        return;
    }

    Node* pivot = first;
    Node* boundary = first;
    for (Node* it = first->next; it != last; it = it->next)
    {
        // Invariant:
        // The iterators in the range [first, boundary->next) 
        // point to nodes with data less than the pivot
        // element's.
        // The iterators in the range [boundary->next, it) 
        // point to nodes with data greater or equal to 
        // the pivot element's.

        if (it->data < pivot->data)
        {
            // Swap the data to maintain the invariant
            boundary = boundary->next;
            std::swap(it->data, boundary->data);
        }
    }

    // Put the pivot data in its right place
    std::swap(pivot->data, boundary->data);

    Quicksort(first, boundary);
    Quicksort(boundary->next, last);
}

初始通话类似于

Quicksort(head, 0);

答案 2 :(得分:1)

基本案例是一个包含0或1个元素的列表。

答案 3 :(得分:1)

你不需要“倒带”。当您进行递归调用时,它会在调用完成时返回到递归堆栈。

if(first==last) return;

答案 4 :(得分:1)

从概念上讲,请注意在first==last的基本情况下,您有一个元素的链接列表,因此它已经排序。

我认为您的算法可能略有偏差?你想要一个循环,将所有小于枢轴的东西移动到前半部分,并且一切都更大到下半部分。然后(循环结束后!)你可以递归地对两半进行排序。我看到你的做法有点不同,但我不相信它是对的......

最后,正如其他人所说,对链表进行排序不是一项非常有用的任务。你不会用自行车拖车......