zoukankan      html  css  js  c++  java
  • 操作系统之LRU算法 C语言链表实现

    LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

    为什么要使用链表实现呢,因为这个页面不会很多,内存和资源开销都小

    在计算机中,开销往往是需要考虑的,我们不希望占用过多的系统资源,动态路由小型网络使用RIP(Bellman-Ford Routing Algorithm),大型网络设备用的就是OSPF(dijkstra),当然也有很多方面的考虑,比如RIP配置和管理更简单,RIP为了避免出现网络延迟太高,也将路由器最大的允许跳数设为15

    我们存储的时候就按照时间吧,末尾为刚刚使用的,淘汰前面的

    然后我们来考虑下这个算法,保证我们不使用无关变量。这个cache是空的

    进行一次请求需要查看我当前的cache里是否存在这个数据

    1存在

      存在就比较简单了,直接取出数据,页面数据不变,并把这个结点放在最后

    2不存在

      2.1cache满

      把最靠前的页面用读取数据的数据覆盖,然后把它放到最后的cache

      2.2cache不满

      直接去读取数据,然后把他放在最后的页面

    我需要维护的是一个编号(或者说地址)还有后结点,然后查询肯定是O(1)的,这是内部完成的,不需要我考虑(直接得到地址去取数据)

    缺页中断都对应了一个硬件操作,就是去取这个数据

    #include <stdio.h>
    #include <stdlib.h>
    struct node
    {
        int id;
        struct node *next;
    } * head, *tail, *p;
    void PushBack()
    {
        /* 
        pre没有意义,仅需要多保留一个尾结点
        p->pre = tail; //使pre指向前一个节点,循环可得到反向链表
        */
        p->next = NULL;
        tail->next = p;
        tail = p;
    }
    void fun()
    {
        struct node *q;
        q = head;
        while (q->next != NULL)
        {
            if (q->next->id == p->id)//不缺页
            {
                PushBack();
                p = q->next;
                q->next = p->next;
                free(p);
                return; //执行完全部操作停掉
            }
            q = q->next;
        }
        printf("发生缺页中断 %d
    ",p->id);
        PushBack();
        p = head->next;
        head->next = p->next;
        free(p);
    }
    int main()
    {
        int sum, n, i;
        sum = 0;         //初始cache内没有数据
        scanf("%d", &n); //读入页数
        head = (struct node *)malloc(sizeof(struct node));
        head->next = NULL;
        tail = head;
        while (1)
        {
            p = (struct node *)malloc(sizeof(struct node));
            scanf("%d", &p->id);
            if (p->id < 0)
            {
                break;
            }
            else
            {
                if (sum < n) //cache未满,放至后面
                {
                    PushBack();
                    printf("发生缺页中断 %d
    ",p->id);
                    sum += 1; //并对cache+1
                }
                else
                {
                    fun();
                }
            }
        }
        return 0;
    }

    事后来看,我说pre没有意义是不对的,因为实际上并不是乱序的,往往我们先访问的到的会被继续访问,并不是一个完全的均摊复杂度。

    所以应该记录pre进行倒序,有兴趣的可以实现一下,不过我还是觉得c++好写,但是内部肯定是更厉害的

    c++实现就用list搞一下啊,把最近访问的放到最前面

    #include<iostream>
    #include<list>
    void fun(std::list<int>&L,int x)
    {
        for(std::list<int>::iterator it=L.begin();it!=L.end();it++)
        {
            if(*it==x)
            {
                L.push_front(x);
                L.erase(it);
                return;
            }
        }
        std::cout<<"发生缺页中断 "<<x<<std::endl;
        L.pop_back();
        L.push_front(x);
    }
    int main()
    {
        std::list<int>L;
        int sum, n, i,x;
        sum = 0;         //初始cache内没有数据
        std::cin>>n; //读入页数
        while (true)
        {
            scanf("%d", &x);
            if (x < 0)
            {
                break;
            }
            else
            {
                if (sum < n) //cache未满,放至后面
                {
                    L.push_front(x);
                    std::cout<<"发生缺页中断 "<<x<<std::endl;
                    sum += 1; //并对cache+1
                }
                else
                {
                    fun(L,x);
                }
            }
        }
        return 0;
    }
    C++ list 因为内部就是双向链表
    public class LRUCache{
        private int limit;
        private HashMap<String,Node> hashMap;
        private Node head;
        private Node end;
     
        public LRUCache(int limit)
        {
            this.limit = limit;
            hashMap = new HashMap<String,Node>();
        }
     
        public String get(String key){
            Node node = hashMap.get(key);
            if(node ==null)
                return null;
            refreshNode(node);
            return node.value;
        }
     
        public void put(String key,String value){
            Node node = hashMap.get(key);
            if(node == null){
                if(hashMap.size()>=limit)
                {
                    String oldKey = removeNode(head);
                    hashMap.remove(oldKey);
                }
                node = new Node(key,value);
                addNode(node);
                hashMap.put(key,node)
            }else{
                node.value = value;
                refreshNode(node);
            }
        }
     
        public void remove(String key){
            Node node = hashMap.get(key);
            removeNode(node);
            hashMap.remove(key);
        }
     
     
        private void refreshNode(Node node)
        {
            if(node == end)
                return;
            removeNode(node);
            addNode(node);
        }
     
     
        public String removeNode(Node node){
            if(node == end)
                end = end.pre;
            else if(node ==head)
                head = head.next;
            else
                {
                    node.pre.next = node.next;
                    node.next.pre = node.pre;
                }
            return node.key;
        }
         
         public void addNode(Node node)
         {
            if(end!=null)
            {
                end.next = node;
                node.pre = end;
                node.next = null;
            }
            end = node;
            if(head == null)
                head = node;
         }
     
    }
    Java实现(高并发线程安全使用ConcurrentHashMap
  • 相关阅读:
    hive 数据hadoop数据etl交换
    团队冲刺(三)
    团队冲刺(二)
    CVPR2019论文热词云的实现
    团队冲刺(一)
    团队开发之电梯演讲----团队项目介绍--“益青春APP”
    android的finish()方法
    java web项目通过外网ip访问
    MySQL出现错误1205-Lock wait timeout exceeded; try restarting transaction
    团队开发(自己的理解)
  • 原文地址:https://www.cnblogs.com/BobHuang/p/11224447.html
Copyright © 2011-2022 走看看