题目描述
请设计一个文件缓存系统,该文件缓存系统可以指定缓存的最大值(单位为字节)
文件缓存系统有两种操作:存储文件(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,最近访问时间更新到最新时间
-
任何两个文件的最近访问时间不会重复
-
文件名不会为空,均为小写字母,最大长度为10
-
缓存空间不足时,不能存放新文件
-
每个文件大小都是大于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(); // 最终输出缓存内容
}
}
4711

被折叠的 条评论
为什么被折叠?



