【问题标题】:How to keep track of highest and lowest values in an arbitrary sized window如何在任意大小的窗口中跟踪最高和最低值
【发布时间】:2013-09-29 08:23:47
【问题描述】:

我有一个音频输入流,它接收当前播放音乐的音量。 然后在最新卷的某个窗口大小(范围从 5 到 40)上,我想跟踪窗口内的最高值和最低值。所以在每次迭代中,删除最旧的值并添加最新的音量读数。

也就是说,如果我以 5 个窗口运行程序 8 次迭代,结果会是这样。 只有低值和高值很重要。

加2

2

加4个

2 4

加 3

2 3 4

加2

2 2 3 4

加7

2 2 3 4 7

-从列表中删除前 2 个添加 9

2 3 4 7 9

删除4个,添加5个

2 3 5 7 9

删除 3 个,添加 2 个

2 2 5 7 9

最有效的方法是什么?使用什么类型的集合?

编辑请注意,此循环在单独的线程上不断运行

值是浮点数

【问题讨论】:

  • 这里有 2 对操作。最小\最大和添加\删除。哪一种出现频率更高??
  • 在每次迭代中添加和删除一个数字,然后找到最小值和最大值,它们出现的数量相同

标签: java sorting


【解决方案1】:

在每次迭代中添加和删除一个数字,然后是最小值和 最大找到,它们出现的数量相同

使用平衡二叉树,例如Treemap,所以在最坏的情况下所有操作都是 O(log n)。我相信如果这些操作连续发生,那么三个操作是 O(1) 和一个是 O(n) 是没有意义的。

顺便说一句,n=5 太小了,我不明白为什么你应该过分担心效率低下。

编辑: 要跟踪对象的顺序,您可以使用简单的队列作为二级结构。当您需要删除时,您删除队列的头部并将其用作在树中删除的键......添加和删除需要恒定的时间。

注意:可以到此为止,原创如下

调整后的min-max heap 是一种更好的复杂数据结构,它可以在您的所有操作之间进行很好的权衡:

  • 插入是O(log n)
  • 删除是O(n)
  • Min 和 Max 都是 O(l)

如果您只删除最大/最小,删除将是对数。调整是implement a general purpose delete which is log n

【讨论】:

  • 谢谢。它适用于一个 android 应用程序,它计算每个可能实例的音量是否高于窗口内高值和低值总和的百分比。我对速度的了解非常有限,所以我只想让它尽可能快。
  • 我对删除有点困惑,关于您的想法,您将如何跟踪添加值的顺序?
  • 是的,在您的问题中,您击落了最古老的。我忘了。已编辑
  • 您的意思是 TreeSet 而不是 TreeMap 因为 TreeMap 是按键排序的?
【解决方案2】:

您可以使用链表,因为您想在列表中存储重复值。此外,由于您计划添加到最后一个元素,因此您使用 LinkedList API 的 addLast() 方法。在您自己的 add() 方法中检查大小。如果大小达到最大大小,您可以调用链接列表的 removeFirst() 方法,然后调用 addLast() 方法。这样,您的链接列表大小将保持在 5 不变

public class Tester {
private LinkedList<Integer> values = new LinkedList<Integer>();
private static final int MAX_VAL = 5;

public void addvalue(int val) {
    if (values.size() == this.MAX_VAL) {
        values.removeFirst();
    }
    values.addLast(val);
}

public int getMaxValue(){           
    return Collections.min(values);
}

public int getMinValue(){
    return Collections.max(values);
}

}

【讨论】:

  • 谢谢,我如何有效地跟踪列表的最小值和最大值?
  • 由于你使用的是整数,你可以直接在你的链表上调用 Collections.sort
  • 如果我对它进行排序然后 removeFirst 它将删除最低值而不是最早添加的值?
  • 我忘记了max和min的api方法。我已经编辑了我的代码。看看吧。
  • 这是 Theta(totalNumberOfElements * WINDOW_SIZE)。为什么要维护一个单独的集合。为什么不从末尾(尾部)向后迭代,同时保持 min 和 max ?复杂性是一样的。
【解决方案3】:

由于值是 5 到 40 的整数,如果窗口很大,我们可以通过存储数组 count[] 来尝试获得一个好的平均案例时间,该数组记录每个卷的窗口数量。然后添加新元素并删除最后一个(保留Queue,例如LinkedList)是恒定时间,除非lowhigh 处的计数降至0。然后从最后一个开始逐个搜索值最好的,这是O(35),但实际上可能更便宜,尤其是在大窗户的情况下。

在某种程度上,这是一个常数时间解决方案,在实际输入中,您添加的体积元素的数量。它是O(nk),听起来k 只有三十多卷。我怀疑我们可以证明平均案例时间是\Theta(nk/w),其中w 是窗口大小,假设数据分布合理。

这听起来确实不像是高吞吐量操作(用户多久可以更改一次音量,总共数百次??)但这就是我在这些条件下实现它的方式。

【讨论】:

  • 嗨,我认为这里有些混乱,只有一个窗口,窗口中的值是最后一个(窗口大小)值的浮点数。音量是根据播放音乐的音频输出流计算的,不是用户音量,抱歉没说清楚。
  • 好吧,不管它是什么,这是解决问题的一种方法。这仅取决于数据的属性(分布),以及是否有可能成为 O(n)“慢”
猜你喜欢
  • 1970-01-01
  • 2012-07-19
  • 1970-01-01
  • 2013-01-27
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 2019-07-09
  • 2021-06-01
相关资源
最近更新 更多