QuickSort程序达到最大递归限制500?

时间:2017-08-16 10:59:29

标签: algorithm matlab sorting recursion quicksort

我正在通过在MATLAB中绘制图表来分析排序算法。下面是我的快速排序代码。当我运行它时会出现此错误:

  

达到500的最大递归限制。使用set(0,'RecursionLimit', N)   改变限制。请注意,超出可用的堆栈空间   可能会崩溃MATLAB和/或您的计算机。 ==>中的错误快速排序

为什么会出现此错误?我的代码有什么问题吗?

function [ar] = quickSort(ar, low, high)
    if low < high
        [ar, q] = parti(ar, low, high);
        ar = quickSort(ar, low, q - 1);
        ar = quickSort(ar, q + 1, high);
    end
end

function [ar, i] = parti(ar, p, r)
    x = ar(r);
    i = p - 1;

    for j = p : r
        if ar(j) <= x
            i = i + 1;
            if i ~= j
                tmp = ar(i);
                ar(i) = ar(j);
                ar(j) = tmp;
            end
        end
    end
    i = i + 1;
    tmp = ar(i);
    ar(i) = ar(r);
    ar(r) = tmp;
end

我正在使用

调用此函数
ar = [7,7,3,0,3,1,4,7,5,6]
quickSort(ar, 1, 10)

2 个答案:

答案 0 :(得分:3)

在函数parti中,要根据数据透视对数组进行分区,在尝试确定数据的正确位置时,包括数据透视本身

在某些情况下,这会带来无限递归,因为枢轴只是在相邻位置之间交换,因为与自身进行比较

两种解决方案:

解决方案1:

function [ar,i]= parti(ar,p,r)
    x=ar(r);
    i=p-1;

    for j=p:r-1 % Notice the r-1
        if ar(j) <= x
            i=i+1;
            if i~=j
    % ...

解决方案2:

function [ar,i]= parti(ar,p,r)
    x=ar(r);
    i=p-1;

    for j=p:r
        if ar(j) < x % Notice the change in checking
            i=i+1;
            if i~=j
    % ...

答案 1 :(得分:0)

我已经深入探讨了如何优化MATLAB的使用,如何更好地利用递归函数和重新编写代码。 要跳到quicksort函数的工作重定向,请参阅下面的 nd 和4 th 代码块

在您的功能中,您使用lowhigh索引来跟踪您的分区并没有帮助。使用递归快速排序功能的重点是:

  1. 从数组ar(p)
  2. 中选择一个数据透视表元素ar
  3. 拆分为2个数组,其中一个数值小于ar(p),另一个数值大于ar(p)。等值可以在任一阵列中,因为它们将保留在枢轴旁边。
  4. 返回步骤1.每个列表,重复。
  5. 列表是自相似的,我的意思是将每个子列表视为自己需要排序的列表,而不是更大列表的一部分!您不需要跟踪索引(当您进行3次递归时最终会引起混淆),只需自己分析每个列表。

    您可能会发现Wikipedia article很有用,因为它详细说明了这3点,并建议了一些最佳选择枢轴的方案。在下面的代码中,我只选择中间元素。

    此外,您的分区函数parti 确实效率低下。在MATLAB中,如果你发现自己循环遍历数组的每个索引,那么你可能会加快速度。相反,使用逻辑索引来向量化代码!

    至少,在documentation中学习更多关于索引的知识,因为你可以做这样的好事:

    % Your code for swapping array elements
    tmp = arr(i);
    ar(i) = ar(r);
    ar(r) = tmp;
    % Using MATLAB's indexing
    ar([i,r]) = ar([r,i]);
    

    编辑:虽然这演示了一种更加“MATLAB-esque”的做事方式,you incur a performance hit assigning elements like this,所以如果你不介意更长的代码,那么随意使用temps! < / p>

    您可以使用此7行功能替换所有代码,这将更快。我添加了注释来解释逻辑...

    function ar = qs(ar)
    % Quicksort algorithm, for some 1D array "ar"
    % First check we have more than one element, vital to terminate the recursion!
        if numel(ar) > 1
            % Choose some pivot index p, which we will split the array around
            p = ceil(numel(ar)/2);
            % Put values from "ar" which are smaller than "ar(p)" in one array
            smaller = ar(ar < ar(p));
            % Put values from "ar" which are larger than "ar(p)" in another array
            larger = ar(ar > ar(p));
            % Rebuild "ar" from a (qs-sorted) array of the smaller elemenets, then all
            % elements which were equal the pivot element (no need to sort these!) then 
            % a (qs-sorted) array of the larger elements.
            ar = [qs(smaller), ar(ar == ar(p)), qs(larger)];    
        end
    end
    

    这可以像你的测试一样运行:

    ar = [7,7,3,0,3,1,4,7,5,6];
    qs(ar)
    >> ans = [0 1 3 3 4 5 6 7 7 7]
    

    我们可以通过不明确声明smallerlarger以及始终选择p=1来使这更短一些(尽管这是已排序数组的最坏情况)。

    function ar = qs(ar)
        if numel(ar) > 1
            ar = [qs(ar(ar < ar(1))), ar(ar == ar(1)), qs(ar(ar > ar(1)))];    
        end
    end