HashSet<T>用来存储一组无指定顺序的对象的集合,特点是高性能。
内部数据结构定义如下:
public class HashSet<T> : ISerializable, IDeserializationCallback, ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable
{
private int[] m_buckets;
private HashSet<T>.Slot[] m_slots;
private int m_count;
private int m_lastIndex;
private int m_freeList;
private const int Lower31BitMask = 2147483647;
private const int StackAllocThreshold = 100;
private const int ShrinkThreshold = 3;
其中Slot结构体的定义如下:
internal struct Slot
{
internal int hashCode;
internal T value;
internal int next;
}
添加新值的实现:
private bool AddIfNotPresent(T value)
{
if (this.m_buckets == null)
this.Initialize(0);
int hashCode = this.InternalGetHashCode(value);
int index1 = hashCode % this.m_buckets.Length;
int num = 0;
for (int index2 = this.m_buckets[hashCode % this.m_buckets.Length] - 1; index2 >= 0; index2 = this.m_slots[index2].next)
{
if (this.m_slots[index2].hashCode == hashCode && this.m_comparer.Equals(this.m_slots[index2].value, value))
return false;
++num;
}
int index3;
if (this.m_freeList >= 0)
{
index3 = this.m_freeList;
this.m_freeList = this.m_slots[index3].next;
}
else
{
if (this.m_lastIndex == this.m_slots.Length)
{
this.IncreaseCapacity();
index1 = hashCode % this.m_buckets.Length;
}
index3 = this.m_lastIndex;
++this.m_lastIndex;
}
this.m_slots[index3].hashCode = hashCode;
this.m_slots[index3].value = value;
this.m_slots[index3].next = this.m_buckets[index1] - 1;
this.m_buckets[index1] = index3 + 1;
++this.m_count;
++this.m_version;
if (num > 100 && HashHelpers.IsWellKnownEqualityComparer((object) this.m_comparer))
{
this.m_comparer = (IEqualityComparer<T>) HashHelpers.GetRandomizedEqualityComparer((object) this.m_comparer);
this.SetCapacity(this.m_buckets.Length, true);
}
return true;
}
其中Initialize()的实现如下:通过HashHelpers类的静态函数GetPrime()函数取一个素数,作为bucket数组和slot数组的初始大小。
private void Initialize(int capacity)
{
int prime = HashHelpers.GetPrime(capacity);
this.m_buckets = new int[prime];
this.m_slots = new HashSet<T>.Slot[prime];
}
GetPrime()的实现如下:
public static int GetPrime(int min)
{
if (min < 0)
throw new ArgumentException(Environment.GetResourceString("Arg_HTCapacityOverflow"));
for (int index = 0; index < HashHelpers.primes.Length; ++index)
{
int num = HashHelpers.primes[index];
if (num >= min)
return num;
}
int candidate = min | 1;
while (candidate < int.MaxValue)
{
if (HashHelpers.IsPrime(candidate) && (candidate - 1) % 101 != 0)
return candidate;
candidate += 2;
}
return min;
}
HashHelpers内置了一组素数:
public static readonly int[] primes = new int[72]
{
3,
7,
11,
17,
23,
29,
37,
47,
59,
71,
89,
107,
131,
163,
197,
239,
293,
353,
431,
521,
631,
761,
919,
1103,
1327,
1597,
1931,
2333,
2801,
3371,
4049,
4861,
5839,
7013,
8419,
10103,
12143,
14591,
17519,
21023,
25229,
30293,
36353,
43627,
52361,
62851,
75431,
90523,
108631,
130363,
156437,
187751,
225307,
270371,
324449,
389357,
467237,
560689,
672827,
807403,
968897,
1162687,
1395263,
1674319,
2009191,
2411033,
2893249,
3471899,
4166287,
4999559,
5999471,
7199369
};
而判断一个数是否为素数的函数如下:
public static bool IsPrime(int candidate)
{
if ((candidate & 1) == 0)
return candidate == 2;
int num1 = (int) Math.Sqrt((double) candidate);
int num2 = 3;
while (num2 <= num1)
{
if (candidate % num2 == 0)
return false;
num2 += 2;
}
return true;
}
InternalGetHashCode的实现是根据不同类型调用相关的GetHashCode函数与int.MaxValue做&运算,参考.NET中基本数据类型的GetHashCode
private int InternalGetHashCode(T item)
{
if ((object) item == null)
return 0;
else
return this.m_comparer.GetHashCode(item) & int.MaxValue;
}
当达到容限时,需要扩容:
private void IncreaseCapacity()
{
int newSize = HashHelpers.ExpandPrime(this.m_count);
if (newSize <= this.m_count)
throw new ArgumentException(SR.GetString("Arg_HSCapacityOverflow"));
this.SetCapacity(newSize, false);
}
private void SetCapacity(int newSize, bool forceNewHashCodes)
{
HashSet<T>.Slot[] slotArray = new HashSet<T>.Slot[newSize];
if (this.m_slots != null)
Array.Copy((Array) this.m_slots, 0, (Array) slotArray, 0, this.m_lastIndex);
if (forceNewHashCodes)
{
for (int index = 0; index < this.m_lastIndex; ++index)
{
if (slotArray[index].hashCode != -1)
slotArray[index].hashCode = this.InternalGetHashCode(slotArray[index].value);
}
}
int[] numArray = new int[newSize];
for (int index1 = 0; index1 < this.m_lastIndex; ++index1)
{
int index2 = slotArray[index1].hashCode % newSize;
slotArray[index1].next = numArray[index2] - 1;
numArray[index2] = index1 + 1;
}
this.m_slots = slotArray;
this.m_buckets = numArray;
}
查找某个数据是否存在于hashset中的实现如下:
public bool Contains(T item)
{
if (this.m_buckets != null)
{
int hashCode = this.InternalGetHashCode(item);
for (int index = this.m_buckets[hashCode % this.m_buckets.Length] - 1; index >= 0; index = this.m_slots[index].next)
{
if (this.m_slots[index].hashCode == hashCode && this.m_comparer.Equals(this.m_slots[index].value, item))
return true;
}
}
return false;
}
删除某个数据的实现:
public bool Remove(T item)
{
if (this.m_buckets != null)
{
int hashCode = this.InternalGetHashCode(item);
int index1 = hashCode % this.m_buckets.Length;
int index2 = -1;
for (int index3 = this.m_buckets[index1] - 1; index3 >= 0; index3 = this.m_slots[index3].next)
{
if (this.m_slots[index3].hashCode == hashCode && this.m_comparer.Equals(this.m_slots[index3].value, item))
{
if (index2 < 0)
this.m_buckets[index1] = this.m_slots[index3].next + 1;
else
this.m_slots[index2].next = this.m_slots[index3].next;
this.m_slots[index3].hashCode = -1;
this.m_slots[index3].value = default (T);
this.m_slots[index3].next = this.m_freeList;
--this.m_count;
++this.m_version;
if (this.m_count == 0)
{
this.m_lastIndex = 0;
this.m_freeList = -1;
}
else
this.m_freeList = index3;
return true;
}
else
index2 = index3;
}
}
return false;
}
导出到数组的实现:
public void CopyTo(T[] array, int arrayIndex, int count)
{
if (array == null)
throw new ArgumentNullException("array");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException("arrayIndex", SR.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", SR.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (arrayIndex > array.Length || count > array.Length - arrayIndex)
throw new ArgumentException(SR.GetString("Arg_ArrayPlusOffTooSmall"));
int num = 0;
for (int index = 0; index < this.m_lastIndex && num < count; ++index)
{
if (this.m_slots[index].hashCode >= 0)
{
array[arrayIndex + num] = this.m_slots[index].value;
++num;
}
}
}
以上