C#数据结构支持以下内容
本文关键字:数据结构 支持 | 更新日期: 2023-09-27 18:27:20
我需要一个以以下方式工作的C#数据结构:
- 用静态大小定义
- 将新数据添加到列表末尾
- 最旧的数据会减少
- 数据元素的随机访问
示例:如果我定义了一个由5个元素组成的结构,并添加了以下
1,2,3,4,5,6,7,8
数据结构如下所示:
4,5,6,7,8
我不确定哪种结构会以这种方式工作。矢量?列表堆栈数据结构支持像数组这样的静态大小,并支持推送旧数据的数据。
堆栈/队列不提供随机访问。列表没有"推送"操作。
也许是LinkedList并为"push"添加自定义操作,以删除第一个元素?不过,链表随机访问是o(n)操作。
为了最大限度地提高效率,这可能是一个实现循环缓冲区的自定义类。
只需在实例化时创建一个固定大小的数组来保存数据。此外,还有一个开始索引、一个大小成员和一个容量,这样您就可以知道缓冲区中有多少数据以及数据从哪里开始。
因此,首先,您的列表不包含任何数据,起始位置为0,大小为0。
添加项目时,它将进入元素(start + size) % capacity
,如果size
还不在capacity
,则它将递增。如果在capacity
时为,则也可以递增start
,如果需要,则环绕为:start = (start + 1) % capacity
。
要从列表中获得索引为n
的元素,实际上可以使用start
:对其进行调整
return element[(start + n) % capacity];
我还没有谈到删除列表的开头,因为这不在你的规格中。然而,这是一个简单的检查,以确保size
不是0,然后在element[start]
提取项目,然后用上面显示的相同环绕来递增start
。
在伪代码中(未经测试但应接近):
def listNew (capacity):
me = new object
me.capacity = capacity
me.data = new array[capacity]
me.start = 0
me.size = 0
return me
def listAdd (me, item):
if me.size = me.capacity:
me.data[me.start] = item
me.start = (me.start + 1) % me.capacity
else:
me.data[(me.start + me.size) % me.capacity] = item
me.size = me.size + 1
def listGet (me, index):
if index > size:
return 0 # or raise error of some sort
return me.data[(me.start + index) % me.capacity]
def listRemove (me):
if size == 0:
return 0 # or raise error of some sort
item = me.data[(me.start + index) % me.capacity]
me.start = (me.start + 1) % me.capacity
me.size = me.size - 1
return item
根据要求,所有这些操作都具有O(1)时间复杂性。
对于将数字1
到8
添加到五元素列表的特定示例,您将得到:
0 1 2 3 4 <--- index
+---+---+---+---+---+
| 6 | 7 | 8 | 4 | 5 |
+---+---+---+---+---+
^
+--------- start = 3
size = 5
capacity = 5
这样,从缓冲区中提取虚拟索引3(第四个数字)会得到一个实际索引:
(start + 3) % capacity
= ( 3 + 3) % 5
= 6 % 5
= 1
这是一个最大长度的队列(因此,一旦达到最大长度,您必须先取消队列并丢弃一个元素,然后再对另一个元素进行排队)。你可以对C#队列进行随机访问,但它是O(n)(使用ElementAt LINQ扩展),如果5是一个典型的大小,这可能不是一个真正的问题。如果你想要O(1),我怀疑你必须自己滚(https://github.com/mono/mono/blob/master/mcs/class/System/System.Collections.Generic/Queue.cs?source=cc可能会有所帮助!)
Queue在这种情况下是最好的,您应该编写自己的包装类,在Enqueue(将新数据添加到列表末尾)之前检查您的计数(限制),使其表现得像一个固定的计数,这里有一个示例:
public class FixedQueue<T> : Queue<T>
{
//to sets the total number of elements that can be carried without resizing,
//we called the base constrctor that takes the capacity
private Random random;
public int Size { get; private set; }
public FixedQueue(int size, Random random)
:base(size)
{
this.Size = size;
this.random = random;
}
public new void Enqueue(T element)
{
base.Enqueue(element);
lock (this)
while (base.Count > Size)
base.Dequeue(); //as you said, "Oldest data falls off" :)
}
public T RandomAcess()
{
return this.ElementAt(random.Next(Count));
}
}