提供优化的算法来处理带有时间戳的值

Offer optimised algorithm to work with timestamped values

本文关键字:时间戳 处理 优化 算法      更新时间:2023-10-16

可能重复:
C#。需要优化计数正值和负值

我需要最大限度地提高以下功能的速度:

  • a。一个值进来了。value有两个属性-int值和以ticks表示的长时间戳
  • b。需要计算之前存储的小于1ms的值(从当前值开始(
  • c。需要分别计算阴性和阳性
  • d。我只需要知道是否有10个neg或pos值。我不需要保留任何其他关于价值观的知识

我认为-分别为pos和neg实现2个环形阵列,将expired替换为0,以跟踪pos-neg计数。

有什么想法吗?

维护2个缓冲区以将积极因素与消极因素分开听起来既痛苦又低效。

相反,您可以有一个包含所有值的单个缓冲区,并使用std::accumulate来对阳性和阴性进行计数。如果你从所有元组的集合开始(每个元组都有一个年龄和一个值(,你可以从根据年龄对集合进行排序开始,找到最后一个元素<=1ms旧,然后使用从begin()到该点的accumulate。这里有一些代码演示了最后一点:

#include <algorithm>
#include <numeric>
#include <iterator>
#include <vector>
#include <string>
#include <ctime>
using namespace std;
struct Counter 
{
    Counter(unsigned pos=0, unsigned neg=0) : pos_(pos), neg_(neg) {};
    unsigned pos_, neg_;
    Counter& operator+(int n)
    {
        if( n < 0 )
            ++neg_;
        else if( n > 0 )
            ++pos_;
        return * this;
    }
};
int main()
{
    srand((unsigned)time(0));
    vector<int> vals;
    generate_n(back_inserter(vals), 1000, []() 
    {
        return (rand() / (RAND_MAX/40)) - 20;
    });
    Counter cnt = accumulate(vals.begin(), vals.end(), Counter());
}

如果按年龄对集合进行排序,然后在排序后的结果中搜索最后一个符合条件的条目听起来过于低效,则可以使用for_each_if而不是accumulate,只需在整个集合上迭代一次。for_each_if不是标准库的一部分,但编写起来很容易。如果你不想写自己的for_each_if,那也没关系。你可以简单地调整累加器一点,这样它就不会累积太旧的元素:

#include <algorithm>
#include <numeric>
#include <iterator>
#include <vector>
#include <string>
#include <ctime>
using namespace std;
struct Tuple
{
    int val_;
    unsigned age_;
};
struct Counter 
{
    Counter(unsigned pos=0, unsigned neg=0) : pos_(pos), neg_(neg) {};
    unsigned pos_, neg_;
    Counter& operator+(const Tuple& tuple)
    {
        if( tuple.age_ > 1 )
            return * this; 
        if( tuple.val_ < 0 )
            ++neg_;
        else if( tuple.val_ > 0 )
            ++pos_;
        return * this;
    }
};
int main()
{
    srand((unsigned)time(0));
    vector<Tuple> tuples;
    generate_n(back_inserter(tuples), 1000, []() -> Tuple
    {
        Tuple retval;
        retval.val_ = (rand() / (RAND_MAX/40)) - 20;
        retval.age_ = (rand() / (RAND_MAX/5));
        return retval;
    });
    Counter cnt = accumulate(tuples.begin(), tuples.end(), Counter());
}

我会将值存储在一个由时间戳键控的最小堆中,因此最年轻的值位于堆的顶部。整数值是每个节点的辅助数据。然后,您可以使用遍历堆的递归函数来实现计数。您可以将负数和正数的运行总数传递给递归调用。

它看起来像这样,在类似Python的伪代码中,类型为:

def young_pos_and_neg(Time currtime, HeapNode p):
    if (p is not None and currtime - p.time < 1):
        posleft, negleft = young_pos_and_neg(p.leftChild())
        posright, negright = young_pos_and_neg(p.rightChild())
        totpos = posleft + posright
        totneg = negleft + negright
        if (p.intValue < 0):
            return totpos, totneg + 1
        else:
            return totpos + 1, totneg
    else:
        return 0, 0

如果在插入新值之前在堆根上调用此函数,但使用新值的时间戳作为currtime参数,则将获得每个值的计数。这可能不是最快的方式,但它非常简单优雅。在C++中,可以用结构替换元组返回值。