IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 漏斗算法详解 -> 正文阅读

[数据结构与算法]漏斗算法详解

? ? ? ? 漏斗是生活中一个非常常见的容器,他自身的形状决定了其拥有的性质,上面宽、下边窄,上面进水快,而窄的那头出水较慢。比如生活中,我们需要向开水瓶里灌水,用一个漏斗会非常的方便。

? ? ? ? 我们用热水壶通过漏斗往开水瓶里倒水,水会沿着漏斗顺流到开水瓶里,如果这个时候你不小心手抖了,一下倒入很多,你会发现漏斗里的水不能一下子进到开水瓶里而是满了出来。

? ? ? ? 这是一个简单的数学问题,可以用以下表达式说明:

? ? ? ?if? ?单位时间内的进水速率> 单位时间内出水速率 :

? ? ? ? ? ? print("漏斗里的水会一直增加!... 直到溢出")

? ? ? else?

? ? ? ? ? ?print("漏斗永远装不满...水一直会顺着流出。")

? ? ? ? 由分析,如果我们能控制进水和出水的速率,那么可以借助漏斗实现单位时间内流量的限制,即限流。

? ? ? ? 实现思路:

? ? ? ? 1.? 定义一个Funnel 静态内部类,相当于漏斗,可以初始化容量和漏斗大口的出水速率。

? ? ? ? 2.? 定义进水方法watering(int capacity),参数为每次出水的量,默认为1。

? ? ? ? 3.? 定义出水方法runningWater(), 由于每次流出水需要统计量,那么就需要记录每次入水的时间戳,以供计算容量,出水的同时剩余容量leftCapcity需要加上出水量 this.leftCapacity += deltaCapacity。

? ? ? ? ? 单位时间内的出水量(deltaCapacity)?=? 速率(waterRate) * (当前出水的时间戳ts- 上一次出水的时间戳ts)

? ? ? ? 4. 如果出水的量超过了漏斗的最大容量,那么直接将leftCapacity置为最大容量,也就是说此刻漏斗里相当于没有水。

? ? ? ? 如果剩余容量> 进水量,那么表示水可以通行,否则不能通行。

package leetcode100;


import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 漏斗算法
 * Funnel algorithm
 */
public class FunnelProblem {

    /**
     * record a logic key and funnel
     */
    private static Map<String, Funnel> funnelMap = new HashMap<>();


    static class Funnel {

        private BigDecimal waterRate;

        private Integer capacity;

        private Integer leftCapacity;

        private Long leakTimes;

        public Funnel(BigDecimal waterRate, Integer capacity) {
            this.waterRate = waterRate;
            this.capacity = capacity;
            this.leftCapacity = capacity;
            this.leakTimes = System.currentTimeMillis();
        }

        /**
         * water out, space add
         */
        public void runningWater() {
            long nowTime = System.currentTimeMillis();
            long deltaTime = nowTime - leakTimes;
            Integer deltaCapacity = waterRate.multiply(new BigDecimal(deltaTime)).intValue();
            // the deltaCapacity  means how much water are in .
            if (deltaCapacity < 0) {
                this.leftCapacity = capacity;
                this.leakTimes = nowTime;
                return;
            }
            if (deltaCapacity < 1) {
                return;
            }

            this.leftCapacity += deltaCapacity;
            this.leakTimes = nowTime;
            if (this.leftCapacity < this.capacity) {
                this.leftCapacity = this.capacity;
            }
        }

        /**
         * water in.
         */
        public boolean watering(Integer waterCapacity) {
            runningWater();
            if (leftCapacity > waterCapacity) {
                this.leftCapacity -= waterCapacity;
                return true;
            }
            return false;
        }

    }

    public boolean allow(String userId, String key, Integer initCapacity, BigDecimal leakRate) {
        Funnel funnel = funnelMap.get(key);
        if (funnel == null) {
            funnel = new Funnel(leakRate, initCapacity);
            funnelMap.put(key, funnel);
        }
        return funnel.watering(1);
    }


    public static void main(String[] args) {
        FunnelProblem funnelProblem = new FunnelProblem();
        for (int i = 0; i < 10000; i++) {
            Boolean allow = funnelProblem.allow("zhangsan", "browser", 10, BigDecimal.valueOf(0.1));

            if (allow) {
                System.out.println("you can browser!");
            } else {
                System.out.println("pls wait !");
            }
        }
    }


}

查看打印结果:

????????可以发现,每波数据能顺利通过9个, 然后等一段时间后,再次会通过9个,限流的作用就显现出来了, 我们可以通过设置initCapacity 和 leakRate的值来初始化每个漏斗的大小和进水的速率。

? ? ? ? ?此方案存在的缺陷,由于采用了map做为key和很多漏桶的存储,每次存、取不具备原子性,高并发情况下会出现线程安全问题,需要加分布式锁实现, 不过加锁会损耗一定的性能。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:39:43  更:2022-03-03 16:43:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 15:42:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码