算法 | 链表的应用,缓存失效算法

简介: 算法 | 链表的应用,缓存失效算法

先进先出策略(FIFO,First In First Out)


这种策略的实现是最简单的了,我们利用链表的特性,只要将需要缓存的数据依次添加到链表中,当空间不够时,将链表末尾的数据删除即可(如果我们对队列比较熟悉的话,可以发现这种策略用队列进行实现是最方便的)

实现代码如下:

package com.study.spring.transaction.cache;
import lombok.AllArgsConstructor;
import java.security.InvalidParameterException;
/**
 * @author dmz
 * @date Create in 20:57 2019/8/10
 */
public class Main {
    public static void main(String[] args) {
        link link = new link(4);
        link.add(1);
        link.add(2);
        link.add(3);
        link.add(4);
        link.add(5);
        link.add(6);
        link.add(7);
        link.sout();
    }
    static class link {
        public link(int max) {
            if (max > 0) {
                this.max = max;
            } else {
                throw new InvalidParameterException("参数不能小于0");
            }
        }
        // 最大能添加的元素的个数
        int max;
        // 链表中实际已经存储的元素的个数
        int size;
        // 链表的头节点
        Node first;
        // 链表的尾节点
        Node last;
        // 链表中的每个节点
        @AllArgsConstructor
        class Node {
            // 节点中保存的数据
            Object item;
            // 指向上一个节点
            Node pre;
            // 指向下一个节点
            Node next;
        }
        public void add(Object item) {
            Node node = new Node(item, null, null);
            if (size == 0) {
                size++;
                node.pre = null;
                node.next = null;
                first = node;
                last = node;
            } else {
                if (size == max) {
                    // 链表中的数据已经满了
                    // 策略1:先进先出,需要删除头节点
                    Node second = first.next;
                    second.pre = null;
                    first.next = null;
                    first = second;
                    size--;
                }
                // 将数据添加到链表尾部
                size++;
                last.next = node;
                node.pre = last;
                last = node;
            }
        }
        public void sout() {
            Node node = first;
            for (int i = 0; i < max; i++) {
                if (size == 0) {
                    System.out.println("链表中没有元素");
                    break;
                } else {
                    System.out.println(node.item);
                    node = node.next;
                    if (node == null) {
                        System.out.println("遍历结束");
                        break;
                    }
                }
            }
        }
    }
}

输出结果如下:

4
5
6
7

最少使用策略(LFU,Least Frequently Out)


根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。


下面给出两种实现方式


JDK自带优先级队列进行实现


实现思路:利用PriorityQueue小顶堆的特点,关于PriorityQueue可参考我之前的文章 java读源码 之 queue源码分析(PriorityQueue,附图)。每次出队的一定是优先级最低的元素,同时我们自定义比较器,我这里是通过用实体实现Comparable接口的方式。


创建类如下:

package com.study.spring.transaction.huancun;
import java.time.LocalDateTime;
/**
 * 进行一个简单的抽象,所有实体都要通过访问时间跟访问次数进行比较
 * @author dmz
 * @date Create in 23:45 2019/8/10
 */
public interface Count extends Comparable<Count> {
    void setLastVisitTime(LocalDateTime localDateTime);
    LocalDateTime getLastVisitTime();
    int getCount();
    void setCount(int count);
    default void addCount() {
        setCount(getCount() + 1);
    }
    // 根据访问次数比较,次数相同的情况下比较访问时间
    @Override
    default int compareTo(Count o2) {
        return this.getCount() == o2.getCount() ? this.getLastVisitTime().compareTo(o2.getLastVisitTime())
                : this.getCount() - o2.getCount();
    }
}
package com.study.spring.transaction.huancun;
import lombok.Data;
import java.time.LocalDateTime;
/**
 * @author dmz
 * @date Create in 23:45 2019/8/10
 */
@Data
public class Entity implements Count, Comparable<Entity> {
    private int count;
    private Object object;
    private LocalDateTime lastVisitTime = LocalDateTime.now();
    Entity(Object object) {
        this.object = object;
    } 
}
package com.study.spring.transaction.huancun;
import java.time.LocalDateTime;
import java.util.PriorityQueue;
/**
 * @author dmz
 * @date Create in 23:55 2019/8/10
 */
public class LFUStrategy<T extends Count> {
    private int max;
    LFUStrategy(PriorityQueue<T> priorityQueue, int max) {
        this.max = max;
        this.priorityQueue = priorityQueue;
    }
    private PriorityQueue<T> priorityQueue;
    /**
     * 访问排列在index位置的元素
     *
     * @param index 位置
     * @return 所在元素
     */
    public T get(int index) {
        int count = 1;
        for (T t : priorityQueue) {
            if (count == index) {
                priorityQueue.remove(t);
                t.addCount();
                t.setLastVisitTime(LocalDateTime.now());
                // 先remove再add是为了利用其内部特性,调用add方法时会进行排序,将最小的元素置于堆顶
                priorityQueue.add(t);
                return t;
            }
        }
        return null;
    }
    @Override
    public String toString() {
        return "LFUStrategy{" +
                "priorityQueue=" + priorityQueue +
                '}';
    }
    public T remove() {
        return priorityQueue.poll();
    }
    public void add(T t) {
        if (max == priorityQueue.size()) {
            T remove = remove();
            System.out.println("执行LFU策略,删除的元素是:" + remove);
        } else {
            priorityQueue.offer(t);
        }
    }
}
package com.study.spring.transaction.huancun;
import java.util.PriorityQueue;
/**
 * @author dmz
 * @date Create in 0:08 2019/8/11
 */
public class Main {
    public static void main(String[] args) {
        PriorityQueue<Entity> priorityQueue = new PriorityQueue<>();
        for (int i = 1; i < 7; i++) {
            Entity entity = new Entity(i);
            priorityQueue.add(entity);
            try {
                // 为了将访问时间隔开
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 最大容忍6个元素,元素满了后,执行LFU策略
        LFUStrategy lfuStrategy = new LFUStrategy<>(priorityQueue, 6);
        // 对第一个元素进行访问
//        lfuStrategy.get(1);
        lfuStrategy.add(new Entity(7));
    }
}

在上述代码中,如果我们不访问任何元素,直接执行 lfuStrategy.add(new Entity(7)),那么就会直接移除第一个元素,但是如果我们访问第一个元素,那么就会移除第二个元素。大家可以自己试验,我就不贴运行结果了,太占篇幅


链表实现


实现思路:相比于上一种实现方式,,这里最大的不同就是要自己去实现排序的过程。我们还是直接用JDK中的LinkedList,进行实现。


package com.study.spring.transaction.huancun;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.LinkedList;
/**
 * @author dmz
 * @date Create in 12:03 2019/8/11
 */
@Data
@AllArgsConstructor
public class LFUStrategySecond<T extends Count> {
    private int max;
    private LinkedList<T> linkedList;
    public void add(T t) {
        if (linkedList.size() == max) {
            System.out.println("链表实现LFU策略删除元素:" + remove());
        }
        linkedList.add(t);
    }
    public T remove() {
        return linkedList.removeFirst();
    }
    public T get(int index) {
        T t = linkedList.get(index);
        t.addCount();
        t.setLastVisitTime(LocalDateTime.now());
        // 最小的放到链表头
        linkedList.sort((Comparator<T>) (o1, o2) ->
                o1.getCount() == o2.getCount() ? o1.getLastVisitTime().compareTo(o2.getLastVisitTime())
                        : o1.getCount() - o2.getCount()
        );
        return t;
    }
}
ackage com.study.spring.transaction.huancun;
import java.util.LinkedList;
/**
 * @author dmz
 * @date Create in 12:10 2019/8/11
 */
public class MainSecond {
    public static void main(String[] args) {
        LinkedList<Entity> linkedList = new LinkedList<>();
        linkedList.add(new Entity(1));
        linkedList.add(new Entity(2));
        linkedList.add(new Entity(3));
        linkedList.add(new Entity(4));
        linkedList.add(new Entity(5));
        LFUStrategySecond<Entity> lfuStrategySecond = new LFUStrategySecond<Entity>(5, linkedList);
        // 可以观察,进行访问跟不进行访问,删除元素的区别
  //      lfuStrategySecond.get(0);
        lfuStrategySecond.add(new Entity(6));
    }
}

最近最少使用策略(LRU,Least Recently Used)


根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。


实现思路:我们还是直接利用JDK的Linkedlist来进行实现,只要每次将被访问的元素置于链尾,若空间不够堆链头的数据进行删除即可。

package com.study.spring.transaction.huancun;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.LinkedList;
/**
 * @author dmz
 * @date Create in 12:25 2019/8/11
 */
@Data
@AllArgsConstructor
public class LRUStrategy<T> {
    // 不能小于1
    int max;
    LinkedList<T> linkedList = new LinkedList<>();
    public T get(int index) {
        // 每次获取元素时,将获取到的元素放到链尾
        T t = linkedList.get(index);
        linkedList.remove(t);
        linkedList.addLast(t);
        return t;
    }
    public T remove() {
        return linkedList.removeFirst();
    }
    public void add(T t) {
        if (linkedList.size() == max) {
            System.out.println("LRU删除的元素:"+remove());
        }
        linkedList.add(t);
    }
}

总结:


到这里三种缓存过期策略我们就介绍完了,可能对于最后一种LRU算法介绍的不是很详细,本来是想自定义一个单链表来实现的,不过这两天写链表都写吐了,实在不想写了,偷了个懒,大家可以自己实现下,有任何问题都可以给我留言哦,一定会回复的!
/

相关文章
|
3月前
|
存储 监控 JavaScript
基于布隆过滤器的 Node.js 算法在局域网电脑桌面监控设备快速校验中的应用研究
本文探讨了布隆过滤器在局域网电脑桌面监控中的应用,分析其高效空间利用率、快速查询性能及动态扩容优势,并设计了基于MAC地址的校验模型,提供Node.js实现代码,适用于设备准入控制与重复数据过滤场景。
112 0
|
2月前
|
运维 监控 JavaScript
基于 Node.js 图结构的局域网设备拓扑分析算法在局域网内监控软件中的应用研究
本文探讨图结构在局域网监控系统中的应用,通过Node.js实现设备拓扑建模、路径分析与故障定位,提升网络可视化、可追溯性与运维效率,结合模拟实验验证其高效性与准确性。
176 3
|
2月前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
|
2月前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
粒子群算法模型深度解析与实战应用
|
2月前
|
机器学习/深度学习 算法 安全
小场景大市场:猫狗识别算法在宠物智能设备中的应用
将猫狗识别算法应用于宠物智能设备,是AIoT领域的重要垂直场景。本文从核心技术、应用场景、挑战与趋势四个方面,全面解析这一融合算法、硬件与用户体验的系统工程。
|
4月前
|
机器学习/深度学习 人工智能 算法
AI-Compass 强化学习模块:理论到实战完整RL技术生态,涵盖10+主流框架、多智能体算法、游戏AI与金融量化应用
AI-Compass 强化学习模块:理论到实战完整RL技术生态,涵盖10+主流框架、多智能体算法、游戏AI与金融量化应用
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习模型、算法与应用的全方位解析
深度学习,作为人工智能(AI)的一个重要分支,已经在多个领域产生了革命性的影响。从图像识别到自然语言处理,从语音识别到自动驾驶,深度学习无处不在。本篇博客将深入探讨深度学习的模型、算法及其在各个领域的应用。
675 3
|
4月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
101 1
|
3月前
|
算法 数据可视化
matlab版本粒子群算法(PSO)在路径规划中的应用
matlab版本粒子群算法(PSO)在路径规划中的应用
|
4月前
|
存储 监控 算法
公司员工泄密防护体系中跳表数据结构及其 Go 语言算法的应用研究
在数字化办公中,企业面临员工泄密风险。本文探讨使用跳表(Skip List)数据结构优化泄密防护系统,提升敏感数据监测效率。跳表以其高效的动态数据处理能力,为企业信息安全管理提供了可靠技术支持。
97 0

热门文章

最新文章