跟踪列表老化

时间:2015-04-15 23:27:45

标签: algorithm data-structures

我的程序会定期收到一个项目列表,让它们结果。所以第一个列表可能如下所示:

[apple, pear, banana]

另外两个清单:

[pear, banana, plum, mandarin]
[banana, plum, apple]

我想要的是一个数据结构,它包含最新列表中的所有项目以及每个项目出现的连续次数。这里的最终状态应该是:

[banana:3, plum:2, apple:1]

因为香蕉已经在最后三个名单中出现了,李子只是最后两个,而苹果是一个新的条目(尽管我们不久前看到它我们忘了它,因为它上次没有)

显而易见的方式(以及我们软件的方式)是:

foreach(Fruit f in oldList){
    f.old = true;
}

foreach(Fruit newF in newList){
    foreach(Fruit oldF in oldList){
        if(newF == oldF){
            oldF.old = false;
            oldF.count++;
        }
    }
}

// iterate through oldList to remove all old entries
oldList.Remove((x) => x.old);

但这是一个很多循环,并且随着程序处理更多数据而变成瓶颈。这可以更有效地完成吗?

3 个答案:

答案 0 :(得分:0)

给定的溶液是O(n 2 )。如果你将两个列表排序,然后合并并删除水果,那就是O(n log n)。

答案 1 :(得分:0)

在这里获得性能提升的显而易见的方法是在检查增加计数之前删除不再需要的水果 - 这意味着内循环的迭代次数减少。

然而,更好的解决方案是按已知顺序对水果进行分类(或如果可能 - 最初存储);这样做可以完全消除对内循环的需求。

答案 2 :(得分:0)

如果你使用HashMap,你可以在O(n)(理论上你可以得到这个问题的最优渐近复杂度)中做到这一点。如果您不担心创建新对象,那么最干净的解决方案就是这样做。下面的代码是用Java编写的,但我认为它很容易理解。

public final class ConsistentFruitCountMaintainer {
        private Map<String, Integer> fruitToCount = new HashMap<>();

        public void processList(final List<Fruit> fruits) {
            final Map<String, Integer> nextMap = new HashMap<>();
            for(final Fruit fruit : fruits) {
                if (fruitToCount.containsKey(fruit)) {
                    nextMap.put(fruit, fruitToCount.get(fruit) + 1);
                } else {
                    nextMap.put(fruit, 1);
                }
            }
            fruitToCount = nextMap;
        }

        public Map<Fruit, Integer> getCurrentCounts() {
            return new HashMap<>(fruitToCount);
        }
    }