操作系统:Java模拟页面置换算法(最佳置换算法、先进先出算法、最近最久未使用算法)


本人是个新手,写下博客用于自我复习、自我总结。
本人编写算法水平不高,可能会有错误,仅供各位参考。


import java.util.Scanner;

/**
 * @author zsx
 * @Date: 2020/6/8
 * 说明:本次算法的编写不算成功,考虑到一个方面后,另一方面就又会出现漏洞。
 *      而在这个不断修补的过程中,使得整体算法变得不够合理。
 *      希望之后在编写程序时,能够考虑好每个方面。
 *      虽然设计的不合理,但是四种页面置换算法也算是实现了。
 * */
public class PageReplace {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请问您想为进程分配几个物理块(推荐 3或4)?");
		int blockNum = sc.nextInt(); // 物理块数
		int blockArr[] = new int[blockNum]; // 根据物理块数建立物理块数组
		for (int k = 0; k < blockNum; k++) { // 初始化物理块数组
			blockArr[k] = -1; // -1表示当前位置没有页面存放
		}
		
		// 初始化页面号引用串
		int arr[] = { 1, 2, 5, 7, 5, 7, 1, 4, 3, 5, 6, 4, 3, 2, 1, 5, 2 };

		// 为最近最久未使用算法做准备
		int time[] = new int[blockNum]; // 用数组来判断每个页面上次被调用的时间(即在物理块中的等待时长)
		// 初始化得到的结果举例: time{2,1,0} 意味着:
		// 物理块的  0号位已经过了2次操作未被调用
		//          1号位已经过了1次操作未被调用
		//          2号位已经过了0次操作未被调用,即刚被调用
		// 因此如果之后该位置的页面被替换或者被调用,则将该页面下标位置的元素重置为0
		// 然后 其他位置元素,自加一
		// 而每次替换的页面都是这个值最大的位置上的页面
		int timeIndex = 0; // 用于记录哪个页面被调用
		
		// 为最少使用算法做准备
		int arrNoRepeat[] = new int[arr.length]; // 首先对arr数组去重
		int arrIndex = 0; // 记录arrNoRepeat中存放数据的个数
		for(int b = 0; b < arr.length; b++){
			if(arrIndex == 0){ // 只要arrNoRepeat数组为空,那就先把第一个值存入
				arrNoRepeat[0] = arr[0];
				arrIndex++;
				continue;
			}
			for(int c = 0; c < arrIndex ; c++){
				if(arr[b] == arrNoRepeat[c]){ // 只要重复,就跳出循环
					break;
				}
				if(c+1 == arrIndex){ // 遍历到arrNoRepeat最后一位仍没有重复,就把这个值存放进来
					arrNoRepeat[c+1] = arr[b];
					arrIndex++;
					break;
				}
			}
		}
		int time1[] = new int[arrIndex]; // 用来记录每个页面的使用次数,它和arrNoRepeat的页面号一一对应
		for(int g = 0; g < arrIndex; g++){
			// 初始化time1
			time1[g] = 0;
		}
		
		System.out.println("物理块初始化过程:");
		/**
		 * 功能:初始化物理块数组 因为物理块最开始必然是空的,因此必然会根据物理块大小先存放相应个数的页面
		 * (因为该部分每个算法都要做,放进算法中重复率太高,因此拿出来单独处理)
		 * */
		int position = blockNum; // 用于判断物理块什么时候第一次存满
		for (int i = 0; i < arr.length; i++) {
			// 如果说物理块中已经没有空位置,就跳出循环,开始算法
			if (blockArr[blockNum - 1] != -1) {
				break;
			}
			for (int j = 0; j < blockNum; j++) {
				// 只要物理块当前位置没存放页面,就立刻存放新页面
				if (blockArr[j] == -1) {
					blockArr[j] = arr[i];
					// 记录当前存放位置的下标,time就不自加这个位置,同时这个位置置0
					timeIndex = j;
					time[j] = 0;
					
					// 判断当前页面在arrNoRepeat中的位置,让其访问次数+1
					for(int d = 0; d < arrIndex; d++){
						if(arr[i] == arrNoRepeat[d]){ //找到位置
							time1[d]++;
							break;
						}
					}
					
					blockOutput(blockArr);
					break;
				}
				
				// 如果遇到了相同的页面,跳过当前页面,记录的编号要向后推移
				if (blockArr[j] == arr[i]) {
					// position就是为了这种情况准备的,方便后续算法进行循环处理
					position++;
					// 记录当前存放位置的下标,time就不自加这个位置,同时这个位置置0
					timeIndex = j;
					time[j] = 0;
					
					// 判断当前页面在arrNoRepeat中的位置,让其访问次数+1
					for(int d = 0; d < arrIndex; d++){
						if(arr[i] == arrNoRepeat[d]){ //找到位置
							time1[d]++;
							break;
						}
					}
					
					System.out.println("物理块无变化");
					break;
				}
			}
			for (int m = 0; m < blockNum; m++) {
				if (m == timeIndex) { // 当前操作页面不加1
					continue;
				}
				// 其他未操作页面,等待时长自加1
				time[m]++;
			}
		}
		
		// 设立这些tranArr是为了避免blockArr数据被修改
		int tranArr[] = new int[blockNum];
		for(int a = 0; a < blockNum; a++){
			tranArr[a] = blockArr[a];
		}
		System.out.println("");
		System.out.println("物理块初始化的结果:");
		blockOutput(blockArr);
		System.out.println("最佳置换算法:");
		Optimal(arr, tranArr, blockNum, position);   // 最佳置换算法
		
		int tranArr1[] = new int[blockNum];
		for(int a = 0; a < blockNum; a++){
			tranArr1[a] = blockArr[a];
		}
		System.out.println("");
		System.out.println("物理块初始化的结果:");
		blockOutput(blockArr);
		System.out.println("先进先出算法:");
		FIFO(arr, tranArr1, blockNum, position);      // 先进先出算法
		
		int tranArr2[] = new int[blockNum];
		for(int a = 0; a < blockNum; a++){
			tranArr2[a] = blockArr[a];
		}
		System.out.println("");
		System.out.println("物理块初始化的结果:");
		blockOutput(blockArr);
		System.out.println("最近最久未使用算法:");
		LRU(arr, tranArr2, blockNum, position, time); // 最近最久未使用算法
		
		int tranArr3[] = new int[blockNum];
		for(int a = 0; a < blockNum; a++){
			tranArr3[a] = blockArr[a];
		}
		System.out.println("");
		System.out.println("物理块初始化的结果:");
		blockOutput(blockArr);
		System.out.println("最少使用算法:");
		LFU(arr, tranArr3, blockNum, position, arrNoRepeat, arrIndex, time1); // 最少使用算法
	}

	/**
	 * 最佳置换算法:所选择的被淘汰页面是以后永不使用或最长时间不再被访问的页面
	 * 相关参数:
	 *   arr:存放页面号的待处理原数组
	 *   blockArr: 物理块中存放页面号的数组
	 *   blockNum: 记录物理块大小
	 *   position: 记录算法中循环的起始位置
	 * */
	public static void Optimal(int arr[], int blockArr[], int blockNum, int position) {
		int index = 0;     // 用于记录应该被淘汰页面的下标
		int judge = 0;     // 用于记录页面在以后没被访问的最长时间
		int pageExist = 0; // 用于判断页面是否存在于物理块数组中
		
		// 请求调入页面次数,用于判断缺页率(初始值一定是物理块大小次)
		int requestReplace = blockNum;
		
		for (int i = position; i < arr.length; i++) {
			// 拿到新页面,首先判断,它是否是物理块中已经存在的页面
			for (int j = 0; j < blockNum; j++) {
				// 如果当前页面存在于物理块中,就去判断下一个页面
				if (arr[i] == blockArr[j]) {
					System.out.println("物理块无变化");
					break;
				}
				if (judge == arr.length - 1) {
					// 如果找到了以后永不使用的页面,就不再判断物理块中其他页面
					// 因为如果需要淘汰页面,就淘汰这个永不使用的页面即可
				} else {
					// 找出物理块数组中最应该被替换的页面
					for (int k = i + 1; k < arr.length; k++) {
						// 寻找最长时间不被访问的页面
						if (blockArr[j] == arr[k]) {
							if (k > judge) { //如果当前页面比上一个页面以后未被使用的时间长
								index = j;   // 暂且认为当前页面是被淘汰页面,记录它的下标
								judge = k;   // 更改数值,去和下个满足条件的页面判断
								break;
							} else { // 如果当前页面没有上一个页面以后未被使用的时间长,就退出循环
								break;
							}
						}
						// 如果遍历到原数组的尾部 也没再找到一个和当前页面相同的页面
						// 那么这个页面肯定是 以后永不使用的页面
						if (k == arr.length - 1) {
							index = j; // 记录它的下标
							judge = k; // 记录它的最值,且当前这个值一定是arr.length-1
							break;
						}
					}
				}
				pageExist++;
				// 当pageExist的大小变成了物理块大小,意味着当前页面不在物理块中,需要替换掉不满足最佳置换的页面
				if (pageExist == blockNum) { 
					// 通过上面得到的index下标,替换这个需要被淘汰的页面
					blockArr[index] = arr[i];
					// 请求调入页面次数加1
					requestReplace++;
					
					blockOutput(blockArr);
				}
			}
			index = 0;     // 归零初始化
			judge = 0;     // 归零初始化
			pageExist = 0; // 归零初始化
		}
		pageMissingRate(requestReplace, arr); // 计算缺页率
	}

	/**
	 * 先进先出算法:总是淘汰最先进入内存的页面
	 * 相关参数:
	 *   arr:存放页面号的待处理原数组
	 *   blockArr: 物理块中存放页面号的数组
	 *   blockNum: 记录物理块大小
	 *   position: 记录算法中循环的起始位置
	 * */
	public static void FIFO(int arr[], int blockArr[], int blockNum, int position) {
		int index = 0;     // 用于记录应该被淘汰页面的下标(相当于指针)
		int pageExist = 0; // 用于判断页面是否存在于物理块数组中
		
		// 请求调入页面次数,用于判断缺页率
		int requestReplace = blockNum;
		
		for (int i = position; i < arr.length; i++) {
			// 拿到新页面,首先判断,它是否是物理块中已经存在的页面
			for (int j = 0; j < blockNum; j++) {
				// 如果当前页面存在于物理块中,就去判断下一个页面
				if (arr[i] == blockArr[j]) {
					System.out.println("物理块无变化");
					break;
				}
				pageExist++;
				// 当pageExist的大小变成了物理块大小,意味着当前页面不在物理块中,需要替换掉不满足先进先出的页面
				if (pageExist == blockNum) { 
					// 通过上面得到的index下标,替换这个需要被淘汰的页面
					blockArr[index] = arr[i];
					// 请求调入页面次数加1
					requestReplace++;
					// 指针后移
					index++;
					
					blockOutput(blockArr);
				}
			}
			if (index == blockNum) { // 如果到了物理块尾部,就回到物理块头部
				index = 0;
			}
			pageExist = 0; // 归零初始化
		}
		pageMissingRate(requestReplace, arr); // 计算缺页率
	}

	/**
	 * 最近最久未使用算法:总是淘汰最近最久未使用的页面
	 * 相关参数:
	 *   arr:存放页面号的待处理原数组
	 *   blockArr: 物理块中存放页面号的数组
	 *   blockNum: 记录物理块大小
	 *   position: 记录算法中循环的起始位置
	 *   time: 物理块中各页面距上一次被调用的时长
	 * */
	public static void LRU(int arr[], int blockArr[], int blockNum, int position, int time[]) {
		int index = 0;     // 用于记录被淘汰页面的下标
		int pageExist = 0; // 用于判断页面是否存在于物理块数组中
		int best = 0;      // 用于记录changeArr方法的返回值
		
		// 请求调入页面次数,用于判断缺页率
		int requestReplace = blockNum;
		
		for (int i = position; i < arr.length; i++) {
			// 拿到新页面,首先判断,它是否是物理块中已经存在的页面
			for (int j = 0; j < blockNum; j++) {
				// 如果当前页面存在于物理块中,就去判断下一个页面
				if (arr[i] == blockArr[j]) {
					// 这个位置的页面被调用过,因此重新置0,同时记录下标index,让除了这个下标的其他位置等待时长加1
					index = j;
					time[index] = 0;
					
					System.out.println("物理块无变化");
					break;
				}
				pageExist++;
				// 当pageExist的大小变成了物理块大小,意味着当前页面不在物理块中,需要替换掉不满足最近最久未使用的页面
				if (pageExist == blockNum) {
					// 拿到物理块数组中,最近最久未被使用的页面的下标(即等待时间最长的)
					best = changeArr(time);
					// 将这个页面淘汰
					blockArr[best] = arr[i];
					// 记录这个淘汰页面的下标,当前新页面重新置0,其他页面等待时长加1
					index = best;
					time[index] = 0;
					// 请求调入页面次数加1
					requestReplace++;
					
					blockOutput(blockArr);
				}
			}
			for (int m = 0; m < blockNum; m++) {
				if (m == index) { // 当前操作页面不加一
					continue;
				}
				// 其他未操作页面,等待时长自加1
				time[m]++;
			}
			index = 0;     // 归零初始化
			pageExist = 0; // 归零初始化
		}
		pageMissingRate(requestReplace, arr); // 计算缺页率
	}

	/**
	 * 功能:返回最近最久未使用算法中time数组最近最久未使用页面的下标
	 * */
	public static int changeArr(int time[]) {
		int index = 0; // 记录返回页面的下标
		int best = -1; // 记录最大值变化情况
		for (int i = 0; i < time.length; i++) {
			if (time[i] > best) {
				best = time[i];
				index = i;
			}
		}
		return index;
	}

	/**
	 * 最少使用算法:总是淘汰在最近时期使用最少的页面作为淘汰页
	 * 相关参数:
	 *   arr:存放页面号的待处理原数组
	 *   blockArr: 物理块中存放页面号的数组
	 *   blockNum: 记录物理块大小
	 *   position: 记录算法中循环的起始位置
	 *   arrNoRepeat: 存放每个页面的页面号
	 *   arrIndex: 记录time数组的大小
	 *   time: 记录每个页面的使用次数
	 * */
	public static void LFU(int arr[], int blockArr[], int blockNum, int position, int arrNoRepeat[], int arrIndex, int time[]) {
		int pageExist = 0;   // 用于判断页面是否存在于物理块数组中
		int visitLess = 100; // 记录访问次数最小值
		int index = 0;       // 记录被淘汰页面的下标
		
		// 请求调入页面次数,用于判断缺页率
		int requestReplace = blockNum;
		
		for (int i = position; i < arr.length; i++) {
			for (int j = 0; j < blockNum; j++) {
				// 如果当前页面存在于物理块中,就去判断下一个页面
				if (arr[i] == blockArr[j]) {
					
					// 判断当前页面在arrNoRepeat中的位置,让其访问次数+1
					for(int d = 0; d < arrIndex; d++){
						if(arr[i] == arrNoRepeat[d]){ //找到位置
							time[d]++;
							break;
						}
					}
					
					System.out.println("物理块无变化");
					break;
				}
				pageExist++;
				// 当pageExist的大小变成了物理块大小,意味着当前页面不在物理块中,需要替换掉不满足最少使用的页面
				if (pageExist == blockNum) { 
					
					// 判断现在存在于物理块中的页面,哪个访问次数最少
					for(int k = 0; k < blockNum; k++){
						for(int m = 0 ; m < arrIndex; m++){
							if(blockArr[k] == arrNoRepeat[m]){
								// 找到
								if(time[m] < visitLess){
									index = k;
									visitLess = time[m];
									break;
								}
							}
						}
					}
					visitLess = 100; // 初始化
					requestReplace++;
					// 将这个页面淘汰
					blockArr[index] = arr[i];
					
					// 判断当前页面在arrNoRepeat中的位置,让其访问次数+1
					for(int d = 0; d < arrIndex; d++){
						if(arr[i] == arrNoRepeat[d]){ //找到位置
							time[d]++;
							break;
						}
					}
					
					blockOutput(blockArr);
				}
			}
			pageExist = 0; // 归零初始化
		}
		pageMissingRate(requestReplace, arr); // 计算缺页率
	}
	/**
	 * 功能:输出物理块数组情况
	 * */
	public static void blockOutput(int blockArr[]) {
		System.out.print("当前物理块中的页面号:");
		for (int i = 0; i < blockArr.length; i++) {
			System.out.print(blockArr[i] + " ");
		}
		System.out.println("");
	}

	/**
	 * 功能:缺页率的计算,缺页率 = 请求调入的次数 / 页面总数
	 * */
	public static void pageMissingRate(int num, int arr[]) {
		System.out.print("该算法总共缺页" + num + "次,缺页率为" + (num / (double) arr.length));
		System.out.println("");
	}
}

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

只爭朝夕不負韶華

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

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

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

打赏作者

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

抵扣说明:

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

余额充值