【发布时间】:2019-09-25 11:49:20
【问题描述】:
在处理大小超过 5000 的双向链表时,出现堆栈溢出错误。我的算法在每次递归后创建双向链表的 2 个新对象,这些对象在每次递归后附加到排序列表中。是否有另一种方法来创建对象,这样我就不必在快速排序的每次递归中都这样做?
static void quick_sort(List sortList, Node first, Node last)
{
//Quick sort algorithm
Node left, pivNode;
List bigList = new List();
List endList = new List();
int pivot;
pivNode = first; //Sets node to become pivot (1st node in given range)
left = first.next; //Sets comparison node
pivot = first.data; //Sets integer for pivot
if (last.next != null)
{
//Creates a new list if there are nodes after last node
endList.firstNode = last.next;
last.next = null;
endList.firstNode.prev = null;
}
if (left != null)
{
do
{
if (left.data > pivot)
{
Node popNode;
popNode = left;
removeNode(popNode, sortList); //Removes node larger than pivot from sortList
left = pivNode; //Resets left node to pivNode
if (bigList.firstNode == null) //Inserts larger node into bigList
{
insertBeginning(popNode, bigList);
}
else
{
popNode.next = popNode.prev = null;
insertEnd(popNode, bigList);
}
}
if (left.data <= pivot)
{
swapNode(left, pivNode); //Swaps smaller node with pivNode(moves smaller nodes to left of list)
pivNode = left; //Resets pivNode to correct node
}
left = left.next;
} while (left != last.next); //Iterates until last given node
}
if (endList.firstNode != null)
{
//If endList exists
if (bigList.firstNode != null)
{
//If bigList exists
appendLists(bigList, endList); //Appends endList at end of bigList
}
else
{
//If bigList doesn't exist, changes it to endList
bigList = endList;
}
}
appendLists(sortList, bigList); //Appends bigList to end of sortList
if (endList.firstNode != null)
{
last = endList.firstNode.prev; //Set's correct last node
}
//Recursion until last has been fully sorted
if (pivNode.prev != first && pivNode != first)
{
quick_sort(sortList, first, pivNode.prev);
}
if (pivNode != last && first != last)
{
quick_sort(sortList, pivNode.next, last);
}
}
【问题讨论】:
-
"如何在我的递归快速排序算法中防止堆栈溢出" 您需要一个停止/退出条件,您的方法决定不再递归调用自身...
-
由于您的代码中已经有一些停止条件(
if语句),显然某些事情并没有按照您的预期进行,从而使停止条件无效。当 *Exception 抛出时,使用debugger 并分析程序的状态(尤其是递归方法中所有变量的值)... -
我已经用较小的列表(最大为 5000)测试了代码,它们都可以正常工作,因为 if 语句最终会导致递归结束。这让我相信问题不在于停止条件。
-
关于您的最后一条评论,可能是如果您有大量元素要排序,那么您的递归可能会变得太深,即调用堆栈耗尽并因此触发 SO 异常.这个问题的解决方案通常是避免这种非常深的递归,这意味着将你的算法转换为迭代算法。 (如果您的教授禁止您使用迭代方法,您将不得不将自己限制为“不太大的列表”,或者增加调用堆栈大小:*.com/questions/2556938/…)
-
在多次递归调用的情况下,递归总是存在导致堆栈溢出的风险(实际限制取决于平台/技术堆栈限制)。这就是为什么许多现代编译器能够将尾递归方法优化为迭代方法并且这种技术被视为足够安全的原因。不幸的是,这不是 C# 编译器的情况,因此您必须处理这样一个事实,即您有发生堆栈溢出的风险,或者您需要重新制作您的方法以使用最接近递归技术并保证堆栈安全的蹦床。跨度>
标签: c# class recursion quicksort doubly-linked-list