执行Java代码以获得O(1)中的结果

执行Java代码以获得O(1)中的结果,java,time-complexity,big-o,concurrenthashmap,Java,Time Complexity,Big O,Concurrenthashmap,我有一个网络服务,我可以从中获得时间和价格。我已将这些记录保存在ConcurrentHashMap中,因为它需要在多线程环境中支持时间戳(LocalDateTime)作为键,价格(BigDecimal)作为值。要求获得以下详细信息 过去90项记录中的总记录 过去90条记录中的平均记录 最近90个记录中的最低价格 过去90年最高价格记录 过去90年的总价格记录 过去90个记录中的平均价格 我已成功地通过下面所示的代码a达到要求 ConcurrentHashMap<LocalDateTime,

我有一个网络服务,我可以从中获得时间和价格。我已将这些记录保存在ConcurrentHashMap中,因为它需要在多线程环境中支持时间戳(LocalDateTime)作为键,价格(BigDecimal)作为值。要求获得以下详细信息

  • 过去90项记录中的总记录
  • 过去90条记录中的平均记录
  • 最近90个记录中的最低价格
  • 过去90年最高价格记录
  • 过去90年的总价格记录
  • 过去90个记录中的平均价格
  • 我已成功地通过下面所示的代码a达到要求

    ConcurrentHashMap<LocalDateTime, BigDecimal> data = // my full records
    
    int totalRecords = 0;
    BigDecimal highestPrice = new BigDecimal(0.0);
    BigDecimal lowestPrice = new BigDecimal(0.0);
    BigDecimal totalPriceSum = new BigDecimal(0.0);
    Instant currentTime = Instant.now();
    Duration limit = Duration.ofSeconds(90);
    for (LocalDateTime time : data.keySet()) {
        Duration duration = Duration.between(currentTime , time);
        Boolean matches = ( duration.compareTo(limit) < 0 );
        if(matches) 
        {
            BigDecimal recordPrice = data.get(time);
            if(recordPrice.compareTo(lowestPrice) < 0) {
                lowestPrice = recordPrice;
            }
    
            if(recordPrice.compareTo(lowestPrice) > 0) {
                highestPrice = recordPrice;
            }
            totalPriceSum = totalPriceSum.add(recordPrice);
            totalRecords++;
        }
    }
    
    
    System.out.println("Total records in last 90 records: "+ totalRecords);
    System.out.println("Average records in last 90 records: "+ (totalRecords/90)*100);
    System.out.println("Lowest Price in last 90 records: "+ lowestPrice);
    System.out.println("Highest Price in last 90 records: "+ highestPrice);
    System.out.println("Total Price in last 90 records: "+ totalPriceSum);
    System.out.println("Average Price in last 90 records: "+ (totalPriceSum.doubleValue()/90)*100);
    
    ConcurrentHashMap数据=//我的完整记录
    int totalRecords=0;
    BigDecimal highestPrice=新的BigDecimal(0.0);
    BigDecimal lowestPrice=新的BigDecimal(0.0);
    BigDecimal totalPriceSum=新的BigDecimal(0.0);
    Instant currentTime=Instant.now();
    持续时间限制=持续时间秒(90);
    for(LocalDateTime:data.keySet()){
    持续时间=持续时间之间(currentTime,time);
    布尔匹配=(duration.compareTo(limit)<0);
    如果(匹配)
    {
    BigDecimal recordPrice=data.get(时间);
    if(记录价格比(最低价格)<0){
    最低价格=记录价格;
    }
    if(记录价格比(最低价格)>0){
    最高价格=记录价格;
    }
    totalPriceSum=totalPriceSum.add(记录价格);
    totalRecords++;
    }
    }
    System.out.println(“最近90条记录中的总记录:“+totalRecords”);
    System.out.println(“最近90条记录中的平均记录数:”+(totalRecords/90)*100);
    System.out.println(“过去90条记录中的最低价格:“+最低价格”);
    System.out.println(“过去90条记录中的最高价格:“+最高价格”);
    System.out.println(“最近90条记录中的总价:“+totalPriceSum”);
    System.out.println(“最近90条记录的平均价格:”+(totalPriceSum.doubleValue()/90)*100);
    
    但是我的客户说这有一些性能问题,代码应该在O(1)中运行并给出


    有谁能帮助我或建议我一个不同的方法来实现这一点。我是否应该使用集合来实现O(1)

    可能您拥有的记录比过去90秒的记录多得多。循环浏览所有这些内容,只过滤出你感兴趣的少数几个内容,这是你花费大部分时间的地方。你要么

  • 在迭代键列表之前对其进行排序(这本身不是O(1)操作),或者
  • 首先,保持数据的排序顺序。(看看是否适合您的需要。)
  • 数据按顺序排序后,从最近的末尾开始迭代。一旦找到一条超过90秒的记录,就可以停止循环


    注意:这永远不会是真正的O(1),因为您正在迭代一个可以改变大小的列表。通过对正在循环的集合进行排序,您应该仍然能够极大地提高性能。

    从注释中可以看出,下面是我关于计算要使用的确切密钥的一个示例。它仍然使用
    LocalDateTime
    (而不是nano的Long)作为键,但它被截断为秒。因此,最多需要收集90把钥匙

    存在聚合
    PriceRequest
    类,用于在同一秒内保存并发请求。(它不是完全线程安全的。)

    public类最后90秒{
    private Map priceRequests=new ConcurrentHashMap();
    公共静态void main(字符串[]args)引发异常{
    Last90Seconds应用程序=新的Last90Seconds();
    app.simulatePriceRequests();//连续模拟价格请求的线程
    对于(int i=0;i<10;i++){
    睡眠(9000);
    app.reportOnPriceRequests();
    }
    }
    私有void simulatePriceRequests(){
    新线程(newrequestforpricesimulator()).start();
    }
    私有void reportOnPriceRequests(){
    long startNanos=System.nanoTime();
    新建ReportSimulator().generateReport();
    long elapsednos=System.nanoTime()-startNanos;
    System.out.println(“生成报告的时间为“+elapsednos/1000.0+”毫秒。\n\n”);
    }
    专用LocalDateTime截断秒(LocalDateTime ldt){
    返回ldt.truncatedTo(计时单位秒);
    }
    private PriceRequest getPriceTracker(LocalDateTime密钥){
    返回priceRequests.get(key);
    }
    private PriceRequest getPriceTrackerEvenIfAbsent(LocalDateTime密钥){
    返回priceRequests.ComputeFabSent(键,v->new PriceRequest());
    }
    公共类RequestForPriceSimulator实现可运行{
    @凌驾
    公开募捐{
    LocalDateTime rightNow=truncateToses(LocalDateTime.now());
    LocalDateTime ninentySecondsFromNow=rightNow.plusSeconds(90);
    while(rightNow.isBefore(nintentysecondsfromsnow)){
    PriceRequest pt=getPriceTrackerEvenIfAbsent(立即发送);
    double price=ThreadLocalRandom.current().nextDouble()*10.0;
    pt.addRequest(价格);
    试一试{
    睡眠(10);
    }捕捉(中断异常e){
    e、 printStackTrace();
    }
    rightNow=truncateToses(LocalDateTime.now());
    }
    System.out.println(“全部完成模拟价格请求!\n”);
    }
    }
    公共类报告模拟器{
    公共无效生成器报告(){
    双最低=双最大值;
    最高加倍=最低加倍值;
    双倍合计=0;
    长请求计数器=0;
    int键计数器=0;
    int validKeyCounter=0;
    LocalDateTime rightNow=truncateToses(LocalDateTime.now());
    LocalDateTime key=rightNow.minsse
    
    public class Last90Seconds {
        private Map<LocalDateTime, PriceRequest> priceRequests = new ConcurrentHashMap<>();
    
        public static void main(String[] args) throws Exception {
            Last90Seconds app = new Last90Seconds();
            app.simulatePriceRequests();  // thread which continuously simulates a price request
    
            for (int i = 0; i < 10; i++) {
                Thread.sleep(9000);
                app.reportOnPriceRequests();
            }
        }
    
        private void simulatePriceRequests() {
            new Thread(new RequestForPriceSimulator()).start();
        }
    
        private void reportOnPriceRequests() {
            long startNanos = System.nanoTime();
            new ReportSimulator().generateReport();
            long elapsedNanos = System.nanoTime() - startNanos;
            System.out.println("Took " + elapsedNanos / 1000.0 + " milliseconds to generate report.\n\n");
        }
    
        private LocalDateTime truncateToSeconds(LocalDateTime ldt) {
            return ldt.truncatedTo(ChronoUnit.SECONDS);
        }
    
        private PriceRequest getPriceTracker(LocalDateTime key) {
            return priceRequests.get(key);
        }
    
        private PriceRequest getPriceTrackerEvenIfAbsent(LocalDateTime key) {
            return priceRequests.computeIfAbsent(key, v -> new PriceRequest());
        }
    
        public class RequestForPriceSimulator implements Runnable {
    
            @Override
            public void run() {
                LocalDateTime rightNow = truncateToSeconds(LocalDateTime.now());
                LocalDateTime ninentySecondsFromNow = rightNow.plusSeconds(90);
                while (rightNow.isBefore(ninentySecondsFromNow)) {
    
                    PriceRequest pt = getPriceTrackerEvenIfAbsent(rightNow);
                    double price = ThreadLocalRandom.current().nextDouble() * 10.0;
                    pt.addRequest(price);
    
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    rightNow = truncateToSeconds(LocalDateTime.now());
                }
    
                System.out.println("All done simulating a price request!\n");
            }
        }
    
        public class ReportSimulator {
    
            public void generateReport() {
                double lowest = Double.MAX_VALUE;
                double highest = Double.MIN_VALUE;
                double total = 0;
                long requestCounter = 0;
    
                int keyCounter = 0;
                int validKeyCounter = 0;
    
                LocalDateTime rightNow = truncateToSeconds(LocalDateTime.now());
                LocalDateTime key = rightNow.minusSeconds(90);
                while (key.isBefore(rightNow)) {
                    keyCounter++;
    
                    key = key.plusSeconds(1);
    
                    PriceRequest pt = getPriceTracker(key);
                    if (pt == null) {
                        continue;
                    }
    
                    validKeyCounter++;
                    if (pt.getLowest() < lowest) {
                        lowest = pt.getLowest();
                    }
    
                    if (pt.getHighest() < highest) {
                        highest = pt.getHighest();
                    }
    
                    total += pt.getTotal();
                    requestCounter += pt.getCounter();
                }
    
                System.out.println("Used " + validKeyCounter + " keys out of " + keyCounter + " possible keys.");
                System.out.println("Total records in last 90 seconds: " + requestCounter);
                System.out.println("Average records per second in last 90 seconds: " + requestCounter / 90);
                System.out.println("Lowest Price in last 90 seconds: " + lowest);
                System.out.println("Highest Price in last 90 seconds: " + highest);
                System.out.println("Total Price in last 90 seconds: " + total);
                System.out.println("Average Price in last 90 seconds: " + (total / requestCounter));
            }
        }
    
        public class PriceRequest {
            private long counter;
            private double lowest;
            private double highest;
            private double total;
    
            public PriceRequest() {
                lowest = Double.MAX_VALUE;
                highest = Double.MIN_VALUE;
            }
    
            public void addRequest(double price) {
                synchronized (this) {
    
                    if (price < lowest) {
                        lowest = price;
                    }
    
                    if (price > highest) {
                        highest = price;
                    }
    
                    total += price;
                    counter++;
                }
            }
    
            public double getCounter() {
                synchronized (this) {
                    return counter;
                }
            }
    
            public double getLowest() {
                synchronized (this) {
                    return lowest;
                }
            }
    
            public double getHighest() {
                synchronized (this) {
                    return highest;
                }
            }
    
            public double getTotal() {
                synchronized (this) {
                    return total;
                }
            }
        }
    
    }