命名空间:System.Collections.Generic

先看一下官方说明:类提供了高级的设置操作。集是不包含重复元素的集合,其元素无特定顺序。

HashSet <T>对象的容量是对象可以容纳的元素数。当向对象添加元素时,HashSet <T>对象的容量会自动增加。

HashSet<String> hashSet = new HashSet<string>();
hashSet.Add("test");
hashSet.Add("test");
Console.WriteLine(hashSet.Count);

打印结果:1

HashSet的默认构造方法:

public HashSet()
: this((IEqualityComparer<T>?)null)
{ }

注:: this语法为调用自身对象的其他构造方法。

public HashSet(IEqualityComparer<T>? comparer)
{
if (comparer == EqualityComparer<T>.Default)
{
comparer = null;
}
_comparer = comparer;
_lastIndex = ;
_count = ;
_freeList = -;
_version = ;
}

第二中创建方式,将集合作为参数。

List<string> list = new List<string>();
list.Add("test");
list.Add("test");
HashSet<string> hSet = new HashSet<string>(list);
Console.WriteLine(hSet.Count);

此时控台输出:1

此时调用的构造方法为:

public HashSet(IEnumerable<T> collection, IEqualityComparer<T>? comparer)
: this(comparer)
{
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
var otherAsHashSet = collection as HashSet<T>;
if (otherAsHashSet != null && AreEqualityComparersEqual(this, otherAsHashSet))
{
CopyFrom(otherAsHashSet);
}
else
{
// to avoid excess resizes, first set size based on collection's count. Collection
// may contain duplicates, so call TrimExcess if resulting hashset is larger than
// threshold
ICollection<T>? coll = collection as ICollection<T>;
int suggestedCapacity = coll == null ? : coll.Count;
Initialize(suggestedCapacity);
UnionWith(collection);
if (_count > && _slots.Length / _count > ShrinkThreshold)
{
TrimExcess();
}
}
}

在该构造方法中若存在重复值则通过查找大于或等于容量的下一个质数来使用建议的容量。

private int Initialize(int capacity)
{
Debug.Assert(_buckets == null, "Initialize was called but _buckets was non-null");
int size = HashHelpers.GetPrime(capacity);
_buckets = new int[size];
_slots = new Slot[size];
return size;
}

下面为生成质数方法:

public static int GetPrime(int min)
{
if (min < )
throw new ArgumentException(SR.Arg_HTCapacityOverflow);
foreach (int prime in s_primes)
{
if (prime >= min)
return prime;
}
// Outside of our predefined table. Compute the hard way.
for (int i = (min | ); i < int.MaxValue; i += )
{
if (IsPrime(i) && ((i - ) % HashPrime != ))
return i;
}
return min;
}

再次扩展-》

public static bool IsPrime(int candidate)
{
if ((candidate & ) != )
{
int limit = (int)Math.Sqrt(candidate);//取平方
for (int divisor = ; divisor <= limit; divisor += )
{
if ((candidate % divisor) == )
return false;
}
return true;
}
return candidate == ;
}
internal struct Slot
{
internal int hashCode; // Lower 31 bits of hash code, -1 if unused
internal int next; // Index of next entry, -1 if last
internal T value;
}

存储LIst集合:

public void UnionWith(IEnumerable<T> other)
{
if (other == null)
{
throw new ArgumentNullException(nameof(other));
}
foreach (T item in other)
{
AddIfNotPresent(item);
}
}

继续往下追踪:

private bool AddIfNotPresent(T value)
{
if (_buckets == null)
{
Initialize();
} int hashCode;
int bucket;
int collisionCount = ;
Slot[] slots = _slots; IEqualityComparer<T>? comparer = _comparer; if (comparer == null)
{
//取HASHCODE
hashCode = value == null ? : InternalGetHashCode(value.GetHashCode());
bucket = hashCode % _buckets!.Length; if (default(T)! != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
{
for (int i = _buckets[bucket] - ; i >= ; i = slots[i].next)
{
if (slots[i].hashCode == hashCode && EqualityComparer<T>.Default.Equals(slots[i].value, value))
{
return false;
} if (collisionCount >= slots.Length)
{
// The chain of entries forms a loop, which means a concurrent update has happened.
throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
}
collisionCount++;
}
}
else
{
// Object type: Shared Generic, EqualityComparer<TValue>.Default won't devirtualize
// https://github.com/dotnet/coreclr/issues/17273
// So cache in a local rather than get EqualityComparer per loop iteration
EqualityComparer<T> defaultComparer = EqualityComparer<T>.Default; for (int i = _buckets[bucket] - ; i >= ; i = slots[i].next)
{
if (slots[i].hashCode == hashCode && defaultComparer.Equals(slots[i].value, value))
{
return false;
} if (collisionCount >= slots.Length)
{
// The chain of entries forms a loop, which means a concurrent update has happened.
throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
}
collisionCount++;
}
}
}
else
{
hashCode = value == null ? : InternalGetHashCode(comparer.GetHashCode(value));
bucket = hashCode % _buckets!.Length; for (int i = _buckets[bucket] - ; i >= ; i = slots[i].next)
{
if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value))
{
return false;
} if (collisionCount >= slots.Length)
{
// The chain of entries forms a loop, which means a concurrent update has happened.
throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
}
collisionCount++;
}
} int index;
if (_freeList >= )
{
index = _freeList;
_freeList = slots[index].next;
}
else
{
if (_lastIndex == slots.Length)
{
IncreaseCapacity();
// this will change during resize
slots = _slots;
bucket = hashCode % _buckets.Length;
}
index = _lastIndex;
_lastIndex++;
}
slots[index].hashCode = hashCode;
slots[index].value = value;
slots[index].next = _buckets[bucket] - ;
_buckets[bucket] = index + ;
_count++;
_version++; return true;
}
private const int Lower31BitMask = 0x7FFFFFFF;

获取内部的HASHCODE

private static int InternalGetHashCode(T item, IEqualityComparer<T>? comparer)
{
if (item == null)
{
return ;
}
int hashCode = comparer?.GetHashCode(item) ?? item.GetHashCode();
return hashCode & Lower31BitMask;
}

划重点-》

slots[index].hashCode = hashCode;
slots[index].value = value;
slots[index].next = _buckets[bucket] - ;

最终列表中的值存储到结构中。

使用对象初始化HASHSET时,如果相同

HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("test");
hashSet.Add("test");
HashSet<string> hSet = new HashSet<string>(hashSet);
private void CopyFrom(HashSet<T> source)
{
int count = source._count;
if (count == )
{
// As well as short-circuiting on the rest of the work done,
// this avoids errors from trying to access otherAsHashSet._buckets
// or otherAsHashSet._slots when they aren't initialized.
return;
} int capacity = source._buckets!.Length;
int threshold = HashHelpers.ExpandPrime(count + ); if (threshold >= capacity)
{
_buckets = (int[])source._buckets.Clone();
_slots = (Slot[])source._slots.Clone(); _lastIndex = source._lastIndex;
_freeList = source._freeList;
}
else
{
int lastIndex = source._lastIndex;
Slot[] slots = source._slots;
Initialize(count);
int index = ;
for (int i = ; i < lastIndex; ++i)
{
int hashCode = slots[i].hashCode;
if (hashCode >= )
{
AddValue(index, hashCode, slots[i].value);
++index;
}
}
Debug.Assert(index == count);
_lastIndex = index;
}
_count = count;
}
public static int ExpandPrime(int oldSize)//返回要增长到的哈希表大小
{
int newSize = * oldSize; // Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
{
Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
return MaxPrimeArrayLength;
} return GetPrime(newSize);
}

这里只贴出HashSet声明创建对象的两种方式。

下篇再研究具体实现〜

DotNet源码学习-HASHSET(初探)的更多相关文章

  1. 从JDK源码学习HashSet和HashTable

    HashSet Java中的集合(Collection)有三类,一类是List,一类是Queue,再有一类就是Set. 前两个集合内的元素是有序的,元素可以重复:最后一个集合内的元素无序,但元素不可重 ...

  2. DotNet 源码学习——QUEUE

    1.Queue声明创建对象.(Queue为泛型对象.) public class Queue<T> :IEnumerable<T>,System.Collections.ICo ...

  3. HashSet源码学习,基于HashMap实现

    HashSet源码学习 一).Set集合的主要使用类 1). HashSet 基于对HashMap的封装 2). LinkedHashSet 基于对LinkedHashSet的封装 3). TreeS ...

  4. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

  5. Django 源码小剖: 初探 WSGI

    Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...

  6. Dubbo源码学习--注册中心分析

    相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 注册中心 关于注册中心,Dubbo提供了多个实现方式,有比较成熟的使用zookeeper 和 redis 的 ...

  7. 【iScroll源码学习01】准备阶段 - 叶小钗

    [iScroll源码学习01]准备阶段 - 叶小钗 时间 2013-12-29 18:41:00 博客园-原创精华区 原文  http://www.cnblogs.com/yexiaochai/p/3 ...

  8. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

  9. mybatis源码学习:插件定义+执行流程责任链

    目录 一.自定义插件流程 二.测试插件 三.源码分析 1.inteceptor在Configuration中的注册 2.基于责任链的设计模式 3.基于动态代理的plugin 4.拦截方法的interc ...

随机推荐

  1. Java单体应用 - Markdown - 03.高级技巧

    原文地址:http://www.work100.net/training/monolithic-markdown-advance.html 更多教程:光束云 - 免费课程 高级技巧 序号 文内章节 视 ...

  2. noip2018 考前提醒!

    适应Noilinux 1.终端操作 打开终端 \(Ctrl+Alt+T\) 打开文件夹 \(cd\) +名称 新建文件夹 \(mkdir\) +名称 打开 \(vim\) 配置 \(vim ~/.vi ...

  3. .NET 框架设计 - 模式、配置、工具 Demo 搜索

    ps:http://www.ituring.com.cn/article/195770 看完第二章,我也忍了!但是随着第三章“副本”的开启,我的阅读速度开始慢慢的减缓,虽然对其中每一个程序模式的理论也 ...

  4. List容器排序方法的使用

    今天在做任务的时候需要对已经存到list容器里的对象数组进行排序,需要根据 其中的一个属性进行排序,最初是根据一个利用冒泡排序的算法进行处理的后来上网查了一下对于list容器进行排序时有自带的方法.所 ...

  5. 暑假第五周总结(学习HBASE相关知识)

    本周主要对HBASE的相关知识进行了学习,主要是通过视频的讲解了解到了HBASE的存储机制,HBASE的机制与普通的关系型数据库完全不同,HBASE以列进行存储,其主要执行的就是增删查操作,其更改主要 ...

  6. 使用npm发布、查看、引用、删除自己的包[小白推荐]

    前言  怎么使用npm发布自己的组件包呢?博主看了不少相关的文章,都没有一个好的讲述.要么丢三落四,要么就是复杂到外行人根本看不懂,甚至无从下手.于是,在博主的潜心钻研下,终于成功了!所以,我打算写一 ...

  7. qt5实现简单布局

    layout.h #ifndef LAYOUT_H #define LAYOUT_H #include <QtWidgets/QDialog> #include <QLabel> ...

  8. CentOS 使用yum安装 pip

    pip这个功能很不错,可以用来下载很多东西. 笔者使用的是CentOS Linux release 7.2.1511 (Core)这个版本. 查询版本的语句: cat /etc/redhat-rele ...

  9. LeetCode227:基本计算器II

    感觉自己的思路还不错,比较简单清晰,代码量也比较少,没有用到记录运算符的变量或栈,就想把这个思路发一下博客. 题目: 实现一个基本的计算器来计算一个简单的字符串表达式的值. 字符串表达式仅包含非负整数 ...

  10. Codeforces_731_A

    http://codeforces.com/problemset/problem/731/A 每次操作总共4种情况,判断一下就好了. #include<iostream> #include ...