이것은 귀하의 질문에 대한 답은 아니지만 컬렉션에서 Contains ()의 성능을 향상시키는 클래스가 있습니다. 큐를 서브 클래 싱하고 해시 코드를 객체 목록에 매핑하는 사전을 추가했습니다. Dictionary.Contains()
함수는 O (1) 인 반면 List.Contains()
, Queue.Contains()
및 Stack.Contains()
O (N)를한다.
사전의 값 유형은 동일한 해시 코드를 가진 객체를 보유하는 대기열입니다. 호출자는 IEqualityComparer를 구현하는 사용자 지정 클래스 개체를 제공 할 수 있습니다. 이 패턴을 스택 또는 목록에 사용할 수 있습니다. 코드는 몇 가지만 변경하면됩니다.
private class HashQueue<T> : Queue<T>
{
private readonly IEqualityComparer<T> _comp;
public readonly Dictionary<int, Queue<T>> _hashes;
public HashQueue(IEqualityComparer<T> comp = null) : base()
{
this._comp = comp;
this._hashes = new Dictionary<int, Queue<T>>();
}
public HashQueue(int capacity, IEqualityComparer<T> comp = null) : base(capacity)
{
this._comp = comp;
this._hashes = new Dictionary<int, Queue<T>>(capacity);
}
public HashQueue(IEnumerable<T> collection, IEqualityComparer<T> comp = null) : base(collection)
{
this._comp = comp;
this._hashes = new Dictionary<int, Queue<T>>(base.Count);
foreach (var item in collection)
{
this.EnqueueDictionary(item);
}
}
public new void Enqueue(T item)
{
base.Enqueue(item);
this.EnqueueDictionary(item);
}
private void EnqueueDictionary(T item)
{
int hash = this._comp == null ? item.GetHashCode() : this._comp.GetHashCode(item);
Queue<T> temp;
if (!this._hashes.TryGetValue(hash, out temp))
{
temp = new Queue<T>();
this._hashes.Add(hash, temp);
}
temp.Enqueue(item);
}
public new T Dequeue()
{
T result = base.Dequeue();
int hash = this._comp == null ? result.GetHashCode() : this._comp.GetHashCode(result);
Queue<T> temp;
if (this._hashes.TryGetValue(hash, out temp))
{
temp.Dequeue();
if (temp.Count == 0)
this._hashes.Remove(hash);
}
return result;
}
public new bool Contains(T item)
{
int hash = this._comp == null ? item.GetHashCode() : this._comp.GetHashCode(item);
return this._hashes.ContainsKey(hash);
}
public new void Clear()
{
foreach (var item in this._hashes.Values)
item.Clear();
this._hashes.Clear();
base.Clear();
}
}
내 간단한 테스트는 내 HashQueue.Contains()
실행이 Queue.Contains()
. 개수를 10,000으로 설정하여 테스트 코드를 실행하면 HashQueue 버전의 경우 0.00045 초, Queue 버전의 경우 0.37 초가 걸립니다. 100,000의 카운트를 사용하면 HashQueue 버전은 0.0031 초, 대기열은 36.38 초가 걸립니다!
내 테스트 코드는 다음과 같습니다.
static void Main(string[] args)
{
int count = 10000;
{
var q = new HashQueue<int>(count);
for (int i = 0; i < count; i++)
q.Enqueue(i);
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
bool contains = q.Contains(i);
}
sw.Stop();
Console.WriteLine(string.Format("HashQueue, {0}", sw.Elapsed));
}
{
var q = new Queue<int>(count);
for (int i = 0; i < count; i++)
q.Enqueue(i);
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
bool contains = q.Contains(i);
}
sw.Stop();
Console.WriteLine(string.Format("Queue, {0}", sw.Elapsed));
}
Console.ReadLine();
}