下面是一个基本的堆排序的Java代码示例:
1 | import java.util.Arrays; |
在这个示例中,heapSort
方法使用堆排序算法对整数数组进行排序。首先,构建一个最大堆,然后将根节点(最大值)与最后一个节点交换,然后再重新堆化剩余的部分。重复这个过程,直到整个数组有序。
下面是一个基本的堆排序的Java代码示例:
1 | import java.util.Arrays; |
在这个示例中,heapSort
方法使用堆排序算法对整数数组进行排序。首先,构建一个最大堆,然后将根节点(最大值)与最后一个节点交换,然后再重新堆化剩余的部分。重复这个过程,直到整个数组有序。
基数排序(Radix Sort)是一种非比较性的排序算法,它将数据按照位数逐个分配到不同的桶中,从而实现排序。以下是一个基数排序的Java代码示例:
1 | import java.util.Arrays; |
在这个示例中,radixSort
方法使用基数排序算法来对整数数组进行排序。首先,找到数组中的最大值以确定需要进行几轮排序(根据位数)。然后,通过 countingSortByDigit
方法对数组按照当前位上的数字进行计数排序。最后,将排序后的结果拷贝回原始数组。
MD5 和SHA-1 是目前使用比较广泛的散列(Hash)函数,也是在消息认证和数字签名中普遍使用的两种加密算法。本文基于AVR 高速嵌入式单片机,实现了MD5和SHA-1 两种加密算法的比较,并对算法进行了汇编语言的优化和改进。根据实验结果,对两种算法的优缺点进行了比较和分析。 0 引言 随着信息技术和Internet 的迅速发展,信息安全和可靠性问题越来越重要。现在信息安全面临两大基本攻击:被动式攻击(获取消息的内容、业务流分析)和主动攻击(假冒、消息的篡改、业务拒绝)。前者主要靠加密和解密技术进行有效处理,而后者就要靠消息认证来处理。在金融交易、电子商务、电子信件、手机用户信息的确认等领域,数据完整性确认和数据来源的真伪鉴定都是很重要的安全服务。实现这些安全服务的最好方法就是使用加密函数中的单项散列(Hash)函数。单项散列(Hash)函数是一种单项密码体制,它是一个从明文到密文的不可逆函数,也就是说,是无法解密的。通常应用在只需要加密、不需要解密的特殊应用场合。单项散列(Hash)函数H(M)作用于一任意长度的消息M,它返回一固定长度的散列值h:h=H(M)作为初始消息的独一无二的“数字指纹”,从而能保证数据的完整性和惟一性。 3.1 MD5 与SHA-1 的比较 由于MD5 与SHA-1均是从MD4 发展而来,它们的结构和强度等特性有很多相似之处,表(1)是对MD5 与SHA-1 的结构比较。SHA-1与MD5 的最大区别在于其摘要比MD5 摘要长 32 比特。对于强行攻击,产生任何一个报文使之摘要等于给定报文摘要的难度:MD5 是2128 数量级的操作,SHA-1 是2160 数量级的操作。产生具有相同摘要的两个报文的难度:MD5是 264 是数量级的操作,SHA-1 是280 数量级的操作。因而,SHA-1 对强行攻击的强度更大。但由于SHA-1 的循环步骤比MD5 多(80:64)且要处理的缓存大(160 比特:128 比特),SHA-1 的运行速度比MD5 慢。 5 结束语 MD5 和SHA-1 是单项散列函数的典型代表,它们广泛地应用在信息安全和数字签名等各个领域。从而有效地抗击了信息的主动式攻击,本文基于AVR 单片机实现了这两种算法,并结合汇编语言尽心了优化,取得了较好的效果。根据信息安全的要求的不同层次可以灵活选择这两种算法从而达到实际目的。
显示关于redis服务器的状态报告和统计数值
redis> INFO
# Server
redis_version:2.9.11 //服务器版本
redis_git_sha1:937384d0
redis_git_dirty:0
redis_build_id:8e9509442863f22
redis_mode:standalone //mode
os:Linux 3.13.0-35-generic x86_64
arch_bits:64
multiplexing_api:epoll //事件处理机制
gcc_version:4.8.2
process_id:4716 //进程ID
run_id:26186aac3f2380aaee9eef21cc50aecd542d97dc //随机标识符(用于 Sentinel 和集群)
tcp_port:6379 //监听端口号
uptime_in_seconds:362 //启动以来,经过的秒数
uptime_in_days:0 //启动以来,经过的天数
hz:10 //serverCron运行频率,此值越大表示redis对"间歇性task"的执行次数越频繁(次数/秒)
lru_clock:1725349 //以分钟为单位进行自增的时钟,用于 LRU 管理
config_file:
# Clients
connected_clients:1 //已连接客户端的数量(不包括通过从属服务器连接的客户端)
client_longest_output_list:0 //当前连接的客户端当中,最长的输出列表
client_biggest_input_buf:0 //当前连接的客户端当中,最大输入缓存
blocked_clients:0 //正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量
# Memory
used_memory:508536 //由 Redis 分配器分配的内存总量,以字节(byte)为单位
used_memory_human:496.62K //以人类可读的格式返回 Redis 分配的内存总量
used_memory_rss:7974912 //从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
//理想情况下, used_memory_rss 的值应该只比 used_memory 稍微高一点儿
//当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片
//当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。
used_memory_peak:508536 //Redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human:496.62K //以人类可读的格式返回 Redis 的内存消耗峰值
used_memory_lua:33792 // Lua 引擎所使用的内存大小(以字节为单位)
mem_fragmentation_ratio:15.68 //used_memory_rss 和 used_memory 之间的比率
mem_allocator:jemalloc-3.2.0 //在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc
# Persistence
loading:0 //一个标志值,记录了服务器是否正在载入持久化文件
rdb_changes_since_last_save:6 //距离最近一次成功创建持久化文件之后,经过了多少秒
rdb_bgsave_in_progress:0 //一个标志值,记录了服务器是否正在创建 RDB 文件
rdb_last_save_time:1411011131 //最近一次成功创建 RDB 文件的 UNIX 时间戳
rdb_last_bgsave_status:ok //一个标志值,记录了最近一次创建 RDB 文件的结果是成功还是失败
rdb_last_bgsave_time_sec:-1 //记录了最近一次创建 RDB 文件耗费的秒数
rdb_current_bgsave_time_sec:-1 // 如果服务器正在创建 RDB 文件,那么这个域记录的就是当前的创建操作已经耗费的秒
aof_enabled:0 //标志值,记录了 AOF 是否处于打开状态。
//如果 AOF 持久化功能处于开启状态,那么这个部分还会加上以下域:
// aof_current_size : AOF 文件目前的大小。
// aof_base_size : 服务器启动时或者 AOF 重写最近一次执行之后,AOF 文件的大小。
// aof_pending_rewrite : 一个标志值,记录了是否有 AOF 重写操作在等待 RDB 文件创建完毕之后执行。
// aof_buffer_length : AOF 缓冲区的大小。
// aof_rewrite_buffer_length : AOF 重写缓冲区的大小。
// aof_pending_bio_fsync : 后台 I/O 队列里面,等待执行的 fsync 调用数量。
// aof_delayed_fsync : 被延迟的 fsync 调用数量。
aof_rewrite_in_progress:0 //一个标志值,记录了服务器是否正在创建 AOF 文件。
aof_rewrite_scheduled:0 //一个标志值,记录了在 RDB 文件创建完毕之后,是否需要执行预约的 AOF 重写操作
aof_last_rewrite_time_sec:-1 //最近一次创建 AOF 文件耗费的时长。
aof_current_rewrite_time_sec:-1 //如果服务器正在创建 AOF 文件,那么这个域记录的就是当前的创建操作已经耗费的秒
aof_last_bgrewrite_status:ok //一个标志值,记录了最近一次创建 AOF 文件的结果是成功还是失败。
aof_last_write_status:ok //
# Stats
total_connections_received:2 //服务器已接受的连接请求数量
total_commands_processed:4 //服务器已执行的命令数量
instantaneous_ops_per_sec:0 //服务器每秒钟执行的命令数量
rejected_connections:0 //因为最大客户端数量限制而被拒绝的连接请求数量
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0 //因为过期而被自动删除的数据库键数量
evicted_keys:0 //因为最大内存容量限制而被驱逐(evict)的键数量。
keyspace_hits:0 //查找数据库键成功的次数。
keyspace_misses:0 //查找数据库键失败的次数。
pubsub_channels:0 //目前被订阅的频道数量。
pubsub_patterns:0 //目前被订阅的模式数量。
latest_fork_usec:0 //最近一次 fork() 操作耗费的毫秒数。
migrate_cached_sockets:0
# Replication
role:master //如果当前服务器没有在复制任何其他服务器,那么这个域的值就是 master ;否则的话,这个域的值就是 slave 。注意,在创建复制链的时候,一个从服务器也可能是另一个服务器的主服务器。
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:0.21 // Redis 服务器耗费的系统 CPU 。
used_cpu_user:0.17 // Redis 服务器耗费的用户 CPU 。
used_cpu_sys_children:0.00 //后台进程耗费的系统 CPU 。
used_cpu_user_children:0.00 //后台进程耗费的用户 CPU 。
# Cluster
cluster_enabled:0 //一个标志值,记录集群功能是否已经开启
# Keyspace
db0:keys=2,expires=0,avg_ttl=0 //部分记录了数据库相关的统计信息,比如数据库的键数量、数据库已经被删除的过期键数量等。
线性回归、rate、loss
em code
em算法
gmm与图像
图像的卷积
去均值ICA分离
带噪声的信号分离
SVM: 高斯核函数的影响
HMM分词:MLE
LDA
舆情
最大熵模型
聚类
降维
SVM
主题模型pLASA/LDA
条件随机场
变分推导Variation Inference
深度学习
$$ S=\frac{1}{0!} + \frac{1}{1!} + \frac{1}{2!} + \frac{1}{3!} + \frac{1}{4!} + \frac{1}{4!} + \Lambda + \frac{1}{n!} $$
跳跃表分析
markdown优点是易读易写。格式化编辑,纯文本发布,无标签,但支持html标签。
段落前后需要空行,若使用换行符<br/>
,前面至少两个以上空格才会生效
Setext 底线形式
高阶标题\次阶标题,大于等于2个=-
This is Setext H1
=================
This is Setext H2
-----------------
[TOC] 目录 Markdown语法书写的话,可以自动生成层级目录
六级标题
atx 井号 1-6个
# This is H1
## This is H2
可以加在每一行,也可以加在段落第一行,可以嵌套使用
> 引用文本-一级引用
>> 引用文本-二级引用
>>> 引用文本-三级引用
引用文本-一级引用
引用文本-二级引用
引用文本-三级引用
引用文本-一级引用
无序、有序 <br/>
无序列表 使用 *、+、- <br/>
有序列表 使用 数字+英文句点
缩进4个空格或1个制表符 或<pre>、<code>
标签
三个以上*、-、_
语法:行内式、参考式语法:行内式、参考式 [方括号]标记
This is 百度
This is [百度](https://www.baidu.com/ "title")
This is 关于
This is [关于](/about "about")
This is 百度
This is [百度][1] <br>
[1]:https://www.baidu.com/ "title"
OR: [1]:<https://www.baidu.com/> "title"
[Google][]
[Google]:https://www.google.com/
参考式:更易读
使用 * 或者底线 _ <strong>
this is strong //*两侧不能有空白
*this is strong* //*两侧不能有空白
反引号`````
行内式 参考式 <img>

状态集 | A | B |
---|---|---|
1 | 43 | 33 |
2 | 0 | 33 |
3 | 130 | 118 |
4 | 0 | 0 |
5 | 17 | 6 |
6 | 180 | 111 |
总数 | 370 | 225 |
标签: MARKDOWN
Tags: MARKDOWN
这是一条删除线
这是一个注脚^1
跳转
github文件地址格式
https://github.com/用户名/repository仓库名/raw/分支名master/图片文件夹名称/图片名称
文本中加入公式 $ 数学公式 $
单独加入公式 $$ 数学公式 $$
\begin{equation}
数学公式
\label{eq:当前公式名}
\end{equation}
自动编号后的公式可在全文任意处使用 \eqref{eq:公式名} 语句引用。
$ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha} \text {,行内公式示例}
示例: $ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha} \text {,行内公式示例} $
$$ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha} \text {,独立公式示例} $$
示例:$$ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha} \text {,独立公式示例} $$
^
表示上标, _
表示下标。如果上下标的内容多于一个字符,需要用{}
将这些内容括成一个整体。上下标可以嵌套,也可以同时使用
$$ x^{y^z}=(1+{\rm e}^x)^{-2xy^w} $$
$$ x^{y^z}=(1+{\rm e}^x)^{-2xy^w} $$
左右两边都有上下标,可以用\sideset
命令
$$ \sideset{^1_2}{^3_4}\bigotimes $$
$$ \sideset{^1_2}{^3_4}\bigotimes $$
()
、[]
和|
表示符号本身,使用 \{\}
来表示 {}
。当要显示大号的括号或分隔符时,要用 \left
和 \right
命令
$$\langle表达式\rangle$$
$$\langle表达式\rangle$$
$$\lceil表达式\rceil$$
$$\lceil表达式\rceil$$
$$\lfloor表达式\rfloor$$
$$\lfloor表达式\rfloor$$
$$\lbrace表达式\rbrace$$
$$\lbrace表达式\rbrace$$
$$ f(x,y,z) = 3y^2z \left( 3+\frac{7x+5}{1+y^2} \right) $$
$$ f(x,y,z) = 3y^2z \left( 3+\frac{7x+5}{1+y^2} \right) $$
通常使用 \frac {分子} {分母}
命令产生一个分数\frac {分子} {分母},分数可嵌套。
便捷情况可直接输入 \frac ab来快速生成一个\frac ab。
如果分式很复杂,亦可使用 分子 \over 分母 命令,此时分数仅有一层
$$\frac{a-1}{b-1} \quad and \quad {a+1\over b+1}$$
$$\frac{a-1}{b-1} \quad and \quad {a+1\over b+1}$$
使用 \sqrt [根指数,省略时为2] {被开方数}
命令输入开方。
$$\sqrt{2} \quad and \quad \sqrt[n]{3}$$
$$\sqrt{2} \quad and \quad \sqrt[n]{3}$$
省略号有两种,\ldots
表示与文本底线对齐的省略号,\cdots
表示与文本中线对齐的省略号
$$f(x_1,x_2,\underbrace{\ldots}_{\rm ldots} ,x_n) = x_1^2 + x_2^2 + \underbrace{\cdots}_{\rm cdots} + x_n^2$$
$$f(x_1,x_2,\underbrace{\ldots}{\rm ldots} ,x_n) = x_1^2 + x_2^2 + \underbrace{\cdots}{\rm cdots} + x_n^2$$
使用 \vec{矢量}
来自动产生一个矢量。也可以使用 \overrightarrow
等命令自定义字母上方的符号
$$\vec{a} \cdot \vec{b}=0$$
$$\vec{a} \cdot \vec{b}=0$$
$$\overleftarrow{xy} \quad and \quad \overleftrightarrow{xy} \quad and \quad \overrightarrow{xy}$$
$$\overleftarrow{xy} \quad and \quad \overleftrightarrow{xy} \quad and \quad \overrightarrow{xy}$$
使用 \int_
积分下限^积分上限 {被积表达式}
来输入一个积分
$$\int_0^1 {x^2} \,{\rm d}x$$
$$\int_0^1 {x^2} ,{\rm d}x$$
使用\lim_{变量 \to 表达式}
表达式 来输入一个极限。如有需求,可以更改 \to
符号至任意符号
$$ \lim_{n \to +\infty} \frac{1}{n(n+1)} \quad and \quad \lim_{x\leftarrow{示例}} \frac{1}{n(n+1)} $$
$$ \lim_{n \to +\infty} \frac{1}{n(n+1)} \quad and \quad \lim_{x\leftarrow{示例}} \frac{1}{n(n+1)} $$
使用 \sum_{下标表达式}^{上标表达式} {累加表达式}
来输入一个累加。
与之类似,使用 \prod \bigcup \bigcap
来分别输入累乘、并集和交集。
此类符号在行内显示时上下标表达式将会移至右上角和右下角
$$\sum_{i=1}^n \frac{1}{i^2} \quad and \quad \prod_{i=1}^n \frac{1}{i^2} \quad and \quad \bigcup_{i=1}^{2} R$$
$$\sum_{i=1}^n \frac{1}{i^2} \quad and \quad \prod_{i=1}^n \frac{1}{i^2} \quad and \quad \bigcup_{i=1}^{2} R$$
输入 \小写希腊字母英文全称
和\首字母大写希腊字母英文全称
来分别输入小写和大写希腊字母。
输入 | 显示 | 输入 | 显示 |
---|---|---|---|
\alpha | α | A | A |
\beta | β | B | B |
\gamma | γ | \Gamma | Γ |
\delta | δ | \Delta | Δ |
\epsilon | ϵ | E | E |
\zeta | ζ | Z | Z |
\eta | η | H | H |
\theta | θ | \Theta | Θ |
\iota | ι | I | I |
\kappa | κ | K | K |
\lambda | λ | \Lambda | Λ |
\nu | ν | N | N |
\mu | μ | M | M |
\xi | ξ | \Xi | Ξ |
o | o | O | O |
\pi | π | \Pi | Π |
\rho | ρ | P | P |
\sigma | σ | \Sigma | Σ |
\tau | τ | T | T |
\upsilon | υ | \Upsilon | Υ |
\phi | ϕ | \Phi | Φ |
\chi | χ | X | X |
\psi | ψ | \Psi | Ψ |
\omega | ω | \Omega | Ω |
使用 \left
和 \right
来创建自动匹配高度的 (圆括号),[方括号] 和 {花括号}
。
在每个公式末尾前使用\tag{行标}
来实现行标。
$$
f\left(
\left[
\frac{
1+\left\{x,y\right\}
}{
\left(
\frac{x}{y}+\frac{y}{x}
\right)
\left(u+1\right)
}+a
\right]^{3/2}
\right)
\tag{行标}
$$
$$
f\left(
\left[
\frac{
1+\left{x,y\right}
}{
\left(
\frac{x}{y}+\frac{y}{x}
\right)
\left(u+1\right)
}+a
\right]^{3/2}
\right)
\tag{行标}
$$
$\smash{\displaystyle\max_{0 \leq q \leq n-1}} f(q) \le n$
$\smash{\displaystyle\max_{0 \leq q \leq n-1}} f(q) \le n$
$f(x + \epsilon) \approx f(x) + f'(x) \epsilon + \mathcal{O}(\epsilon^2).$
$f(x + \epsilon) \approx f(x) + f’(x) \epsilon + \mathcal{O}(\epsilon^2).$
$\text{d}x$
$\text{d}x$
二分查找要求元素可以随机访问,所以决定了需要把元素存储在连续内存。这样查找确实很快,但是插入和删除元素的时候,为了保证元素的有序性,就需要大量的移动元素了。
如果需要的是一个能够进行二分查找,又能快速添加和删除元素的数据结构,首先就是二叉查找树,二叉查找树在最坏情况下可能变成一个链表。
于是,就出现了平衡二叉树,根据平衡算法的不同有AVL树,B-Tree,B+Tree,红黑树等,但是AVL树实现起来比较复杂,平衡操作较难理解,这时候就可以用SkipList跳跃表结构。
Key-Value数据结构
目前常用的key-value数据结构有三种:Hash表、红黑树、SkipList,它们各自有着不同的优缺点(不考虑删除操作):
Hash表:插入、查找最快,为O(1);如使用链表实现则可实现无锁;数据有序化需要显式的排序操作。
红黑树:插入、查找为O(logn),但常数项较小;无锁实现的复杂性很高,一般需要加锁;数据天然有序。
SkipList:插入、查找为O(logn),但常数项比红黑树要大;底层结构为链表,可无锁实现;数据天然有序。
如果要实现一个key-value结构,需求的功能有插入、查找、迭代、修改,那么首先Hash表就不是很适合了,因为迭代的时间复杂度比较高;而红黑树的插入很可能会涉及多个结点的旋转、变色操作,因此需要在外层加锁,这无形中降低了它可能的并发度。而SkipList底层是用链表实现的,可以实现为lock free,同时它还有着不错的性能(单线程下只比红黑树略慢),非常适合用来实现我们需求的那种key-value结构。
LevelDB、Reddis的底层存储结构就是用的SkipList。
常见的lock free编程一般是基于CAS(Compare And Swap)操作:CAS(void *ptr, Any oldValue, Any newValue);
即查看内存地址ptr处的值,如果为oldValue则将其改为newValue,并返回true,否则返回false。X86平台上的CAS操作一般是通过CPU的CMPXCHG指令来完成的。CPU在执行此指令时会首先锁住CPU总线,禁止其它核心对内存的访问,然后再查看或修改*ptr的值。简单的说CAS利用了CPU的硬件锁来实现对共享资源的串行使用。
而在性能层面上,CAS与mutex/readwrite lock各有千秋,简述如下:
跳表使用多级链表来实现,可以在 O(log n) 的平均时间内执行插入、删除和查找操作。
以下是一个简单的 Java 实现示例,用于构建和使用跳表:
1 | import java.util.Random; |
在上面的示例中,我们首先定义了 SkipListNode
类来表示跳表中的节点。每个节点包含一个值和一个指向下一级的数组。然后,我们创建了 SkipList
类来实现跳表。randomLevel
方法用于随机生成节点的层级,insert
方法用于插入节点,search
方法用于搜索节点,display
方法用于打印跳表的内容。
请注意,这只是一个简单的跳表实现示例。在实际应用中,您可能需要考虑更多的功能和优化,以满足不同的需求。
树状数组(Fenwick Tree,也称为Binary Indexed Tree,BIT)是一种用于高效处理区间求和(或其他类似操作)的数据结构。它具有较低的内存消耗,能够在 O(log n) 的时间内更新单个元素和计算前缀和。
树状数组适用于处理动态数组中的元素累加操作,如频繁更新某个位置的值以及查询某个区间的和等情况。
以下是一个简单的 Java 实现示例,用于构建和使用树状数组:
1 | public class FenwickTree { |
在上述代码中,FenwickTree
类用于实现树状数组。update
方法用于更新树状数组中的一个元素,query
方法用于查询前缀和。树状数组中的数组大小比原始数组大小多1,因为树状数组的下标从1开始。
这只是一个简单的树状数组实现示例。在实际应用中,您可能需要考虑更多的功能和优化,以满足不同的需求。
哈希表(HashMap)是一种常见的数据结构,用于存储键值对。它提供了基于键的快速查找和插入操作,具有高效的查找性能。在 Java 中,HashMap 是基于哈希表实现的,用于存储键值对的无序集合。
下面将分别介绍 Java 1.7 和 Java 1.8 中 HashMap 的实现原理:
在 Java 1.7 中,HashMap 使用拉链法解决哈希冲突。拉链法是一种处理冲突的方法,每个哈希桶(bucket)实际上是一个链表,相同哈希值的元素被放入同一个桶中。
HashMap 由一个哈希桶数组和哈希表的加载因子组成。加载因子是一个浮点数,表示哈希表在填满之前可以容纳的元素数量与当前桶数的比值。当元素数量超过加载因子与桶数的乘积时,HashMap 会自动进行扩容。
在 Java 1.7 的 HashMap 中,哈希值通过调用键对象的 hashCode()
方法得到,然后使用一个散列函数将哈希值映射到桶索引。每个桶中都是一个链表,存储具有相同哈希值的键值对。
Java 1.8 中的 HashMap 在处理哈希冲突时引入了红黑树,以提高性能。当链表长度超过一定阈值时,链表会被转换为红黑树,这样可以减少查找操作的时间复杂度。
Java 1.8 的 HashMap 也引入了桶位(Node 数组和 TreeNode 数组)的概念,将链表和红黑树存储在同一个数组中。HashMap 在插入、删除和查找操作时,会根据桶位的类型(链表或红黑树)选择不同的操作方式,以提高性能。
此外,Java 1.8 的 HashMap 在遇到哈希冲突时会采用扰动函数,将哈希值再次散列,以减少冲突概率。
1 | // Java 1.8 中的 HashMap 源码片段 |
这是 Java 1.8 中的 HashMap 根据哈希值计算桶索引的代码片段,其中 n 是哈希桶数组的大小。
综上所述,Java 的 HashMap 在不同版本中采用了不同的优化策略,包括拉链法、红黑树、扰动函数等,以提供高效的查找和插入操作。当选择使用 HashMap 时,要考虑到哈希冲突、加载因子、性能等因素,以便正确使用和配置该数据结构。