文件缓存系统 华为OD/E卷200分 备考记录

题目描述

请设计一个文件缓存系统,该文件缓存系统可以指定缓存的最大值(单位为字节)

文件缓存系统有两种操作:存储文件(put)和读取文件(get)

操作命令为 put fileName fileSize或者 get fileName

存储文件是把文件放入文件缓存系统中;读取文件是从文件缓存系统中访问已存在的文件,如果文件不存在,则不作任何操作。

当缓存空间不足以存放新的文件时,根据规则删除文件,直到剩余空间满足新的文件大小为止,再存放新文件。

具体的删除规则为: 文件访问过后,会更新文件的最近访问时间和总的访问次数,当缓存不够时,按照第一优先顺序为访问次数从少到多,第二顺序为 时间从老到新的方式来删除文件。

输入描述

第一行为缓存最大值m (整数,取值范围为0<m<=52428800)

第二行为文件操作序列个数n(0<=n<=300000)

从第三行起为文件操作序列,每个序列单独一行

文件操作定义为 op file_name file_size

file_name是文件名,file_size是文件大小

输出描述

输出当前文件缓存中的文件名列表,文件名用英文逗号分隔,按字典顺序排序

如: a,c

如果文件缓存中没有文件,则输出 NONE

补充说明
  1. 如果新文件的文件名和文件缓存中已有的文件名相同,则不会放在缓存中

  2. 新的文件第一次存入到文件缓存中时,文件的总访问次数不会变化,文件的最近访问时间会更新到最新时间

  3. 每次文件访问后,总访问次数加1,最近访问时间更新到最新时间

  4. 任何两个文件的最近访问时间不会重复

  5. 文件名不会为空,均为小写字母,最大长度为10

  6. 缓存空间不足时,不能存放新文件

  7. 每个文件大小都是大于0的整数

示例1

输入:  

50

6  

put a 10  

put b 20  

get a  

get a  

get b  

put c 30  

输出:

a,c

示例2

输入:  
50  
1  
get file  
输出:
​​​​​​NONE 

题解(Java)
import java.util.*;

public class Main {
    // 文件类,表示缓存系统中的文件对象
    static class File {
        private String fileName;   // 文件名
        private int fileSize;      // 文件大小
        private int LastTime;      // 最近一次访问时间
        private int count;         // 总访问次数

        // 构造函数:初始化文件名、大小、操作时间
        File(String name, int size, int t) {
            fileName = name;
            fileSize = size;
            count = 0;            // 初始访问次数为0
            LastTime = t;         // 初始最近访问时间为创建时间
        }

        // 文件名
        public String getFileName() {
            return fileName;
        }

        // 获取最近访问时间(用于缓存替换策略)
        public int getLastTime() {
            return LastTime;
        }

        // 获取总访问次数(用于缓存替换策略)
        public int getCount() {
            return count;
        }

        // 获取文件大小(用于空间管理)
        public int getFileSize() {
            return fileSize;
        }

        // 设置最近访问时间(当文件被访问时更新)
        public void setTime(int t) {
            LastTime = t;
        }

        // 增加访问次数(当文件被访问时调用)
        public void addCount() {
            count++;
        }
    }

    // 文件系统类,管理缓存逻辑
    static class FileSystem {
        private int m;             // 剩余可用容量
        private List<File> files;  // 当前缓存中的文件列表
        private HashSet<String> set; // 快速查找文件名是否存在

        // 构造函数:初始化缓存容量
        FileSystem(int m) {
            this.m = m;
            files = new ArrayList<>();
            set = new HashSet<>();
        }

        // 删除优先级最低的文件(缓存替换策略)
        public void deleteFile() {
            // 排序规则:优先删除访问次数少的,次数相同则删除最近访问时间早的
            files.sort(Comparator.comparing(File::getCount)
                    .thenComparing(File::getLastTime));

            // 删除第一个文件(优先级最低的)
            m += files.get(0).getFileSize();  // 释放空间
            set.remove(files.get(0).fileName); // 从集合移除
            files.remove(0);                   // 从列表移除
        }

        // 添加文件到缓存系统
        public void addFile(File file) {
            // 如果文件已存在,直接返回(不允许重复添加)
            if (set.contains(file.fileName)) {
                return;
            }

            // 当空间不足时,循环删除文件直到足够容纳新文件
            while (file.getFileSize() > m) {
                deleteFile();
            }

            // 添加新文件到系统
            set.add(file.fileName);    // 记录文件名
            m -= file.getFileSize();    // 扣除空间
            files.add(file);           // 加入列表
        }

        // 访问文件(更新访问时间和次数)
        public void getFile(String s, int t) {
            // 如果文件不存在于缓存中,直接返回
            if (!set.contains(s)) {
                return;
            }

            // 遍历找到目标文件并更新状态
            for (File file : files) {
                if (file.getFileName().equals(s)) {
                    file.setTime(t);   // 更新最近访问时间为当前操作序号
                    file.addCount();     // 增加访问次数
                    return;
                }
            }
        }

        // 输出当前缓存中按文件名排序的文件列表
        public void print() {
            if (set.isEmpty()) {
                System.out.println("NONE");  // 缓存为空时输出NONE
                return;
            }

            StringJoiner res = new StringJoiner(",");  // 用逗号连接文件名
            files.sort(Comparator.comparing(File::getFileName)); // 按文件名排序
            for (int i = 0; i < files.size(); i++) {
                res.add(files.get(i).getFileName());  // 逐个添加文件名
            }
            System.out.println(res);  // 输出结果
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int max = sc.nextInt();        // 读取缓存最大容量
        int n = sc.nextInt();          // 读取操作次数
        sc.nextLine();                 // 清除换行符

        FileSystem fileSystem = new FileSystem(max);  // 初始化文件系统

        for (int i = 0; i < n; i++) {  // 处理每条操作
            String[] s = sc.nextLine().split(" ");
            if (s[0].equals("put")) {  // 添加文件操作
                int fileSize = Integer.parseInt(s[2]);
                // 只有文件大小<=缓存总容量时才允许添加(否则会被后续循环删除处理)
                if (fileSize <= max) {
                    fileSystem.addFile(new File(s[1], fileSize, i));
                }
            } else {  // 访问文件操作(get)
                fileSystem.getFile(s[1], i);  // 传入当前操作序号作为时间戳
            }
        }
        fileSystem.print();  // 最终输出缓存内容
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunriseCs001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值