.NET源码中的HashSet<T>

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

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值