Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 有效实施';自x'以来的事件;在爪哇_Java_Algorithm_Optimization - Fatal编程技术网

Java 有效实施';自x'以来的事件;在爪哇

Java 有效实施';自x'以来的事件;在爪哇,java,algorithm,optimization,Java,Algorithm,Optimization,我希望能够询问一个对象“在过去的x秒内发生了多少事件”,其中x是一个参数 e、 g.在过去120秒内发生了多少事件 我的方法是基于事件发生的数量线性的,但我想知道实现这一要求的最有效方式(空间和时间)是什么 public class TimeSinceStat { private List<DateTime> eventTimes = new ArrayList<>(); public void apply() { eventTimes.add(

我希望能够询问一个对象“在过去的x秒内发生了多少事件”,其中x是一个参数

e、 g.在过去120秒内发生了多少事件

我的方法是基于事件发生的数量线性的,但我想知道实现这一要求的最有效方式(空间和时间)是什么

public class TimeSinceStat {
private List<DateTime> eventTimes = new ArrayList<>();

public void apply() {
            eventTimes.add(DateTime.now());
           }


public int eventsSince(int seconds) {
    DateTime startTime = DateTime.now().minus(Seconds.seconds(seconds));
    for (int i = 0; i < orderTimes.size(); i++) {
        DateTime dateTime = eventTimes.get(i);
        if (dateTime.compareTo(startTime) > 0)
            return eventTimes.subList(i, eventTimes.size()).size();
    }
    return 0;
}
公共类TimesRunStat{
private List eventTimes=new ArrayList();
公开无效申请(){
add(DateTime.now());
}
公共整数事件频度(整数秒){
DateTime startTime=DateTime.now().减(秒。秒(秒));
对于(int i=0;i0)
返回eventTimes.subList(i,eventTimes.size()).size();
}
返回0;
}
(PS-我使用JodaTime表示日期/时间)

编辑:


此算法的关键是查找过去x秒内发生的所有事件;确切的开始时间(例如,现在-30秒)is可能在集合中,也可能不在集合中

日期时间
存储在
树集
中,然后使用
尾集
获取最新事件。这样,您就不必通过迭代(即
O(n)
)而是通过搜索(即
O(logn)
)来找到起点

编辑x2 以下是一种更有效的方法,它利用了一个事实,即您只记录在所有其他事件之后发生的事件。对于每个事件,存储到该日期为止的事件数:

SortedMap<DateTime, Integer> eventCounts = initEventMap();

public SortedMap<DateTime, Integer> initEventMap() {
    TreeMap<DateTime, Integer> map = new TreeMap<>();
    //prime the map to make subsequent operations much cleaner
    map.put(DateTime.now().minus(Seconds.seconds(1)), 0);
    return map;
}

private long totalCount() {
    //you can handle the edge condition here
    return eventCounts.getLastEntry().getValue();
}

public void logEvent() {
    eventCounts.put(DateTime.now(), totalCount() + 1);
}

这消除了低效的迭代。这是一个恒定时间的查找和一个
O(logn)
lookup.

由于
DateTime
已经实现了
compariable
接口,我建议将数据存储在
树状图中,您可以使用来获取在所需时间发生的
DateTime
的子树

根据您的代码:

public class TimeSinceStat {
    //just in case two or more events start at the "same time"
    private NavigableMap<DateTime, Integer> eventTimes = new TreeMap<>();
    //if this class needs to be used in multiple threads, use ConcurrentSkipListMap instead of TreeMap

    public void apply() {
        DateTime dateTime = DateTime.now();
        Integer times = eventTimes.contains(dateTime) != null ? 0 : (eventTimes.get(dateTime) + 1);
        eventTimes.put(dateTime, times);
    }

    public int eventsSince(int seconds) {
        DateTime startTime = DateTime.now().minus(Seconds.seconds(seconds));
        NavigableMap<DateTime, Integer> eventsInRange = eventTimes.tailMap(startTime, true);
        int counter = 0;
        for (Integer time : eventsInRange.values()) {
            counter += time;
        }
        return counter;
    }
}
公共类TimesRunStat{
//以防两个或多个事件“同时”开始
private NavigableMap eventTimes=new TreeMap();
//如果该类需要在多个线程中使用,请使用ConcurrentSkipListMap而不是TreeMap
公开无效申请(){
DateTime DateTime=DateTime.now();
整数倍=eventTimes.contains(dateTime)!=null?0:(eventTimes.get(dateTime)+1);
eventTimes.put(dateTime,times);
}
公共整数事件频度(整数秒){
DateTime startTime=DateTime.now().减(秒。秒(秒));
NavigableMap eventsInRange=eventTimes.tailMap(startTime,true);
int计数器=0;
for(整数时间:EventsRange.values()){
计数器+=时间;
}
返回计数器;
}
}

假设列表已排序,您可以进行二进制搜索。Java Collections已经提供了
集合。binarySearch
,而
DateTime
实现了
可比性
(根据JodaTime JavaDoc).
binarySearch
将返回所需值的索引(如果该值存在于列表中),否则它将返回小于所需值的最大值的索引(符号翻转)。因此,您只需(在
eventsSince
方法中):

//找到你想要的时间。
int index=Collections.binarySearch(eventTimes,startTime);
if(index<0)index=-(index+1)-1;//如果找不到startTime,请确保得到正确的索引
//检查是否有重复
while(index!=eventTimes.size()-1&&eventTimes.get(index).equals(eventTimes.get(index+1))){
索引++;
}
//返回索引后的事件数
return eventTimes.size()-index;//这是有效的,因为索引从0开始

这应该是一种更快的实现方法。

如果您是从头开始实现数据结构,并且数据不是按顺序排序的,那么您应该构建一个平衡的树(另请参见)。这只是一个常规的平衡树,树的大小根在节点本身维护的每个节点上

大小字段可以有效地计算树中任何键的“秩”。您可以通过在树中进行两次O(logn)探测,以获得最小和最大范围值的秩,最后计算它们的差值,来执行所需的范围查询

建议的树和集尾操作非常好,除了尾视图需要时间来构建外,即使您只需要它们的大小。渐进复杂性与OST相同,但OST完全避免了这种开销。如果性能非常关键,那么这种差异可能是有意义的


当然,首先我必须使用标准库解决方案,只有在速度不够充分的情况下才考虑OST。<代码> > TeMeMAP还有数据在O(log n)中排序和处理,而使用<代码>列表< /> >方法采用<代码> o(n)

,它的用法是1行,但它不是按事件时间排序的-建议OP将它存储在按事件时间排序的结构中。OP只存储时间,不存储事件,所以我认为集合比Map@goat:当然已经分类了,但他并没有利用这个机会。@MarkPeters-如果我错了,请纠正我,但是这个费用cts用于在集合中精确匹配,但在现实世界中可能不是这样(我们在特定时间后查找元素计数)@伊恩:不,tailSet的工作方式是你所希望的。如果startTime不在集合中,它会接受它之后的一切。这是因为元素是可比较的,包括你正在搜索的值。我意外地忽略了一个相关的细节:
tailSet
的第二个参数和
tailMultiset
确定它是否应该包含ive或exclusive(即
=
传递的元素)我认为这类问题应该在code Revi中
SortedMap<DateTime, Integer> eventCounts = initEventMap();

public SortedMap<DateTime, Integer> initEventMap() {
    TreeMap<DateTime, Integer> map = new TreeMap<>();
    //prime the map to make subsequent operations much cleaner
    map.put(DateTime.now().minus(Seconds.seconds(1)), 0);
    return map;
}

private long totalCount() {
    //you can handle the edge condition here
    return eventCounts.getLastEntry().getValue();
}

public void logEvent() {
    eventCounts.put(DateTime.now(), totalCount() + 1);
}
public int eventsSince(int seconds) {
    DateTime startTime = DateTime.now().minus(Seconds.seconds(seconds));
    return totalCount() - eventCounts.lowerEntry(startTime).getValue();
}
public class TimeSinceStat {
    //just in case two or more events start at the "same time"
    private NavigableMap<DateTime, Integer> eventTimes = new TreeMap<>();
    //if this class needs to be used in multiple threads, use ConcurrentSkipListMap instead of TreeMap

    public void apply() {
        DateTime dateTime = DateTime.now();
        Integer times = eventTimes.contains(dateTime) != null ? 0 : (eventTimes.get(dateTime) + 1);
        eventTimes.put(dateTime, times);
    }

    public int eventsSince(int seconds) {
        DateTime startTime = DateTime.now().minus(Seconds.seconds(seconds));
        NavigableMap<DateTime, Integer> eventsInRange = eventTimes.tailMap(startTime, true);
        int counter = 0;
        for (Integer time : eventsInRange.values()) {
            counter += time;
        }
        return counter;
    }
}
// find the time you want.
int index=Collections.binarySearch(eventTimes, startTime);
if(index < 0) index = -(index+1)-1; // make sure we get the right index if startTime isn't found
// check for dupes
while(index != eventTimes.size() - 1 && eventTimes.get(index).equals(eventTimes.get(index+1))){
    index++;
}
// return the number of events after the index
return eventTimes.size() - index; // this works because indices start at 0