Java HashMap

首先是前面一些英文的翻译

hashtable基于map接口的实现,这个实现提供了map所有可选的操作,并且允许null值和null键。hashmap类和hashtable大致相同,除了hashmap是非同步的,并且hashmap是允许null的。这类不保证map中键值对的顺序,不保证map中的顺序
假设hash函数把元素分散到各个桶里,这个类的基础操作(get/put)只需要常量级的操作时间。对集合视图的迭代需要与实例的“容量”(桶的数量)加上其大小(键值映射的数量)成比例的时间。所以,如果迭代效率很重要的话,不要把初始容量设的太大,也不要把load factor设的太小。
一个hashmap的实例的初始容量和加载因子影响着它的性能。容量是哈希表的桶数量,初始容量就是哈希表建立时的容量。加载因子代表哈希表装到多满时进行扩容。当哈希表中项的数量超出加载因子乘以当前容量的乘积,哈希表会进行重新哈希(哈希表内部结构会变化),为了让哈希表的桶数量翻倍。
通常的规则是,默认加载因子是0.75,这在时间和空间之间是比较好的一个平衡。更高的值降低了空间花销但是提高了寻找的开销(反应在hashmap中最多的操作 get和put)。在设置初始容量时应考虑希望存储在map内的元素数量和加载因子,为了最小化重新哈希的次数。如果初始容量 > (元素的最大数量 / 加载因子)将不会发生重新哈希
如果要把很多键值对存在hashmap中,应该在创建时设置足够大的初始容量,这样可以更有效的存储,避免了在容器增长时多次重新哈希操作。使用大量相同的key毫无疑问会降低任何哈希表的时间表现。为了渐少影响,当key可以比较的时候,hashmap将会使用比较顺序来帮助打破关系。
这实现是不同步的。如果多线程同时访问一个hashmap,并且至少一个线程会改变结构,必须保证在外部同步(结构修改就是任何会增加或删除键值对的操作,只是改变了key对应的值不是改变结构)这通常用包含着map的对象实现同步。
如果不存在这对象,map应该包在{Collections#synchronizedMap Collections.synchronizedMap}方法里面。最好是在创建的时候,为了避免偶然对map的不同步访问
Map m = Collections.synchronizedMap(new HashMap(...))

该类返回的所有迭代器都是 “快失败” 的,如果创建了迭代器后map遇到了结构性改变,调用除了迭代器自己的删除方法以外的方法,将会抛出ConcurrentModificationException异常。因此,面对同步操作,迭代器迅速干净的失效,而不是在未来的未确定时间冒任意,非确定性行为的风险。
请注意,迭代器的快速失败行为无法保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。快速失败的迭代器在最好的情况下抛出ConcurrentModificationException异常。因此,因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应仅用于debug
 

此映射通常用作分区(分区)哈希表,但是当分区变得太大时,它们将转换为TreeNodes的分区,每个分区的结构与java.util.TreeMap中的类似。大多数方法尝试使用普通的bin,但在适用时中继到TreeNode方法(只需检查节点的实例)。 TreeNodes的Bin可以像其他任何一样遍历和使用,但是当人口过多时还支持更快的查找。但是,由于正常使用的绝大多数垃圾箱都不是人口过多,因此在表格方法的过程中可能会延迟检查树箱的存在。

树容器(即,其元素都是TreeNodes的容器)主要由hashCode排序,但在tie的情况下,如果两个元素具有相同的“C类实现Comparable <C>”,则键入然后将其compareTo方法用于排序。 (我们保守地通过反射检查泛型类型以验证这一点 - 请参阅方法equivalentClassFor)。当密钥具有不同的哈希值或可订购时,增加树容器的复杂性对于提供最坏情况的O(log n)操作是值得的。因此,在hashCode()方法返回值很差的偶然或恶意用法中,性能会优雅地降级分布式,以及许多密钥共享hashCode的那些,只要它们也是可比较的。 (如果这些都不适用,与不采取任何预防措施相比,我们可能在时间和空间上浪费大约两倍。但是,唯一已知的情况源于糟糕的用户编程实践,这些实践已经非常缓慢,这几乎没有什么区别。)

由于TreeNodes的大小约为常规节点的两倍,因此只有当bin包含足够的节点以保证使用时,我们才使用它们(请参阅TREEIFY_THRESHOLD)。当它们变得太小(由于移除或调整大小)时,它们会转换回普通箱。在具有良好分布的用户hashCodes的用法中,很少使用树容器。理想情况下,在随机hashCodes下,bin中节点的频率遵循泊松分布(http://en.wikipedia.org/wiki/Poisson_distribution),参数平均值约为0.5,默认调整阈值为0.75,尽管由于调整粒度而导致的大差异。忽略方差,列表大小k的预期出现是(exp(-0.5)* pow(0.5,k)/ factorial(k))。第一个值是:

0:0.60653066
1:0.30326533
2:0.07581633
3:0.01263606
4:0.00157952
5:0.00015795
6:0.00001316
7:0.00000094
8:0.00000006
更多:不到千万分之一

树bin的根通常是它的第一个节点。但是,有时(目前仅在Iterator.remove上),根可能在其他地方,但可以在父链接之后恢复(方法TreeNode.root())。
 
所有适用的内部方法都接受哈希码作为参数(通常从公共方法提供),允许它们相互调用而无需重新计算用户hashCodes。大多数内部方法也接受“tab”参数,通常是当前表,但在调整或转换时可能是新的或旧的。

当bin列表被树化,拆分或未解析时,我们将它们保持在相同的相对访问/遍历顺序(即,字段Node.next)中以更好地保留局部性,并略微简化对调用iterator.remove的拆分和遍历的处理。在插入时使用比较器时,为了保持整个重新排序的总排序(或者尽可能接近),我们将类和identityHashCodes作为绑定器进行比较。

普通vs树模式之间的使用和转换由于子类LinkedHashMap的存在而变得复杂。请参阅下面的钩子方法,这些钩子方法定义为在插入,删除和访问时调用,允许LinkedHashMap内部以其他方式保持独立于这些机制。 (这也要求将地图实例传递给可能创建新节点的一些实用程序方法。)

类似于并发编程的基于SSA的编码风格有助于避免在所有扭曲指针操作中出现混叠错误。

(以上翻译很大一部分用Google翻译完成 有空有时间再直接翻吧 下面讲代码了)

前面的代码先是讲了一些变量

DEFAULT_INITIAL_CAPACITY// 默认的初始容量,必须是2的幂
MAXIMUM_CAPACITY//最大容量,必须是2的幂且少于1<<30
DEFAULT_LOAD_FACTOR//默认的加载因子
TREEIFY_THRESHOLD//当桶里的数量超过这阈值时,桶里的结构变成树
UNTREEIFY_THRESHOLD//当桶里的数量少于这阈值,从树变回线性
MIN_TREEIFY_CAPACITY//当表里的数量超过这阈值,表里的结构变成树

然后声明静态内部类Node<K,V> implements Map.Entry<K,V>,提供一些基本的get set toString方法

hashCode方法返回的值是用key的hash值做基数,value的hash值做幂
equals方法先判断传入对象是否和this是同一个对象,是就返回true,如果不是再判断key和value的hash值是否同时相等,同时相等返回true,否则返回false
然后是static final方法hash,传入对象,如果对象为null则返回0,否则返回(对象本身的hashcode值 ^ hashcode >>> 16);所以如果对象的hashcode没有16位,那么肯定是返回1

然后是comparableClassFor函数,没有看懂,注释说返回对象实现的可比较接口,从而可以调用接口的compareTo函数来对两个对象做比较,从而判断大小,如果对象没有实现可比较接口返回null

方法compareComparables,传入一个可比较泛型类和两个对象,第一个对象是泛型类的实例,如果第二个对象为null或不是泛型类的实例返回0(意味着相等)否则用第一个对象调用compareTo和第二个对象做比较关于比较函数有说明(一个负整数,零或正整数,因为此对象小于,等于或大于指定的对象。)

函数tableSizeFor一段非常骚的进位操作,传入希望得到的容量,返回比这容量大的最小的二的幂(待我学成归来再仔细看看这段代码的玄机)

变量transient Node<K,V>[] table;长度必须是2的幂,会根据需要调整大小,这里的node就是上面声明的静态类

注释说是装缓存的transient Set<Map.Entry<K,V>> entrySet;

还有表示当前map里元素数量的transient int size;

注释说是表示hashmap结构修改次数的transient int modCount;

表示下一次扩容的阈值int threshold;

加载因子final float loadFactor;

 

然后就到public方法辣

 

 

 

内容概要:本文针对国内加密货币市场预测研究较少的现状,采用BP神经网络构建了CCi30指数预测模型。研究选取2018年3月1日至2019年3月26日共391天的数据作为样本,通过“试凑法”确定最优隐结点数目,建立三层BP神经网络模型对CCi30指数收盘价进行预测。论文详细介绍了数据预处理、模型构建、训练及评估过程,包括数据归一化、特征工程、模型架构设计(如输入层、隐藏层、输出层)、模型编译与训练、模型评估(如RMSE、MAE计算)以及结果可视化。研究表明,该模型在短期内能较准确地预测指数变化趋势。此外,文章还讨论了隐层节点数的优化方法及其对预测性能的影响,并提出了若干改进建议,如引入更多技术指标、优化模型架构、尝试其他时序模型等。 适合人群:对加密货币市场预测感兴趣的研究人员、投资者及具备一定编程基础的数据分析师。 使用场景及目标:①为加密货币市场投资者提供一种新的预测工具和方法;②帮助研究人员理解BP神经网络在时间序列预测中的应用;③为后续研究提供改进方向,如数据增强、模型优化、特征工程等。 其他说明:尽管该模型在短期内表现出良好的预测性能,但仍存在一定局限性,如样本量较小、未考虑外部因素影响等。因此,在实际应用中需谨慎对待模型预测结果,并结合其他分析工具共同决策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值