是否可以基于中值将一系列数字拆分为两组而不进行排序?

时间:2010-06-17 19:17:35

标签: algorithm sorting

是否存在根据动态确定的中值将一组随机数分成两组的算法(不对它们进行排序)?

实施例。如果我有序列2-3-6-7-1-4-5,结果将是两个分开的组:

A)1 2 3

B)5 6 7

中位数价值:4

4 个答案:

答案 0 :(得分:3)

您可以在linear time中找到数组(和拆分)的中位数。

答案 1 :(得分:0)

是的,这可以在 O(n)

中完成

首先,如果我们已经知道中位数,我们可以通过迭代序列并将每个值与中位数进行比较,轻松地将序列分成两个 O(n)。那么我们如何在 O(n)

中找到中位数

基本思想是使用quicksort,但不是递归排序数据透视的两边,只对包含中位数的一半进行排序(即包含指数的一半) ⌈n/2⌉)。如果我们选择一个枢轴保证快速排序的几何收敛(如median-of-medians那样),那么我们的整体算法将是O(n)。

算法

让我们调用数组的当前大小 k ,并且由于中位数中位数 c 而减少 - 即。我们的支点保证阵列每步缩小至少 c

  1. 使用中位数中位数估算阵列的中位数 - O(k)
  2. 对数组快速排序方式进行分区(将估算作为我们的支点) - O(k)
  3. 选择包含中位数(索引⌈n/2⌉)的数组的一半。这个新的子数组的大小不会超过k/c。重复步骤1& 2递归,直到我们确定了原始数组中的位置为⌈n/2⌉的元素。
  4. 该算法的渐近运行时间为

    2 O(n)+ 2 O(n / c)+ 2 O(n / c 2 )+ 2 O(n / c 3 )+ ...
    = O(n)

答案 2 :(得分:0)

BFPRT(Blum-Floyd-Pratt-Rivest-Tarjan)算法(查看wiki)可以找到线性时间的中位数,即O(n)

然而,O - 符号中的常量“隐藏”是如此之大,以至于对于实践而言,在O(n log n)中对数组进行排序以获得合理的数组大小会更快。

答案 3 :(得分:-1)

您可以通过查找最低楼层(n / 2)与最低楼层(n / 2)之间的平均值来找到中位数。这可以在previous SO question的帮助下完成。

之后,只需遍历您的数组,将大于中位数的元素放入一个中,然后将中位数放入另一个中。


或者,如果您知道序列的大小,则可以创建两个大小为(n / 2)的集合:一个“最小的一半”( S )和一个“最大的一半”( L ),然后逐个:

  • 取出序列中的一个元素,称之为 e
  • 如果 S 未满,请将其置于 S
  • 如果 S 已满,请找到( S | e )的最大元素(两者的并集)(这可以是通过迭代 S 来实现,直到找到大于 e 的元素;如果没有找到,则 e ,否则,它是找到的元素),并将其添加到 L 。如果这个最大值位于 S ,请将 e 置于 S 中重新填充。
  • 如果 L 已满,请找到( L | e )的最小元素并将其删除,然后添加 e e 未被删除,则强>进入 L

相信这是O(n)时间;如果我错了,有人会纠正我。我能想象的最糟糕的情况是原始序列按降序排序。

ruby​​实现(具有很多非性能快捷方式):

def split_into_halves to_split
  s = []
  l = []
  medianlimit = to_split.size/2
  for e in to_split
    if s.size < medianlimit
      s.push(e)
    else

      if s.max >= n
        max = s.max
        s.delete max
        s.push(e)
      else
        max = e
      end

      if l.size < medianlimit
        l.push(max)
      elsif l.max >= max
        l.delete l.max
        l.push(max)
      end

    end
  end

  return [s,l]
end

k = [2,3,6,7,1,4,5]
split_into_halves(k) #=> [[2,3,1],[6,4,5]]