操作系统OPT算法(最佳页面替换算法)

简介: 操作系统OPT算法(最佳页面替换算法)

操作系统OPT算法(最佳页面替换算法)

简介:本文是博主当年学习操作系统的时候,所写的操作系统的OPT算法。

import sun.plugin.javascript.navig.Link;
import java.util.*;
class Pair
{
    public Pair(int first, int second)
    {
        this.first = first;
        this.second = second;
    }
    public int first;
    public int second;
}
// opt算法的思路是
// 将每个数字和它的出现了的索引的队列做成映射表
// 每次比较内存里面的元素的索引队列的对首元素谁最大
// 最大的那个滚
public class Main
{
    static void ListTrave(List<Integer> list)
    {
        System.out.print("list: ");
        for (int i = 0; i < list.size(); ++ i)
        {
            System.out.print(list.get(i) + " ");
        }
        System.out.println();
    }
    static void QueueTrave(Queue<Integer> q)
    {
        System.out.print("Queue:");
        Iterator<Integer> it = q.iterator();
        while(it.hasNext())
        {
            System.out.print(it.next() + " ");
        }
        System.out.println();
    }
    static void MapTrave(Map<Integer, Queue<Integer> > map)
    {
        System.out.println("map:");
        for (Integer i : map.keySet())
        {
            System.out.print(i + ": ");
            Iterator it = map.get(i).iterator();
            while(it.hasNext())
            {
                System.out.print(it.next() + " ");
            }
            System.out.println();
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner (System.in);
        // 内存访问顺序
        System.out.println("内存的访问顺序:");
        int numPage = in.nextInt();
//        System.out.println(numPage);
        // 页面中断的次数
        int cnt = 0;
        // 内存块的数量
        System.out.println("内存的数量:");
        int numMemory = in.nextInt();
        System.out.println("输入内存:");
        Map<Integer, Queue<Integer> > map = new HashMap<>();
        // 把每个元素存一遍
        // 用队列的好处是 可以保证查询的效率是O(1)
        Queue<Integer> q = new LinkedList<>();
        // 存放当前内存中的元素
        List<Integer> list = new ArrayList<>();
        // 把每个元素和它的索引队列做成映射表
        for (int i = 0; i < numPage; ++ i)
        {
            int num = in.nextInt();
            q.add(num);
            if (map.containsKey(num))
            {
                Queue<Integer> queue = map.get(num);
                queue.add(i);
                map.put(num, queue);
            }
            else
            {
                Queue<Integer> queue = new LinkedList<>();
                queue.add(i);
                map.put(num, queue);
            }
        }
        // 检查
//        QueueTrave(q);
//        MapTrave(map);
        for (int i = 0; i < numPage; ++ i)
        {
            int num = q.poll();
            if (list.size() < numMemory)
            {
                if (!list.contains(num))
                {
                    list.add(num);
                    map.get(num).poll();
                    cnt ++;
                }
            }
            else
            {
                if (list.contains(num))
                {
                    // 这里是就算 内存里面存在这个元素 但是也是还要假替换的 就是
                    // 把这次新来的num的对应的队列的索引也删掉
                    map.get(num).poll();
                }
                else
                {
                    check((ArrayList<Integer>) list, map);
                    cnt ++;
                    list.add(num);
                    // 把num对应的索引删掉一个
                    map.get(num).poll();
                }
            }
//            ListTrave(list);
        }
//        System.out.println("cnt: " + cnt);
        System.out.printf("%.1f%%", (double)cnt / (double)numPage * 100);
    }
    // 返回那个要滚的数字
    static int check(ArrayList<Integer> list, Map<Integer, Queue<Integer> > map)
    {
//        System.out.println("enter:");
//        ListTrave(list);
//        MapTrave(map);
        // 最后要滚的数字 和 对应的索引
        // 先设置为list的第一个元素
        // 如果这个数字对应的队列映射为空那么 用负数代表索引 表示无穷远
        int t = list.get(0);    // t是内存中的数字
        int idx = 0;  // t对应的索引
        int t2 = map.get(t).size();  // 索引对应的数字对应的队列的大小
        int t3;                     // 队列第一个数字的索引
        // 判断是否为空的情况
        if (t2 == 0) t3 = -1;
        else t3 = map.get(t).peek();
//        System.out.println("t1 + idx + t2 + t3=" + t + " " + idx + " " + t2 + " " + t3);
        Pair num = new Pair(idx, t3);  // num存放需要删除的数字的索引和这个数字对应的队列的队首
        if (num.second == -1)  // 如果找到-1的后面的就不用找了
        {
            list.remove(num.first);  // remove是按照索引删除
            return list.get(num.first);
        }
//        System.out.println("t1 + idx + t2 + t3=" + t + " " + idx + " " + t2 + " " + t3);
        for (int i = 1; i < list.size(); ++ i)
        {
//            ListTrave(list);
            t = list.get(i);
            idx = i;
            t2 = map.get(t).size();
            if (t2 == 0) t3 = -1;
            else t3 = map.get(t).peek();
//            System.out.println("t1 + idx + t2 + t3=" + t + " " + idx + " " + t2 + " " + t3);
            if(t3 == -1)
            {
                list.remove(idx);
                return list.get(num.first);
            }
            else
            {
                // 让更远的代替
                if (num.second < t3)
                {
                    num = new Pair(idx, t3);
                }
            }
        }
        // 最后second最大的滚
        list.remove(num.first);
        return list.get(num.first);
    }
}

如果大家觉得有用的话,可以关注我下面的微信公众号,极客李华,我会在里面更新更多行业资讯,企业面试内容,编程资源,如何写出可以让大厂面试官眼前一亮的简历等内容,让大家更好学习编程,我的抖音,B站也叫极客李华。大家喜欢也可以关注一下

相关文章
|
1月前
|
算法 调度 UED
探索操作系统的心脏:调度算法的奥秘与影响
【10月更文挑战第9天】 本文深入探讨了操作系统中至关重要的组件——调度算法,它如同人体的心脏,维持着系统资源的有序流动和任务的高效执行。我们将揭开调度算法的神秘面纱,从基本概念到实际应用,全面剖析其在操作系统中的核心地位,以及如何通过优化调度算法来提升系统性能。
|
13天前
|
算法
虚拟内存的页面置换算法有哪些?
【10月更文挑战第25天】不同的页面置换算法各有优缺点,在实际应用中,操作系统会根据不同的应用场景和系统需求选择合适的页面置换算法,或者对算法进行适当的改进和优化,以平衡系统的性能、开销和资源利用率等因素。
33 5
|
19天前
|
算法 大数据 Linux
深入理解操作系统之进程调度算法
【10月更文挑战第24天】本文旨在通过浅显易懂的语言,带领读者深入了解操作系统中的进程调度算法。我们将从进程的基本概念出发,逐步解析进程调度的目的、重要性以及常见的几种调度算法。文章将通过比喻和实例,使复杂的技术内容变得生动有趣,帮助读者建立对操作系统进程调度机制的清晰认识。最后,我们还将探讨这些调度算法在现代操作系统中的应用和发展趋势。
|
1月前
|
算法 调度 UED
深入理解操作系统的进程调度算法
【10月更文挑战第7天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。它不仅影响系统的性能和用户体验,还直接关系到资源的合理分配。本文将通过浅显易懂的语言和生动的比喻,带你一探进程调度的秘密花园,从最简单的先来先服务到复杂的多级反馈队列,我们将一起见证算法如何在微观世界里编织宏观世界的和谐乐章。
|
1月前
|
边缘计算 算法 调度
探究操作系统的心脏:调度算法的进化与影响
【10月更文挑战第2天】 本文深入探讨了操作系统中核心组件——调度算法的历史演变、关键技术突破及其对现代计算的影响。通过详细回顾从单任务到多任务、实时系统及分布式计算环境下调度算法的发展,文章揭示了这些算法如何塑造我们的数字世界,并对未来的趋势进行了展望。不同于传统的摘要,本文特别聚焦于技术细节与实际应用的结合点,为读者提供一幅清晰的技术演进蓝图。
46 4
|
1月前
|
算法 调度 UED
探索操作系统的心脏:进程调度算法
【9月更文挑战第32天】在数字世界的每一次心跳中,都隐藏着一个不为人知的英雄——进程调度算法。它默默地在后台运作,确保我们的命令得到快速响应,应用程序平稳运行。本文将带你走进操作系统的核心,一探进程调度的奥秘,并通过代码示例揭示其背后的智慧。准备好跟随我一起深入这趟技术之旅了吗?让我们开始吧!
|
2月前
|
算法 调度
操作系统的心脏:深入解析进程调度算法
本文旨在深入探讨现代操作系统中的核心功能之一——进程调度。进程调度算法是操作系统用于分配CPU时间片给各个进程的机制,以确保系统资源的高效利用和公平分配。本文将详细介绍几种主要的进程调度算法,包括先来先服务(FCFS)、短作业优先(SJF)、时间片轮转(RR)以及优先级调度(PS)。我们将分析每种算法的基本原理、优缺点及其适用场景。同时,本文还将讨论多级反馈队列(MFQ)调度算法,并探讨这些算法在实际应用中的表现及未来发展趋势。通过深入解析这些内容,希望能够为读者提供对操作系统进程调度机制的全面理解。
|
2月前
|
存储 算法 前端开发
深入理解操作系统:进程调度与优先级队列算法
【9月更文挑战第25天】在操作系统的复杂世界中,进程调度是维持系统稳定运行的核心机制之一。本文将深入探讨进程调度的基本概念,分析不同的进程调度算法,并着重介绍优先级队列算法的原理和实现。通过简洁明了的语言,我们将一起探索如何优化进程调度,提高操作系统的效率和响应速度。无论你是计算机科学的初学者还是希望深化理解的专业人士,这篇文章都将为你提供有价值的见解。
|
1月前
|
算法
有哪些页面置换算法?
页面置换算法(Page Replacement Algorithms)在计算机操作系统中用于管理虚拟内存。
|
2月前
|
人工智能 算法 大数据
探究操作系统的心脏:调度算法的进化与影响
本文深入探讨了操作系统中核心组件——调度算法的发展及其对系统性能的影响。通过分析先来先服务、短作业优先、时间片轮转等传统调度算法,阐述了它们的原理和优缺点。同时,讨论了现代调度算法如多级队列和优先级调度在提高系统响应速度和处理能力方面的作用。文章还探讨了实时系统中的调度挑战,以及如何通过优化调度策略来满足不同应用场景下的性能需求。