我有一系列时间敏感的项目。一段时间后,最后一个项目需要脱落,并在开始时放置一个新项目。
做这个的最好方式是什么?
我建议使用队列,只是数组或列表的一个特殊实例。当您的定时事件发生时,从队列中弹出最后一个项目,然后推送您的新项目。
使用数组执行此操作的最简单方法可能是使用循环索引。与其总是查看 array[n],不如引用 array[cIndex](其中 cIndex 指的是数组中被索引的项目(cIndex 基于 arraySize (cIndex % arraySize) 递增)。
当您选择删除数组中最旧的项目时,您只需引用位于 ((cIndex + (arraySize - 1)) % arraySize) 的元素。
或者,您可以使用linkedList 方法。
请改用队列。
通过使用队列,最好使用链表实现。
看看使用队列而不是简单的数组。
如果有固定数量的项目,队列将起作用。
鉴于“时间量”是已知的,那么如何使用具有 DateTime 键的 SortedDictionary 并覆盖 Add 方法以删除所有具有太旧键的项目。
LinkedList<T>具有应该可以完美运行的 AddFirst 和 RemoveLast 成员。
编辑:查看 Queue 文档,他们似乎使用了内部数组。只要实现使用循环数组类型的算法性能应该没问题。
在 csharp 3 中,您可以执行以下操作:
original = new[] { newItem }.Concat(
original.Take(original.Count() - 1)).ToArray()
但是您最好使用专门的数据结构
Queue
非常适合 FIFO 数组。例如,对于通用数组处理,使用List(T)和
Insert(0, x)
方法RemoveAt(0)
在列表前面放置或删除项目。
从技术上讲,您需要一个双端队列。队列仅在一端推送和弹出项目。双端队列在两端都是开放的。
大多数语言都允许数组操作,只需删除第一个元素并将另一个元素放在最后。
或者,您可以通过循环移动每个元素。只需用它的邻居替换每个元素(从最旧的开始)。然后将新项目放在最后一个元素中。
如果您知道您的双端队列不会超过某个大小,那么您可以将其设为圆形。你需要两个指针来告诉你两端在哪里。添加和删除项目将相应地增加/减少您的指针。您必须检测缓冲区溢出情况(即您的指针“交叉”)。而且您必须使用模运算,以便您的指针围绕数组转一圈。
或者您可以为数组中的每个元素加上时间戳,并在它们变得太“旧”时将其删除。您可以通过保持一个单独的数组以相同的方式索引来实现这一点,或者通过一个由两个元素数组组成的数组,并将时间戳存储在其中一个子元素中。
如果您正在寻找执行此操作的最快方法,它将是一个循环数组:您跟踪数组中的当前位置 (ndx) 和数组的末尾 (end),因此当您插入一个项目,您隐式消除了最旧的项目。
循环数组是我所知道的固定大小队列的最快实现。
例如,在 C/C++ 中,整数看起来像这样(当你得到 0 时退出):
int queue[SIZE];
int ndx=0; // start at the beginning of the array
int end=SIZE-1;
int newitem;
while(1){
cin >> newitem;
if(!newitem) // quit if it's a 0
break;
if(ndx>end) // need to loop around the end of the array
ndx=0;
queue[ndx] = newitem;
ndx++
}
可以做很多优化,但如果你想自己构建它,这是最快的路线。
如果您不关心性能,请使用随附的 Queue 对象,因为它应该是通用的。
它可能会优化也可能不会优化,也可能不支持固定大小的列表,所以在使用之前一定要检查它的文档。