java - 在线性时间内找到未排序数组的中位数?

标签 java arrays algorithm performance arraylist

经过仔细研究和思考,我决定发布这个问题,这是我今天早些时候提出的上一个问题的“续集”。

我制作了一个算法来查找 ArrayList 的中位数,基本上我所做的就是制作一个临时 ArrayList,然后在该 ArrayList 上使用 Collections.sort(),我可以轻松获得中位数。问题是对于较大的文件来说花费的时间太长,而且我正在尝试(没有运气)找到一种算法的实现来获取未排序的数组(或ArrayList)的中位数。

根据我读到的here ,使用 Median of Medians 算法,然后使用 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(),因此需要找到更好的在线性时间内找到中位数的算法。

谢谢。

最佳答案

我觉得基本的Quickselect算法(来自此链接的以下代码)非常容易理解:您选择一个主元,应用快速排序的分区函数,然后查看该主元结束的位置,相应地仅递归到其中的一半。

 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),但您可以通过随机选择主元来显着降低发生这种情况的可能性,如评论中所述。

如果您对您不完全理解的中位数中位数的实现不满意,我建议您采用类似的方法。

关于java - 在线性时间内找到未排序数组的中位数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31926852/

相关文章:

arrays - 跳过 “for each”循环中的第一个元素?

arrays - 将值转换为未知 `Element` 类型的数组

algorithm - 什么是 lzo 和 lzf,有什么区别?

java - 如何反射(reflect)过滤列表中的更改

java - Liferay:如何使enctype ="multipart/form-data"和方法="post"一起工作?

javascript - 如何在不循环的情况下将固定属性值插入数组内的每个对象?

algorithm - 如何证明排序网络深度的下界是lgn?

java - 找到重叠部分的最大数量

java - 在 Java 中确定数组的长度(初学者)

java - 在类里面找不到主要方法