我正试图在单链表上绕过一个递归的快速排序。什么是基本情况,当我到达它以便函数“倒带”并打印排序列表时我需要做什么?这是一些代码,但我认为这是非常错误的......
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) ;
}
}
答案 0 :(得分:2)
有关快速排序的一般性评论,您应该查看quick-sort algorithm on Wikipedia。简而言之,如果您使用partition
辅助函数将列表置于一个状态,其中所有小于您的轴点的状态位于其左侧,并且大于枢轴点的所有内容都位于其右侧,则会更容易。然后,您可以使用数据透视表的两侧递归调用快速排序。
我看到使用链表快速排序的方式,算法类似于
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
的基本情况下,您有一个元素的链接列表,因此它已经排序。
我认为您的算法可能略有偏差?你想要一个循环,将所有小于枢轴的东西移动到前半部分,并且一切都更大到下半部分。然后(循环结束后!)你可以递归地对两半进行排序。我看到你的做法有点不同,但我不相信它是对的......
最后,正如其他人所说,对链表进行排序不是一项非常有用的任务。你不会用自行车拖车......