如何防止递归快速排序算法中的堆栈溢出

时间:2019-05-07 19:01:49

标签: c# class recursion quicksort doubly-linked-list

当处理大小大于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);
            }
        }

1 个答案:

答案 0 :(得分:0)

为防止堆栈溢出,请创建两个计数器,它们的名称分别为left_counter和right_counter。在分区步骤中,更新计数器,以使left_counter =从第一个到透视图或ivot.prev的节点数,而right_counter是从第一个透视图或pivot.next到最后一个节点的数。比较两个计数器,并在对应于较小计数的子列表上使用递归。然后根据要排序的部分(通过递归)更新first = pivot.next或last = pivot.prev,然后循环回到代码顶部以继续。


在排序过程中,创建循环的双向链接列表可能会更简单,因此first.prev指向最后一个节点,last.next指向第一个节点。这样一来,在交换第一个或最后一个节点或附近的节点时,不必检查是否为空。

该代码显示使用名为List的类类型,但通常是C#的本机类,具有对“列表”中的元素进行索引(随机访问)的能力,类似于数组。列表类可能应使用其他名称,双向链接列表应使用“ DLList”。