快速排序尾部调用优化(将最坏情况下的空间减少到日志n)

先决条件: 尾声消除

null

在里面 快速排序 ,分区函数已经就位,但我们需要额外的空间来进行递归函数调用。快速排序的一个简单实现对自身进行两次调用,在最坏的情况下,需要函数调用堆栈上的O(n)空间。

最坏的情况是,选定的轴总是分割数组,使一部分有0个元素,而另一部分有n-1个元素。例如,在下面的代码中,如果我们选择最后一个元素作为轴心,我们得到排序数组的最坏情况(参见 (用于可视化)

C

/* A Simple implementation of QuickSort that makes two
two recursive calls. */
void quickSort( int arr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
// See below link for complete running code


JAVA

// A Simple implementation of QuickSort that
// makes two recursive calls.
static void quickSort( int arr[], int low, int high)
{
if (low < high)
{
// pi is partitioning index, arr[p] is
// now at right place
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1 );
quickSort(arr, pi + 1 , high);
}
}
// This code is contributed by rutvik_56


Python3

# Python3 program for the above approach
def quickSort(arr, low, high):
if (low < high):
# pi is partitioning index, arr[p] is now
# at right place
pi = partition(arr, low, high)
# Separately sort elements before
# partition and after partition
quickSort(arr, low, pi - 1 )
quickSort(arr, pi + 1 , high)
# This code is contributed by sanjoy_62


C#

// A Simple implementation of QuickSort that
// makes two recursive calls.
static void quickSort( int []arr, int low, int high)
{
if (low < high)
{
// pi is partitioning index, arr[p] is
// now at right place
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
// This code is contributed by pratham76.


Javascript

<script>
// A Simple implementation of QuickSort that
// makes two recursive calls.
function quickSort(arr , low , high)
{
if (low < high)
{
// pi is partitioning index, arr[p] is
// now at right place
var pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
// This code is contributed by umadevi9616.
</script>


我们能减少函数调用堆栈的辅助空间吗? 我们可以将辅助空间限制为O(logn)。这个想法是基于 尾声消除 .如图所示 以前的职位 ,我们可以转换代码,使其进行一次递归调用。例如,在下面的代码中,我们将上面的代码转换为使用while循环,并减少了递归调用的数量。

C

/* QuickSort after tail call elimination using while loop */
void quickSort( int arr[], int low, int high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
low = pi+1;
}
}
// See below link for complete running code


JAVA

/* QuickSort after tail call elimination using while loop */
static void quickSort( int arr[], int low, int high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1 );
low = pi+ 1 ;
}
}
// See below link for complete running code
// This code is contributed by gauravrajput1


Python3

# QuickSort after tail call elimination using while loop '''
def quickSort(arr, low, high):
while (low < high):
# pi is partitioning index, arr[p] is now
#  at right place '''
pi = partition(arr, low, high)
# Separately sort elements before
# partition and after partition
quickSort(arr, low, pi - 1 )
low = pi + 1
# See below link for complete running code
# https:#ide.geeksforgeeks.org/qrlM31
# This code is contributed by gauravrajput1


C#

/* QuickSort after tail call elimination using while loop */
static void quickSort( int []arr, int low, int high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
low = pi+1;
}
}
// See below link for complete running code
// This code contributed by gauravrajput1


Javascript

<script>
/* QuickSort after tail call elimination using while loop */
function quickSort(arr , low , high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
var pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
low = pi+1;
}
}
// See below link for complete running code
// This code is contributed by gauravrajput1
</script>


虽然我们减少了递归调用的数量,但在最坏的情况下,上面的代码仍然可以使用O(n)辅助空间。在最坏的情况下,数组的划分方式可能是第一部分始终有n-1个元素。例如,当最后一个元素被选为轴,数组按递增顺序排序时,可能会发生这种情况。

我们可以优化上面的代码,只对分区后的较小部分进行递归调用。下面是这个想法的实现。

进一步优化:

C

/* This QuickSort requires O(Log n) auxiliary space in
worst case. */
void quickSort( int arr[], int low, int high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// If left part is smaller, then recur for left
// part and handle right part iteratively
if (pi - low < high - pi)
{
quickSort(arr, low, pi - 1);
low = pi + 1;
}
// Else recur for right part
else
{
quickSort(arr, pi + 1, high);
high = pi - 1;
}
}
}
// See below link for complete running code


JAVA

/* This QuickSort requires O(Log n) auxiliary space in
worst case. */
static void quickSort( int arr[], int low, int high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// If left part is smaller, then recur for left
// part and handle right part iteratively
if (pi - low < high - pi)
{
quickSort(arr, low, pi - 1 );
low = pi + 1 ;
}
// Else recur for right part
else
{
quickSort(arr, pi + 1 , high);
high = pi - 1 ;
}
}
}
// See below link for complete running code
// This code is contributed by gauravrajput1


Python3

''' This QuickSort requires O(Log n) auxiliary space in
worst case. '''
def quickSort(arr, low, high)
{
while (low < high):
''' pi is partitioning index, arr[p] is now
at right place '''
pi = partition(arr, low, high);
# If left part is smaller, then recur for left
# part and handle right part iteratively
if (pi - low < high - pi):
quickSort(arr, low, pi - 1 );
low = pi + 1 ;
# Else recur for right part
else :
quickSort(arr, pi + 1 , high);
high = pi - 1 ;
# See below link for complete running code
# https:#ide.geeksforgeeks.org/LHxwPk
# This code is contributed by gauravrajput1


C#

/* This QuickSort requires O(Log n) auxiliary space in
worst case. */
static void quickSort( int []arr, int low, int high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// If left part is smaller, then recur for left
// part and handle right part iteratively
if (pi - low < high - pi)
{
quickSort(arr, low, pi - 1);
low = pi + 1;
}
// Else recur for right part
else
{
quickSort(arr, pi + 1, high);
high = pi - 1;
}
}
}
// See below link for complete running code
// This code is contributed by gauravrajput1


Javascript

<script>
/* This QuickSort requires O(Log n) auxiliary space in
worst case. */
function quickSort(arr , low , high)
{
while (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
var pi = partition(arr, low, high);
// If left part is smaller, then recur for left
// part and handle right part iteratively
if (pi - low < high - pi)
{
quickSort(arr, low, pi - 1);
low = pi + 1;
}
// Else recur for right part
else
{
quickSort(arr, pi + 1, high);
high = pi - 1;
}
}
}
// See below link for complete running code
// This code contributed by gauravrajput1
</script>


在上面的代码中,如果左半部分变小,那么我们对左半部分进行递归调用。其他的都是正确的部分。在最坏的情况下(对于空间),当所有递归调用中的两部分大小相等时,我们使用O(logn)额外空间。

参考: http://www.cs.nthu.edu.tw/~wkhon/algo08教程/tutorial2b。pdf

本文由 德拉杰·贾因 。如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请发表评论

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享