如果我理解正确(如果我错了请纠正我),list是由.NET中的数组实现的,这意味着列表中每个项目的删除都会导致重新分配所有列表(反过来意味着O(n)
)。
我正在开发一款游戏,在游戏中我有很多子弹在任何给定时刻在空中飞行,让我们说100个子弹,每帧我移动它们几个像素并检查与游戏中物体的碰撞,我需要从列表中删除每个碰撞的子弹。
所以我在另一个临时列表中收集碰撞的子弹,然后执行以下操作:
foreach (Bullet bullet in bulletsForDeletion)
mBullets.Remove(bullet);
由于循环为O(n)
且删除为O(n)
,因此我需要花费O(n^2
}时间来删除。
有没有更好的方法可以删除它,或者使用更合适的集合?
答案 0 :(得分:6)
设置和链接列表都具有恒定的时间删除。你能使用这些数据结构吗?
无法避免从List<T>
中移除O(N)费用。如果这对您来说是个问题,您将需要使用不同的数据结构。这可能会使计算bulletsToRemove的代码感觉更好。
ISet<T>
有很好的方法来计算对象集之间的差异和交叉点。
你使用套装丢失了订单,但鉴于你正在使用子弹,我猜这不是问题。你仍然可以在不变的时间内枚举它。
在您的情况下,您可以写:
mBullets.ExceptWith(bulletsForDeletion);
答案 1 :(得分:4)
创建新列表:
var newList = `oldList.Except(deleteItems).ToList()`.
尝试尽可能使用功能习语。不要修改现有的数据结构,创建新的数据结构。
由于散列,该算法为O(N)。
答案 2 :(得分:2)
你不能只从List
(相当于Java的ArrayList
突出显示那个)切换到LinkedList
吗? LinkedList使用O(1)删除特定元素,但O(n)删除索引
答案 3 :(得分:1)
如何在内部实施列表并不是您应该考虑的事情。您应该与该抽象级别中的列表进行交互。
如果您确实遇到了性能问题,并将其精确定位到列表中,那么现在是时候了解它是如何实现的。
至于从列表中删除项目 - 您可以使用mBullets.RemoveAll(predicate)
,其中predicate
是标识已发生冲突的项目的表达式。
答案 4 :(得分:1)
RemoveAt(int index)
比Remove(T item)
快,因为后者使用第一个内部进行反射,这是每个函数中的代码。
此外,Remove(T)
具有函数IndexOf
,其中包含第二个循环以评估每个项目的索引。
public bool Remove(T item)
{
int index = this.IndexOf(item);
if (index < 0)
return false;
this.RemoveAt(index);
return true;
}
public void RemoveAt(int index)
{
if ((uint) index >= (uint) this._size)
ThrowHelper.ThrowArgumentOutOfRangeException();
--this._size;
if (index < this._size)
Array.Copy((Array) this._items, index + 1, (Array) this._items, index, this._size - index);
this._items[this._size] = default (T);
++this._version;
}
我会做这样的循环:
for (int i=MyList.Count-1; i>=0; i--)
{
// add some code here
if (needtodelete == true)
MyList.RemoveAt(i);
}
答案 5 :(得分:0)
根据“usr”建议的功能习语的精神,您可能会考虑不从列表中删除。相反,让您的更新例程采用列表并返回列表。返回的列表仅包含“仍然活着”的对象。然后,您可以在游戏循环结束时交换列表(或者,如果适用,立即交换)。我自己就是这样做的。