我怎样才能重新排列数组以获得最小,中位数和最大值?

时间:2015-04-24 14:47:13

标签: c++ algorithm

我希望重复重新排列数组或std::vector,以便最小值是第一个元素,最大值是最后一个元素,arr[(0+lastIdx)/2]是中位数,中位数之前的元素小于中位数,中位数之后的元素会更大。在每次查询min,max和median之后,我将对数据进行更改,并且我想再次快速查询这三个值。

每次我想重新排列数组时,数组都是一个大小相同的数组。

使用std::nth_element我可以在正确的位置获得中位数,然后我可以迭代数组以获得最小值和最大值。对于单个阵列,这实现了O(n)复杂度,并且显然这无法改进。 (也许,O(n)前面的复杂性常数)

我需要对数组进行操作,首先,我重新排列数组,然后执行其他操作,这会使排列的数组再次完全解除排列,但不会插入新值。然后,我一遍又一遍地重复这个过程。

5 个答案:

答案 0 :(得分:0)

即使你以某种方式设法降低了将最小值,最大值,中位数定位为零的成本, 您仍然需要将错位元素放在中位数的下方或上方。这意味着每次n/2 - 1 permutations的最坏情况。

  1. 第一次通过,找到最小值及其位置(O(n)时间,O(1)空格)
  2. 第二遍,找到最大值及其位置(O(n)时间,O(1)空间)
  3. 使用find the medianO(n)时间,O(1)空间)的第三次传递,median of median algorithm及其位置
  4. 通过交换将min,max,median放在各自的位置(0,n-1,n / 2)
  5. 现在你有两个索引:一个用于下面的0,一个用于上面的n-1。虽然当前below元素应该是它的位置,但是增加该索引。当前above元素应该是它的位置,减少该索引。当找到错位的元素时,在下方和上方交换。只要below < above重复一遍。 (O(n)时间,O(1)空间)
  6. 步骤4,5的逻辑:当它们应该在上面时,低于中位数的元素的数量正好是上面的元素的数量,应该在下面。

    当然你可以在一个函数中合并传递1,2,3,但这不会影响复杂性

    让我们运行:

    {3, 7, 9, 6, 8, 1, 4, 5, 2}
    

    传递1,2,3:min_pos = 5, max_pos = 2, median_pos = 7, median = 5

    swap (0, min_pos)    -> {1, 7, 9, 6, 8, 3, 4, 5, 2}
    swap (9, max_pos)    -> {1, 7, 2, 6, 8, 3, 4, 5, 9}
    swap (4, median_pos) -> {1, 7, 2, 6, 5, 3, 4, 8, 9}
    

    现在below_pos = 0 above_pos = 8。元素不是错位的。 接下来错位的是位置1处的7位。接下来错位的位置是位置6处的4位。

    swap (1, 6) -> {1, 4, 2, 6, 5, 3, 7, 8, 9}
    

    下面的错位是在第3位的6位。接下来错位在第5位是3位。

    swap (3, 5) -> {1, 4, 2, 3, 5, 6, 7, 8, 9}
    

    算法输出

    {1,4,2,3,5,6,7,8,9}

答案 1 :(得分:0)

如果进行了许多更改和许多查找,您可以在O(log n sqrt(n))摊销时间内执行此操作。

最初,您对数组进行排序。然后,提取中值周围的sqrt(n)最小值,sort(n)最大值和sqrt(n)值。所以你会知道“有n1个元素&lt; = x1”(其中n1是关于sqrt(n)而x1是n1个最小的元素),“有n2个元素&lt; = x2”(其中n2是关于n / 2 - sqrt(n)/ n,x2是n2最小元素),“有n3个元素&lt; = x3”(其中n3约为n / 2 + sqrt(n)/ n,x3是n3 - 最小元素)和“有n4个元素&lt; = x4”,其中n4接近n - sqrt(n),n4是x4最小元素。您可以跟踪元素编号0到n1,编号n2到n3以及编号n4到n-1。

要获得最小值,最大值或中值,您需要检查sqrt(n)元素。

当您对数组元素进行更改,或添加或插入元素时,您可以根据发生的情况调整值n1,n2,n3和n4,以及数字0到n1,n2到n3的列表,和n4到n-1。在进行太多更改后,将更改数字n1,n2,n3,n4,以便搜索min,max,medium需要太长时间或者不再有任何用处。发生这种情况时,再次对数据进行排序。

顺便说一句。我认为堆积的想法会更好。

答案 2 :(得分:-1)

如果您有大量内存,可以使用两个来存储中位数和两个变量来存储最小值/最大值:

优点:

  • 最低最高可在O(1)更新;
  • 中位数可以在O(log N);
  • 中更新

缺点:

  • 您需要额外的内存,N为两个堆(每个N / 2),N为您的向量 - 2N 内存而不是 N 在{{1}解决方案。

C ++中有一个内置的STL函数可以帮助您轻松构建和更新堆:std::make_heapstd::push_heapstd::pop_heap

有关如何使用两个堆来查找中位数的更多详细信息,请参阅here

嗯,你也可以变得更加棘手 - 使用两个向量来保存你的数据。在这种情况下,您只需要 N 内存,但您的数据将被拆分为两个向量。

答案 3 :(得分:-3)

O(n)似乎是你可以做的最好的排列数组,你做的方式似乎很好。

在最后一段中,您声明您对数组执行了某些操作,以便它再次以随机顺序排列,但不会添加任何新值。也许不是像某些人所说的那样创建堆,仅仅制作一个已安排数组的副本是不够的?

Pro:你只需要安排一次数组。

Con:你需要两倍的记忆。

答案 4 :(得分:-3)

绝对不能在O(N)中更快地完成它,因为你必须查看所有元素,甚至找到最小值。

当然,您可以讨论在O(N)复杂度内优化代码(即在 N 之前优化常量)。

或者你会在略微修改过的阵列上多次做同样的操作吗?