LRU算法以及其实现

LRU算法

LRU算法是什么

  • 最近最久未使用

LRU的实现

利用双向链表实现

双向链表的特点就是他的链表是双路的,定义好头结点和尾节点后,利用先进先出(FIFO),最近被放入的数据会最早被获取

  • java实现

    • 定义基本的链表操作节点

      public class Node {
          //键
          Object key;
          //值
          Object value;
          //上一个节点
          Node pre;
          //下一个节点
          Node next;
      
          public Node(Object key, Object value) {
              this.key = key;
              this.value = value;
          }
      }
      
    • 链表基本定义

      • 定义一个LRU类,然后定义它的大小,容量,头节点,尾节点等部分,然后定义一个基本的构造方法
      public class LRU<K, V> {
          //当前大小
          private int currentSize;
          //总容量
          private int capcity;
          //所有的node节点
          private HashMap<K,Node> caches;
          //头结点
          private Node first;
          //尾节点
          private  Node last;
      
          public LRU(int size){
              currentSize=0;
              this.capcity=size;
              caches=new HashMap<K,Node>(size);
          }
      
    • 添加元素

      • 首先先判断是否已经存在,如果是新元素,判断当前大小是否大于等于总容量,防止因为添加导致超出表大小,最后将添加的节点移动到头部。
       public void put(K key,V value){
              //先看看里面是否存在
              Node node =caches.get(key);
              //如果是新元素
              if(node==null){
                  //判断是否超过最大容量
                  if(caches.size()>=capcity){
                      //将最后一个节点删除
                      caches.remove(last.key);
                      removeLast();
                  }
                  //创建新节点
                  node=new Node(key,value);
              }
      
              //如果存在就覆盖旧值
              node.value=value;
              //把元素移到首部
              moveToHead(node);
              caches.put(key,node);
          }
      
    • 访问元素

      • 先判断是否存在,存在的话,先把数据移到头部节点,然后返回旧值。
       public Object get (K key){
              Node node = caches.get(key);
              if(node==null){
                  return null;
              }else {
                  //把访问节点移到首节点
                  moveToHead(node);
                  return node;
              }
          }
      
    • 节点删除操作

      • 在删除的时候需要注意的是,把前后节点的指针给进行相应的更改
       public Object remove(K key){
              Node node= caches.get(key);
              if(node != null){
                  if(node.pre!=null){
                      node.pre.next=node.next;
                  }
                  if (node.next!=null){
                      node.next.pre=node.pre;
                  }
                  if(node==first){
                      first=node.next;
                  }
                  if(node==last){
                      last=node.pre;
                  }
              }
              return caches.remove(key);
          }
      
    • 移动元素到头节点

      • 首先把当前节点移除(类似于删除),然后将其放到首节点
       private void moveToHead(Node node) {
              if (first == node) {
                  return;
              }
              if (node.next != null) {
                  node.next.pre = node.pre;
              }
              if (node.pre != null) {
                  node.pre.next = node.next;
              }
              if (node == last) {
                  last = last.pre;
              }
              if (first == null || last == null) {
                  first = last = node;
                  return;
              }
              node.next = first;
              first.pre = node;
              first = node;
              first.pre = null;
          }
      
  • LRU完成代码

    import java.util.HashMap;
    
    public class LRU<K, V> {
        //当前大小
        private int currentSize;
        //总容量
        private int capcity;
        //所有的node节点
        private HashMap<K,Node> caches;
        //头结点
        private Node first;
        //尾节点
        private  Node last;
    
        public LRU(int size){
            currentSize=0;
            this.capcity=size;
            caches=new HashMap<K,Node>(size);
        }
        /**
         * @Author: sun mingzhi
         * @Description: 添加元素
         * @Date: 2020/1/19 10:06
    
         * @Return: [key, value]
         */
        public void put(K key,V value){
            //先看看里面是否存在
            Node node =caches.get(key);
            //如果是新元素
            if(node==null){
                //判断是否超过最大容量
                if(caches.size()>=capcity){
                    //将最后一个节点删除
                    caches.remove(last.key);
                    removeLast();
                }
                //创建新节点
                node=new Node(key,value);
            }
    
            //如果存在就覆盖旧值
            node.value=value;
            //把元素移到首部
            moveToHead(node);
            caches.put(key,node);
        }
        /**
         * @Author: sun mingzhi
         * @Description: 通过key获取元素
         * @Date: 2020/1/19 10:40
    
         * @Return: 
         */
        public Object get (K key){
            Node node = caches.get(key);
            if(node==null){
                return null;
            }else {
                //把访问节点移到首节点
                moveToHead(node);
                return node;
            }
        }
        /**
         * @Author: sun mingzhi
         * @Description: 通过key删除元素
         * @Date: 2020/1/19 10:42
    
         * @Return: 
         */
        public Object remove(K key){
            Node node= caches.get(key);
            if(node != null){
                if(node.pre!=null){
                    node.pre.next=node.next;
                }
                if (node.next!=null){
                    node.next.pre=node.pre;
                }
                if(node==first){
                    first=node.next;
                }
                if(node==last){
                    last=node.pre;
                }
            }
            return caches.remove(key);
        }
        /**
         * 清除所有节点
         */
        public void clear() {
            first = null;
            last = null;
            caches.clear();
        }
    
        /**
         * 把当前节点移动到首部
         * @param node
         */
        private void moveToHead(Node node) {
            if (first == node) {
                return;
            }
            if (node.next != null) {
                node.next.pre = node.pre;
            }
            if (node.pre != null) {
                node.pre.next = node.next;
            }
            if (node == last) {
                last = last.pre;
            }
            if (first == null || last == null) {
                first = last = node;
                return;
            }
            node.next = first;
            first.pre = node;
            first = node;
            first.pre = null;
        }
    
        /**
         * 移除最后一个节点
         */
        private void removeLast() {
            if (last != null) {
                last = last.pre;
                if (last == null) {
                    first = null;
                } else {
                    last.next = null;
                }
            }
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            Node node = first;
            while (node != null) {
                sb.append(String.format("%s:%s ", node.key, node.value));
                node = node.next;
            }
            return sb.toString();
        }
        public static void main(String[] args) {
            LRU<Integer, String> lru = new LRU<Integer, String>(5);
            lru.put(1, "a");
            lru.put(2, "b");
            lru.put(3, "c");
            lru.put(4,"d");
            lru.put(5,"e");
            System.out.println("原始链表为:"+lru.toString());
    
            lru.get(4);
            System.out.println("获取key为4的元素之后的链表:"+lru.toString());
    
            lru.put(6,"f");
            System.out.println("新添加一个key为6之后的链表:"+lru.toString());
    
            lru.remove(3);
            System.out.println("移除key=3的之后的链表:"+lru.toString());
        }
    }
    
利用LinkedHashMap实现

​ LinkedHashMap底层就是使用HashMap加双链表实现的,而且本身已经实现了按照访问顺序存储,此外LinkedHashMap本身就实现了一个removeEldestEnter用于判断是否需要移除最不常读取的数,方法默认返回false,不会移除元素,只需要重写此方法即可。

import java.util.LinkedHashMap;
import java.util.Map;

public class LRU<K, V> {
    private static final float hashLoadFactory = 0.75f;
    private LinkedHashMap<K,V> map;
    private int cacheSize;

    public LRU(int cacheSize) {
        this.cacheSize = cacheSize;
        int capacity = (int)Math.ceil(cacheSize / hashLoadFactory) + 1;
        //true 表示让LinkedHashMap按照访问顺序来进行排序,最近访问的放在头部,最后访问的放在尾部
        map = new LinkedHashMap<K,V>(capacity, hashLoadFactory, true){
            private static final long serialVersionUID = 1;
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                //当map中的数据量大于某个指定的缓存个数的时候,就自动删除最老的元素
                return size() > LRU.this.cacheSize;
            }
        };
    }

    public synchronized V get(K key) {
        return map.get(key);
    }

    public synchronized void put(K key, V value) {
        map.put(key, value);
    }

    public synchronized void clear() {
        map.clear();
    }

    public synchronized int usedSize() {
        return map.size();
    }

    public void print() {
        for (Map.Entry<K, V> entry : map.entrySet()) {
            System.out.print(entry.getValue() + "--");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        LRU<Integer, String> lru = new LRU<Integer, String>(5);
        lru.put(1, "a");
        lru.put(2, "b");
        lru.put(3, "c");
        lru.put(4,"d");
        lru.put(5,"e");
        System.out.println("原始链表为:");
        lru.print();
        System.out.println("获取key为4的元素之后的链表:");
        lru.get(4);
        lru.print();
        System.out.println("新添加一个key为6之后的链表:");
        lru.put(6,"f");
        lru.print();
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在风能领域,准确预测风速对于风电场的运行与管理至关重要。Matlab作为一个强大的数学计算和数据分析平台,被广泛应用于风速预测模型的构建。本文将深入探讨基于四种风速——随机风、基本风、阵风和渐变风的组合风速预测技术。 我们来理解这四种风速类型: 1. **随机风**:随机风是指风速呈出随机性的变化,通常由大气湍流引起。在建模中,通常通过统计方法如高斯分布或Weibull分布来模拟这种不确定性。 2. **基本风**:基本风速是指在无特定扰动条件下的平均风速,它是长期观测结果的平均值,通常用于结构设计和风能评估。 3. **阵风**:阵风是短时间内风速显著增强的象,对建筑物和风力发电机造成的主要威胁之一。阵风的预测涉及到风的脉动特性分析。 4. **渐变风**:渐变风是指风速随时间和空间逐渐变化的过程,常见于风向转变或地形影响下的风场变化。 在Matlab中,利用这四种风速类型进行组合预测,可以提高预测的准确性。预测模型可能包括以下几个步骤: 1. **数据收集与预处理**:收集历史风速数据,包括随机风、基本风、阵风和渐变风的数据,进行异常值检测、缺失值填充以及数据标准化。 2. **特征工程**:提取风速变化的相关特征,如平均值、标准差、极值、频率分布等,这些特征可能对预测有重要影响。 3. **模型选择**:可以选择多种预测模型,如时间序列分析(ARIMA、状态空间模型等)、机器学习算法(线性回归、决策树、支持向量机、神经网络等)或深度学习模型(LSTM、GRU等)。 4. **模型训练**:利用历史数据训练选定的模型,调整模型参数以优化性能,例如通过交叉验证来避免过拟合。 5. **模型验证与评估**:使用独立的测试集验证模型预测效果,常见的评估指标有均方误差(MSE)、平均绝对误差(MAE)和决定系数(R²)。 6. **组合预测**:结合四种风速的不同模型预测结果,可以采用加权平均、集成学习(如bagging、boosting)等方式,以提升整体预测精度。 7. **实时更新与动态调整**:实际应用中,模型需要不断接收新的风速数据并进行在线更新,以适应风场环境的变化。 通过以上步骤,可以构建一个综合考虑各种风速特性的预测系统,这对于风电场的功率输出预测、风电设备的维护计划以及电网调度都具有重要价值。然而,需要注意的是,每个风场的地理环境、气候条件和设备状况都有所不同,因此模型的建立应根据实际情况进行定制和优
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值