Hash系列目录

  1. Android面试Hash原理详解一
  2. Android面试Hash原理详解二
  3. Android面试Hash常见算法
  4. Android面试Hash算法案例

Android面试Hash原理详解二

  • 前言
  • 1. 散列函数示例
  • 2. Hash冲突
  • 3. 开散列方法(拉链法)
  • 4. 闭散列方法(开放地址法)
  • 5. Hash的应用
  • 总结

博客创建时间:2021.02.22
博客更新时间:2021.02.26

以Android studio build=4.1.2,gradle=6.5,SdkVersion 30来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已

博客《Android面试Hash原理详解一》内容过长,将其内容编辑整理后拆分为该篇文章


前言

在《Android面试Hash原理详解一》中已对Hash函数的原理、相关知识点进行详细的描述和分析,本篇博文主要进行哈希函数的应用分析


MD4
MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现–它是基于 32 位操作数的位操作来实现的。

MD5
MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好
  
SHA-1 及其他
SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。


1. 散列函数示例

我们假设处理的是值为整型的关键码,这样我们就可以建立一种关键码与正整数之间的一一对应关系,从而把该关键码的检索转化为对与其对应的正整数的检索。同时,进一步假定散列函数的值落在0到M-1之间。

除了MD5和SHA等方案,再次介绍几种其他的散列函数。 假设有一哈希表长度11,有如下数据 26 、5、14、35、29、3、9、16

1. 除留余数法
取关键字X被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。除余法几乎是最简单的散列方法,不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。

对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

示例:如函数H(key) = key % 11


2. 乘余取整法

一种乘法运算,此方法先让关键码key乘上一个常数A (0< A < 1),提取乘积的小数部分。然后,再用整数n乘以这个值,对结果向下取整,把它做为散列的地址。散列函数为: hash ( key ) = _LOW( n × ( A × key % 1 ) )
其中,“A × key % 1”表示取 A × key 小数部分,即: A × key % 1 = A × key - _LOW(A × key),而_LOW(X)是表示对X取下整。


3. 平方取中法

由于整数相除的运行速度通常比相乘要慢,所以有意识地避免使用除余法运算可以提高散列算法的运行时间。

平方取中法的具体实现是:先通过求关键码的平方值,从而扩大相近数的差别,然后根据表长度取中间的几位数(往往取二进制的比特位)作为散列函数值。因为一个乘积的中间几位数与乘数的每一数位都相关,所以由此产生的散列地址较为均匀。

关键字 关键字的平方 哈希函数值
1234 1522756 227
2143 4592449 924
4132 17073424 734
3214 10329796 297

这种方法适用于不知道关键字的分布,且数值的位数又不是很大的情况



4. 数字分析法

假设关键字集合中的每个关键字都是由 s 位数字组成 (u1, u2, …, us),分析关键字集中的全体,并从中提取分布均匀的若干位或它们的组合作为地址。数字分析法是取数据元素关键字中某些取值较均匀的数字位作为哈希地址的方法。

即当关键字的位数很多时,可以通过对关键字的各位进行分析,丢掉分布不均匀的位,作为哈希值。它只适合于所有关键字值已知的情况。通过分析分布情况把关键字取值区间转化为一个较小的关键字取值区间。

举个例子:要构造一个数据元素个数n=80,哈希长度m=100的哈希表。不失一般性,我们这里只给出其中8个关键字进行分析,8个关键字如下所示:
K1=61317602
K2=61326875
K3=62739628
K4=61343634
K5=62706815
K6=62774638
K7=61381262
K8=61394220

分析上述8个关键字可知,关键字从左到右的第1、2、3、6位取值比较集中,不宜作为哈希地址,剩余的第4、5、7、8位取值较均匀,可选取其中的两位作为哈希地址。设选取最后两位作为哈希地址,则这8个关键字的哈希地址分别为:2,75,28,34,15,38,62,20。

同样的案例:比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相 同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会 明显降低。

此法适于:能预先估计出全体关键字的每一位上各种数字出现的频度。
通过数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。


5. 折叠法

有时关键码所含的位数很多,采用平方取中法计算太复杂,则可将关键码分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址,这方法称为折叠法。类型分为两种:

  1. 移位叠加:将分割后的几部分低位对齐相加。
  2. 边界叠加:从一端沿分割界来回折叠,然后对齐相加。

将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。


6. 直接寻址法

取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a?key + b,其中a和b为常数(这种散列函数叫做自身函数)

7. 随机数法

选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。

f(key) = random(key)。这里的random是随机函数,当关键字的长度不等时,采用这个方法构造散列函数是比较合适的

8. 平方散列法

乘法的运算要比除法来得省时(对现在的CPU来说,估计我们感觉不出来),所以我们考虑把除法换成乘法和一个位移操作。
公式: index = (Key* Key) >> 28 (右移,除以2^28。记法:左移变大,是乘。右移变小,是除。)
如果数值分配比较均匀的话这种方法能得到不错的结果。

9.位运算法

这类型Hash函数通过利用各种位运算(常见的是移位和异或)来充分的混合输入元素
如公式:H(key)=Key>>14;

10. 斐波那契(Fibonacci)散列法

平方散列法的缺点是显而易见的,所以我们能不能找出一个理想的乘数,而不是拿value本身当作乘数呢?答案是肯定的。其公式为: H(key)= (Key* X) >> 28,X有如下几种理想数选择:

  1. 对于16位整数而言,这个乘数是40503。
  2. 对于32位整数而言,这个乘数是2654435769。
  3. 对于64位整数而言,这个乘数是11400714819323198485。

这几个“理想乘数”是如何得出来的呢?这跟一个法则有关,叫黄金分割法则,而描述黄金分割法则的最经典表达式无疑就是著名的斐波那契数列,即如此形式的序列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,…。


2. Hash冲突

哈希算法的实质是对原始数据的有损压缩,有损压缩后的固定字长用作唯一标识原始数据。若不同的原始数据被有损压缩后产生了相同的结果,该现象称为哈希碰撞。也叫作哈希冲突,Hash Collision

由于hash的原理是将输入空间的值映射成hash空间内,而hash值的空间远小于输入的空间。根据抽屉原理,一定会存在不同的输入被映射成相同输出的情况。

换一种理解即哈希函数可能对于不相等的关键码计算出相同的散列地址,即key1≠key2,即hash(key1)=hash(key2),我们称该现象为冲突(collision),也即hash碰撞。发生冲突的两个关键码称为该散列函数的同义词,一个好的hash算法,就需要这种冲突的概率尽可能小。

同义词

两个元素通过散列函数H(key)得到的散列值相同,那么这两个元素称为“同义词”。因为hash是一种压缩映射,所以当负载因子足够大是同义词一定会存在。


如何解决Hash冲突

虽然任意两个不同的数据块,其hash值相同的可能性极小,且对于一个给定的数据块,找到和它hash值相同的数据块极为困难。

但是在实际应用中,我们必须考虑在冲突发生时的处理办法,因为每种hash 函数都存在hash碰撞的可能。

解决冲突是一个复杂问题。冲突主要取决于:

  1. 散列函数,一个好的散列函数的值应尽可能平均分布。
  2. 处理冲突方法。
  3. 负载因子的大小。太大不一定就好,而且浪费空间严重,负载因子和散列函数是联动的。

常见的两种处理方案是是开散列方法( open hashing,也称为拉链法,separate chaining )和闭散列方法( closed hashing,也称为开地址方法,open addressing )。当然还有部分非主流算法

不同之处在于:

  1. 开散列法把发生冲突的关键码存储在散列表主表之外
  2. 闭散列法把发生冲突的关键码存储在表中另一个槽内。

二级聚集
如果两个关键码散列到同一个基地址,那么采用开散列方法闭散列方法还是得到同样的探查序列,仍然会产生聚集。这个问题称为二级聚集( secondary clustering )。

产生二级聚集的原因是因为伪随机探查和二次探查产生的探查序列只是基地址的函数,而不是原来关键码值的函数。
为了避免二级聚集,我们需要使得探查序列是原来关键码值的函数,而不是基位置的函数。


公共溢出区法

除了两种主流的方法,还有一种非主流的方法,那就是公共溢出区法
假设关键字集合为{12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34},同样使用除留余数法求散列表,如下图所示:

没有冲突的元素放在左边的表,有冲突的元素,将多余的元素放在右边的那个表。


3. 开散列方法(拉链法)

添加一个元素的时候,首先计算元素key的hash值,确定插入数组中的位置。如果当前位置下没有数据,则直接添加到当前位置。当遇到冲突的时候,添加到同一个hash值的元素后面,行成一个链表。这个链表的特点是同一个链表上的Hash值相同。

开散列方法的一种简单形式是把散列表中的每个槽定义为一个链表的表头。散列到一个特定槽的所有记录都放到这个槽的链表中。

例如如图,将12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34几个数据存放到有12个槽的散列表中,通过取余法散列函数
h(K) = K mod 12,得到的余数就是每个数据的储存地址,如图下:

在JDK1.8中HashMap就是使用的拉链法解决冲突的,当链表上数据超过8条时,使用了红黑树进行了优化


4. 闭散列方法(开放地址法)

开放地址法是指大小为 M 的数组保存 N 个键值对,其中 M > N。我们需要依靠数组中的空位解决碰撞冲突。基于这种策略的所有方法被统称为“开放地址”哈希表。

简单来说就是:一旦发生冲突,就去寻找下 一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。
下面介绍几种闭散列方法中的几种常见构造法:

1. 线性探测法
线性探测法,就是比较常用的一种“开放地址”哈希表的一种实现方式。线性探测法的核心思想是当冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

线性探测法的数学描述是:h(k, i) = (h(k, 0) + i) mod m,i表示当前进行的是第几轮探查。i=1时,即是探查h(k, 0)的下一个;i=2,即是再下一个。这个方法是简单地向下探查。mod m表示:到达了表的底下之后,回到顶端从头开始。

后面举例假定:一组关键码为(26,36,38,44,15,68,12,06,51),散列表长度M= 13,使用取余法

将散列表看成是一个环形表,若在基地址d(即h(K)=d)发生冲突,则依次探查下述地址单元:d+1,d+2,…,M-1,0,1,…,d-1直到找到一个空闲地址或查找到关键码为key的结点为止。当然,若沿着该探查序列检索一遍之后,又回到了地址d,则无论是做插入操作还是做检索操作,都意味着失败。

示例:用线性探测法来构造散列表,设定构造函数H(key)=Key%13,那么散列表如下:
根据线性检测,当计算12是地址与38冲突,往后面找…0,1,此时1为空插入数据12。 当计算51时与38冲突,往后找…0,1,2,3,4,此时4位置空闲插入数据51。


2. 二次探测(Quadratic probing)
二次探查法的基本思想是:生成的后继散列地址不是连续的,而是跳跃式的,以便为后续数据元素留下空间从而减少聚集。如果有多个同义词,那么他们是对称分布在原始H(Key)两侧的

示例:用二次探测法来构造散列表,设定构造函数H(key)=Key%13,那么散列表如下:

当计算h(12)=12时已存在38冲突,此时index=0已有数据26,查找0相对12的对称点index=11空闲,将12填入index=11。

当计算h(51)=12时,冲突。查index=0冲突,index=11冲突,index=1时槽空闲,将51填入index=1。


3. 随机探测(Double hashing)
在探查序列中随机地从未访问过的槽中选择下一个位置,即探查序列应当是散列表位置的一个随机排列。
我们可以做一些类似于伪随机探查( pseudo-random probing )的事情。在伪随机探查中,探查序列中的第i个槽是h(Key) = (Key+ ri) mod M,其中ri是1到M - 1之间数的“随机”数序列。所有插入和检索都使用相同的“随机”数。

示例:用随机测法来构造散列表, 伪随机数列为2,5,9… , 设定构造函数H(key)=Key%13,那么散列表如下:

计算H(12)=12冲突,此时H(12+2)=1可填充
计算H(51)=12冲突,此时H(51+2)=1冲突,继续H(51+5)=4槽空闲可填充


4. 双散列探查法

伪随机探查和二次探查都能消除基本聚集——即基地址不同的关键码,其探查序列的某些段重叠在一起——的问题。

同时准备多个散列函数,当第一个散列函数发生冲突的时候可以用备选的散列函数进行计算。

双散列探查法利用第二个散列函数作为常数,每次跳过常数项,做线性探查。双散列函数法:在位置d冲突后,再次使用另一个散列函数产生一个与散列表桶容量m互质的数c,依次试探(d+n*c)%m,使探查序列跳跃式分布。


5. Hash的应用

hash算法常用于数据查找、信息加密、数据校验、负载均衡。主要用于信息安全领域中,通过hash加密算法把一些不同长度的信息转化成杂乱的128位的编码,这些编码值叫做HASH值. 也可以说,Hash就是找到一种数据内容和数据存放地址之间的映射关系。

不可逆
它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程。同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出。哈希函数的这种单向特征和输出数据长度固定的特征使得它可以生成消息或者数据。

抗篡改
对于一个数据块,哪怕只改动其一个比特位,其hash值的改动也会非常大。
哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出。如果输入数据中有变化,则哈希值也会发生变化,哪怕只改动其一个比特位,其hash值的改动也会非常大。

哈希的这种特性可用于许多操作,包括身份验证和数字签名,也称为“消息摘要”。

不同的应用对Hash函数有着不同的要求;比如,用于加密的Hash函数主要考虑它和单项函数的差距,而用于查找的Hash函数主要考虑它映射到小范围的冲突率。


1. 数据校验

我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。

MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。


2. 版权校验

版权校验在数据校验方面的另一个应用场景就是版权的保护或者违禁信息的打击,比如某个小视频,第一个用户上传的时候,我们认为是版权所有者,计算一个hash值存下来。当第二个用户上传的时候,同样计算hash值,如果hash值一样的话,就算同一个文件。

这种方案其实也给用户传播违禁文件提高了一些门槛,不是简单的换一个名字或者改一下后缀名就可以躲避掉打击了。(当然这种方式也是可以绕过的,图片的你随便改一下颜色,视频去掉一帧就又是完全不同的hash值了。

另外我们在社区里,也会遇到玩家重复上传同一张图片或者视频的情况,使用这种校验的方式,可以有效减少cos服务的存储空间。


3. 大文件分块校验

在p2p网络中会把一个大文件拆分成很多小的数据各自传输。这样的好处是如果某个小的数据块在传输过程中损坏了,只要重新下载这个块就好。为了确保每一个小的数据块都是发布者自己传输的,我们可以对每一个小的数据块都进行一个hash的计算,维护一个hash List,在收到所有数据以后,我们对于这个hash List里的每一块进行遍历比对。

这里有一个优化点是如果文件分块特别多的时候,如果遍历对比就会效率比较低。可以把所有分块的hash值组合成一个大的字符串,对于这个字符串再做一次Hash运算,得到最终的hash(Root hash)。在实际的校验中,我们只需要拿到了正确的Root hash,即可校验Hash List,也就可以校验每一个数据块了。


4. 数字签名

Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。通过对Hash值得校验能认为是对文本信息的校验。


5. 签名原理
MD5-Hash-文件的数字文摘通过Hash函数计算得到。不管文件长度如何,它的Hash函数计算结果是一个固定长度的数字。与加密算法不 同,这一个Hash算法是一个不可逆的单向函数。采用安全性高的Hash算法,如MD5、SHA时,两个不同的文件几乎不可能得到相同的Hash结果。因 此,一旦文件被修改,就可检测出来。


6. 信息加密
不要以为用MD5加密数据后,你的数据就安全了。有这么一个牛逼网站https://www.cmd5.com/,有极大可能可以反向查询出你的原始加密内容。该网站的官网介绍是这样的:

 本站针对md5、sha1等全球通用公开的加密算法进行反向查询,通过穷举字符组合的方式,创建了明文密文对应查询数据库,创建的记录约90万亿条,占用硬盘超过500TB,查询成功率95%以上,很多复杂密文只有本站才可查询。已稳定运行十余年,国内外享有盛誉.



一般这种MD解密网站对于复杂内容的解密都是需要收费的。

为了防止信息被反向查询,一般针对这种问题,我们的解决之道就是引入salt(加盐),即利用特殊字符(盐)和用户的输入合在一起组成新的字符串进行加密。通过这样的方式,增加了反向查询的复杂度。


7. 鉴权协议
鉴权协议又被称作挑战–认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。

8. 负载均衡
在开发大数据用户量应用时,都会使用分库分表,针对用户的openid进行hashtime33取模,就可以得到对应的用户分库分表的节点了。也就是用户太多了,分多个表存储它们的数据。

如上假设应用设计了10张表,openid计算后的hash值取模10,得到对应的分表,在进行后续处理就好。对于一般的活动或者系统,我们一般设置10张表或者100张表就好。

假设我们活动初始分表了10张,运营一段时间以后发现需要10张不够,需要改到100张。这个时候我们如果直接扩容的话,那么所有的数据都需要重新计算Hash值,大量的数据都需要进行迁移。如果更新的是缓存的逻辑,则会导致大量缓存失效,发生雪崩效应,导致数据库异常。造成这种问题的原因是hash算法本身的缘故,只要是取模算法进行处理,则无法避免这种情况。针对这种问题,我们就需要利用一致性hash进行相应的处理了扩容问题了。

一致性hash的基本原理是将输入的值hash后,对结果的hash值进行2^32取模,这里和普通的hash取模算法不一样的点是在一致性hash算法里将取模的结果映射到一个环上。将缓存服务器与被缓存对象都映射到hash环上以后,从被缓存对象的位置出发,沿顺时针方向遇到的第一个服务器,就是当前对象将要缓存于的服务器,由于被缓存对象与服务器hash后的值是固定的,所以,在服务器不变的情况下,一个openid必定会被缓存到固定的服务器上,那么,当下次想要访问这个用户的数据时,只要再次使用相同的算法进行计算,即可算出这个用户的数据被缓存在哪个服务器上,直接去对应的服务器查找对应的数据即可。这里的逻辑其实和直接取模的是一样的。如下图所示:

初始情况如下:用户1的数据在服务器A里,用户2、3的数据存在服务器C里,用户4的数据存储在服务器B里

下面我们来看一下当服务器数量发生变化的时候,相应影响的数据情况:

  • 服务器缩容

    服务器B发生了故障,进行剔除后,只有用户4的数据发生了异常。这个时候我们需要继续按照顺时针的方案,把缓存的数据放在用户A上面。

  • 服务器扩容
    同样的,我们进行了服务器扩容以后,新增了一台服务器D,位置落在用户2和3之间。按照顺时针原则,用户2依然访问的是服务器C的数据,而用户3顺时针查询后,发现最近的服务器是D,后续数据就会存储到d上面。


总结

本文主要讲解哈希函数的构建示例过程、哈希冲突的解决方案和哈希函数的应用场景。


相关链接

  1. Android面试Hash原理详解一
  2. Android面试Hash原理详解二
  3. Android面试Hash常见算法
  4. Android面试Hash算法案例

扩展链接:

  1. Android CameraX 使用入门
  2. Android Studio 4.0新特性及升级异常

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !

Android面试Hash原理详解二相关推荐

  1. Android涂鸦画板原理详解——从初级到高级(二)

    前言 前面写了<Android涂鸦画板原理详解--从初级到高级(一)>,讲了涂鸦原理初级和中级的应用,现在讲解高级应用.如果没有看过前面一篇文章的同学,建议先去看看哈. 准备 高级涂鸦涉及 ...

  2. Android Gradle 自定义Task详解二:进阶

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78523958 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  3. DPC密度峰值聚类算法原理详解二

    DPC密度峰值聚类算法原理详解二 1.计算数据点两两之间的距离 1.使用 Numpy 模块查找两点之间的欧几里得距离: 2.使用 distance.euclidean() 函数查找两点之间的欧式距离: ...

  4. Android 中malloc_debug 原理详解

    版本基于:Android R 关联博文: Android 中malloc_debug 使用详解 0. 前言 最近上项目中遇到一个native 可能内存泄漏的问题,曾考虑使用HWASAN,但这个工具是针 ...

  5. android中okhttp原理详解,Android中okhttp原理详解-极度针对面试篇

    一.okhttp工做的大体流程 1.一.总体流程 (1).当咱们经过OkhttpClient创立一个Call,并发起同步或者异步请求时: (2).okhttp会经过Dispatcher对咱们全部的Re ...

  6. Android分包MultiDex原理详解

    MultiDex的产生背景 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的 ...

  7. android广告SDK原理详解(附源码)

    广大的开发者吃糠咽菜开发了一两款APP,获取了一些流量后自然就会想到流量变现,一般情况下大家会选择到百度联盟或者Google Admob这些广告服务提供商注册开发者账号,在自己的APP里面加上几行广告 ...

  8. Android核心破解原理详解

    玩 Android 时,我们经常会听到核心破解这个词,在部分第三方 ROM 里,也有一些作者会直接完成核心破解,以使 Android 拥有更大的可玩性.那么倒底什么是核心破解,它又对系统产生什么样的影 ...

  9. Android视频直播原理详解

    最近一段时间,视频直播可谓大火.在视频直播领域,有不同的商家提供各种的商业解决方案,包括软硬件设备,摄像机,编码器,流媒体服务器等.本文要讲解的是如何使用一系列免费工具,打造一套视频直播方案. 视频直 ...

最新文章

  1. IT行业常见职位职业路线图
  2. oracle查看用户路径,oracle 查看用户的表空间,表空间路径,角色,权限
  3. 记一则Hadoop DataNode OOM故障,以及解决方案
  4. 在CentOS5.5上做Heroku的开发
  5. Android 布局练习
  6. cvc降噪和主动降噪_音频知识:CVC降噪和ANC主动降噪的区别和应用
  7. HDU 1275(两车追及或相遇问题)
  8. Android 打印Log语句
  9. 金融数量分析2:Markowitz均值方差模型
  10. 一个简单的2048小游戏
  11. 【微信测试号实战——01】注册一个属于你自己的微信测试号
  12. MySQL学习整理-码农进阶之路(二)
  13. 本科以下别学 IT 了,切身经历
  14. module ‘selenium.webdriver‘ has no attribute ‘PhantomJS‘
  15. 计算机微机组装与维护形考1,最新国开电大《ERP原理与应用》形考任务实验1至5作业及答案...
  16. MIFARE系列7《安全》
  17. Oracle出错 invalid number
  18. ERP 销售出库单查询---出库单明细 SQL优化
  19. 【转】JAVA EE 6 规范综述
  20. 按照eslint 规则一键修复

热门文章

  1. 鼓励师加成太刺激了,鼻血喷了半斤,代码不一会儿就写完了...
  2. 正在更新office 请稍后... 解决办法
  3. “网上世博会”带来创新体验,水晶石着力推动“数字展览”应用
  4. maven下载jar包下载不下来的解决方法
  5. 解决can't resolve the symbol 'R'方法(转载)
  6. 2021会宁三中高考成绩查询,2019中考分数线
  7. [墨者学院] Windows硬盘文件分析取证(新建的用户名)
  8. 鲁大师历经18年的风雨后,又一重量级评测即将诞生
  9. pikachu通关教程
  10. vue实现好看的相册、图片网站