我正在研究算术分析课程中期的快速选择,我一直在使用的算法如下:
Quickselect(A[L...R],k)
// Input: Array indexed from 0 to n-1 and an index of the kth smallest element
// Output: Value of the kth position
s = LomutoPartition(A[L...R]) // works by taking the first index and value as the
// pivot and returns it's index in the sorted position
if(s == k-1) // we have our k-th element, it's k-1 because arrays are 0-indexed
return A[s]
else if(s> L+k-1) // this is my question below
Quickselect(L...s-1,k) // basically the element we want is somewhere to the left
// of our pivot so we search that side
else
Quickselect(s+1...R, k-1-s)
/* the element we want is greater than our pivot so we search the right-side
* however if we do we must scale the k-th position accordingly by removing
* 1 and s so that the new value will not push the sub array out of bounds
*/
我的问题是为什么我们首先需要L + k - 1
?在纸上做一些例子我得出的结论是,无论上下文L总是一个索引而且索引始终为0.这对算法没有任何作用吗?
答案 0 :(得分:1)
行
之间似乎存在差异if(s == k-1)
和行
else if(s> L+k-1)
解释是不相容的。
正如Trincot正确指出的那样,从第二次递归调用开始, L 可能不是0.你的Lomuto子程序不采用数组,低索引和高索引(如例如the one in Wikipedia。相反,它只需要一个数组(恰好是其他数组的低和高之间的子数组)。它返回的索引 s 因此相对于子数组,并且要将其转换为原始数组中的位置,您需要添加 L 。这与您的第一行一致,除了它后面的行应该是
return A[L + s]
因此,您的第二行也应该与 k - 1 进行比较,而不是 L + k - 1 。
修改强>
在评论之后,这里是来自维基百科的伪代码:
// Returns the n-th smallest element of list within left..right inclusive
// (i.e. left <= n <= right).
// The search space within the array is changing for each round - but the list
// is still the same size. Thus, n does not need to be updated with each round.
function select(list, left, right, n)
if left = right // If the list contains only one element,
return list[left] // return that element
pivotIndex := ... // select a pivotIndex between left and right,
// e.g., left + floor(rand() % (right - left + 1))
pivotIndex := partition(list, left, right, pivotIndex)
// The pivot is in its final sorted position
if n = pivotIndex
return list[n]
else if n < pivotIndex
return select(list, left, pivotIndex - 1, n)
else
return select(list, pivotIndex + 1, right, n)
注意条件
if n = pivotIndex
和
else if n < pivotIndex
它们对分区中返回的索引的解释是一致的。
再一次,可以将分区子例程定义为相对于子数组的开头返回索引,或者相对于原始数组返回索引,但是必须保持一致性。 / p>