.NET源码中的HashSet<T>

来源:互联网 发布:个人网盘网站源码 编辑:程序博客网 时间:2024/05/23 12:55

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;        }      }    }

以上

0 0
原创粉丝点击