经过仔细的研究和思考,我决定发布这个问题,这是一个续集"至今天早些时候我提出的问题。
我做了一个算法,找到了一个ArrayList的中位数,基本上我只做了一个临时的ArrayList,然后在那个ArrayList上使用Collections.sort(),我可以轻松得到中位数。问题是,对于较大的文件需要太长时间,我正在尝试(没有运气)找到算法的实现来获得未排序的数组(或ArrayList)的中位数。
根据我阅读here,使用中位数中位数算法,然后使用QuickSelect,但我找不到一个易于理解的实际实现。
这是我的代码片段,用于查找大小为filterSize
的ArrayList的中位数:
while(elements.size()-counter >= filterSize){
for(int i = 0; i<filterSize; i++){
tempElements.add(this.elements.get(i+counter));
if(i==filterSize){
break;
}
}
Collections.sort(tempElements); //Sort tempElements to find median
outputElements.add(tempElements.get((filterSize-1)/2)); //Add median to an output ArrayList after calculating median index
counter++;
tempElements.clear(); //Removes all elements from the tempElements and start again
}
基本上我试图避免在代码中完全使用Collections.sort()
和tempElements.clear()
,因此找到一种更好的算法来查找线性时间的中位数。
感谢。
答案 0 :(得分:4)
我认为基本的Quickselect算法(此链接下面的代码)很容易理解:你选择一个支点,应用Quicksort的分区功能,然后查看该支点的结束位置,相应地递归只有一半。
function partition(list, left, right, pivotIndex)
pivotValue := list[pivotIndex]
swap list[pivotIndex] and list[right] // Move pivot to end
storeIndex := left
for i from left to right-1
if list[i] < pivotValue
swap list[storeIndex] and list[i]
increment storeIndex
swap list[right] and list[storeIndex] // Move pivot to its final place
return storeIndex
// Returns the n-th smallest element of list within left..right inclusive
// (i.e. left <= n <= right).
// The size of the list is not changing with each recursion.
// 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)
与中位数的中位数相比,这可以退化为O(n^2)
,但您可以通过随机选择枢轴来显着降低发生这种情况的几率,如评论中所述。
如果您对不完全理解的中位数中位数实施不满意,我建议您选择这样的方式。
答案 1 :(得分:1)
只是为了添加另一个答案,&#34;快速选择&#34;如果您随机选择每个支点,即确定中位数具有非常紧张的运行时间,即几乎可以确定&#34;线性时间,意味着当n变大时,随着常数c增大,获得大于cn的运行时间的概率非常快地变为0。因此,除非你担心赔率甚至比赢得彩票更有可能,但是对于所有意图和目的而言,有一个常数c,这样你就不会看到大于cn的运行时间,无论n。