我正在通过在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)
答案 0 :(得分:3)
在函数parti
中,要根据数据透视对数组进行分区,在尝试确定数据的正确位置时,包括数据透视本身。
在某些情况下,这会带来无限递归,因为枢轴只是在相邻位置之间交换,因为与自身进行比较 。
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
% ...
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 代码块
在您的功能中,您使用low
和high
索引来跟踪您的分区并没有帮助。使用递归快速排序功能的重点是:
ar(p)
ar
ar(p)
,另一个数值大于ar(p)
。等值可以在任一阵列中,因为它们将保留在枢轴旁边。列表是自相似的,我的意思是将每个子列表视为自己需要排序的列表,而不是更大列表的一部分!您不需要跟踪索引(当您进行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]
我们可以通过不明确声明smaller
和larger
以及始终选择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