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

发布于 2024-10-28 04:39:45 字数 1391 浏览 1 评论 0原文

我正在尝试在单链表上进行递归快速排序。基本情况是什么?当我到达它时我需要做什么才能让函数“倒回”并打印排序列表?这是一些代码,但我认为这是非常错误的......

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) ;
        }
    }

I'm trying to get my head around a recursive quicksort on a singly linked list. What is the base case, and what do I need to do when I reach it in order for the function to 'rewind' and print a sorted list? Here is some code, but I think it's desperately wrong...

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) ;
            }
        }
}

To rephrase my question: When I reach the base case first==last, what do I need to do? How can I make the recursion rewind and produce the sorted list?

Here's my updated code:

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) ;
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

╄→承喏 2024-11-04 04:39:45

一般来说,

对于快速排序的一般回顾,您可能应该回顾一下 快速排序-维基百科上的排序算法。简而言之,如果您使用 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) 为 true。

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

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

如果我有这个权利,那么对 Should 的调用

qSort(head, last);

可能会是

qSort(pivot, last);

所以你不会在整个过程中调用 qSort再次列出。似乎您可能想继续浏览列表,直到小于枢轴的所有内容都位于列表的左侧,然后再递归调用 qSort。

In General

For a general review on quick-sort, you should probably review the quick-sort algorithm on Wikipedia. In short, it's easier if you use a partition helper function to get your list into a state where everything less than your pivot point is to the left of it, and everything greater than the pivot point is to the right of it. You then call quick-sort recursively with both sides of the pivot.

EJP also has a very good point. I haven't seen quick-sort on a linked list.

Let's Do It Anyway

The way I see a quick-sort with a linked-list, the algorithm would be something like

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)

It gets a little tricky because you have to keep track of pivot - 1, which isn't very natural to do with a singly linked list. Also, the above algorithm doesn't really account for elements that are equal. But the general idea is that you end up with everything less than pivot being before it, and everything greater than it being after, and then you call qsort again for both sides.

Your Code

Let's run through your program with a simple case.

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

Is our start.

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

Gives us

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

Let's say if (head.data.compareToIgnoreCase(pivot.data)<0) is true for each element given the current state of the list.

So we enter the if statement, and do

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 

This gives us

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

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

If I have that right, then the call to

qSort(head, last);

Should probably instead be

qSort(pivot, last);

So you're not calling qSort over the whole list again. It also seems like you might want to instead keep going through your list until everything that is less than the pivot is to the left of it, before recursively calling qSort.

一绘本一梦想 2024-11-04 04:39:45

研究链表的快速排序是一件有用的事情。在研究任何算法时,重要的是要了解绝对需要什么。

在这种情况下,人们发现不需要随机访问迭代器。事实上,前向迭代器就足够了。
Stepanov 在 STL 中的大量工作就是提取此类信息。

这是一个简单的 C++ 实现。抱歉更改语言。
我只是交换数据而不是节点指针。后者与快速排序无关。

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

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);

Investigating Quicksort for a linked list is a useful thing. In studying any algorithm it is important to understand what is absolutely required.

In the case here one discovers that random access iterators are not required. Indeed forward iterators are sufficient.
A lot of Stepanov's work with the STL was to distill such information.

Here is a simple implementation in C++. Sorry for the change of language.
I'm just swapping data instead of node pointers. Doing the latter has nothing to do with Quicksort.

And yes, I know my choice of pivot element can cause problems.
One could find the distance, d, between first and last and then pick a random number x in the range [0, d). Now advance a pointer initialized to first x times, and swap its data with the data pointed to by first.

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);
}

The initial call would be something like

Quicksort(head, 0);
醉生梦死 2024-11-04 04:39:45

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

The base case is a list with 0 or 1 elements.

稚然 2024-11-04 04:39:45

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

如果(第一个==最后一个)返回;

You don't need to "rewind." When you make a recursive call, it goes back up the recursion stack when the call finishes.

if(first==last) return;

无可置疑 2024-11-04 04:39:45

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

我认为你的算法可能略有偏差?您需要一个循环,将小于枢轴的所有内容移动到上半部分,将大于枢轴的所有内容移动到下半部分。然后(循环完成后!)您可以递归地对两半进行排序。我发现你的做法有点不同,但我不相信这是正确的......

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

Conceptually, note that in a base case where first==last, you have a linked list of one element and thus it is already sorted.

I think your algorithm may be slightly off?. You want a loop that moves everything less than the pivot to the first half, and everything greater to the second half. Then (after the loop is done!) you can recursively sort the halves. I see that yours is doing it a little differently, but I'm not convinced it's right....

Finally, as stated by others, sorting a linked list is not a very useful task. You wouldn't use a bike to tow a trailer....

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文