HyperLogLog 使用及其算法原理详细讲解,面试流程4轮技术面+1轮HR

前言:

求职季在即,技巧千万条,硬实力才是关键,听说今年疫情大环境不好,更要好好准备才行。MySQL是Java程序员面向高级的必备技能,很多朋友在面试时经常在这里折戟沉沙,饮恨不已。熟练掌握MySQL知识,在实践中具有很强的操作性,尤其是在互联网行业,不仅要写好代码、实现功能,而且还要在高并发的情况下能够正常运转。

这篇文章总结了许多关于MySQL方面的知识总结,以及面试多家总结出来的常问面试题,希望对大家有所帮助。

static class BitKeeper {

/** 记录最大的低位0的长度 */

private int kmax;

public void random() {

// 生成随机数

long value = ThreadLocalRandom.current().nextLong(2L << 32);

int len = this.lowZerosMaxLength(value);

if (len > kmax) {

kmax = len;

}

}

/**

* 计算低位0的长度

* 这里如果不理解看下我的注释

* value >> i 表示将value右移i,  1<= i <32 , 低位会被移出

* value << i 表示将value左移i,  1<= i <32 , 低位补0

* 看似一左一右相互抵消,但是如果value低位是0右移被移出后,左移又补回来,这样是不会变的,但是如果移除的是1,补回的是0,那么value的值就会发生改变

* 综合上面的方法,就能比较巧妙的计算低位0的最大长度

* @param value

* @return

*/

private int lowZerosMaxLength(long value) {

int i = 1;

for (; i < 32; i++) {

if (value >> i << i != value) {

break;

}

}

return i - 1;

}

}

static class Experiment {

/** 测试次数n */

private int n;

private BitKeeper bitKeeper;

public Experiment(int n) {

this.n = n;

this.bitKeeper = new BitKeeper();

}

public void work() {

for(int i = 0; i < n; i++) {

this.bitKeeper.random();

}

}

/**

* 输出每一轮测试次数n

* 输出 logn / log2 = k 得 2^k = n,这里的k即我们估计的kmax

* 输出 kmax,低位最大0位长度值

*/

public void debug() {

System.out.printf(“%d %.2f %d\n”, this.n, Math.log(this.n) / Math.log(2), this.bitKeeper.kmax);

}

}

public static void main(String[] args) {

for (int i = 0; i < 100000; i++) {

Experiment experiment = new Experiment(i);

experiment.work();

experiment.debug();

}

}

}

我们可以通过修改main函数中,测试的轮次,再根据输出的结果来观察,n=2^kmax这样的结果还是比较吻合的。

image.png

3.5 代码实现-HyperLogLog

接下来根据HyperLogLog中采用调和平均数+分桶的方式来做代码优化,模拟简单版本的HyperLogLog算法的实现,其代码如下:

package com.lizba.pf;

import java.util.concurrent.ThreadLocalRandom;

/**

*      HyperLogLog 简单实现

* @Author: Liziba

* @Date: 2021/8/18 10:40

*/

public class HyperLogLogTest {

static class BitKeeper {

/** 记录最大的低位0的长度 */

private int kmax;

/**

* 计算低位0的长度,并且保存最大值kmax

* @param value

*/

public void random(long value) {

int len = this.lowZerosMaxLength(value);

if (len > kmax) {

kmax = len;

}

}

/**

* 计算低位0的长度

* 这里如果不理解看下我的注释

* value >> i 表示将value右移i,  1<= i <32 , 低位会被移出

* value << i 表示将value左移i,  1<= i <32 , 低位补0

* 看似一左一右相互抵消,但是如果value低位是0右移被移出后,左移又补回来,这样是不会变的,但是如果移除的是1,补回的是0,那么value的值就会发生改变

* 综合上面的方法,就能比较巧妙的计算低位0的最大长度

* @param value

* @return

*/

private int lowZerosMaxLength(long value) {

int i = 1;

for (; i < 32; i++) {

if (value >> i << i != value) {

break;

}

}

return i - 1;

}

}

static class Experiment {

private int n;

private int k;

/** 分桶,默认1024,HyperLogLog中是16384个桶,并不适合我这里粗糙的算法 */

private BitKeeper[] keepers;

public Experiment(int n) {

this(n, 1024);

}

public Experiment(int n, int k) {

this.n = n;

this.k = k;

this.keepers = new BitKeeper[k];

for (int i = 0; i < k; i++) {

this.keepers[i] = new BitKeeper();

}

}

/**

* (int) (((m & 0xfff0000) >> 16) % keepers.length) -> 计算当前m在keepers数组中的索引下标

* 0xfff0000 是一个二进制低16位全为0的16进制数,它的二进制数为 -> 1111111111110000000000000000

* m & 0xfff0000 可以保理m高16位, (m & 0xfff0000) >> 16 然后右移16位,这样可以去除低16位,使用高16位代替高16位

* ((m & 0xfff0000) >> 16) % keepers.length 最后取模keepers.length,就可以得到m在keepers数组中的索引

*/

public void work() {

for (int i = 0; i < this.n; i++) {

long m = ThreadLocalRandom.current().nextLong(1L << 32);

BitKeeper keeper = keepers[(int) (((m & 0xfff0000) >> 16) % keepers.length)];

keeper.random(m);

}

}

/**

* 估算 ,求倒数的平均数,调和平均数

* @return

*/

public double estimate() {

double sumBitsInverse = 0.0;

// 求调和平均数

for (BitKeeper keeper : keepers) {

sumBitsInverse += 1.0 / (float) keeper.kmax;

}

double avgBits = (float) keepers.length / sumBitsInverse;

return Math.pow(2, avgBits) * this.k;

}

}

/**

* 测试

* @param args

*/

public static void main(String[] args) {

for (int i = 100000; i < 1000000; i+=100000) {

Experiment experiment = new Experiment(i);

experiment.work();

double estimate = experiment.estimate();

// i 测试数据

// estimate 估算数据

// Math.abs(estimate - i) / i 偏差百分比

《一线大厂Java面试真题解析+Java核心总结学习笔记+最新全套讲解视频+实战项目源码》开源

Java优秀开源项目:

  • ali1024.coding.net/public/P7/Java/git

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

image

.abs(estimate - i) / i 偏差百分比

《一线大厂Java面试真题解析+Java核心总结学习笔记+最新全套讲解视频+实战项目源码》开源

Java优秀开源项目:

  • ali1024.coding.net/public/P7/Java/git

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

[外链图片转存中…(img-Am4AJmxl-1649663061049)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值