首次适应算法:
首次适应算法从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给作业,这种方法目的在于减少查找时间。为适应这种算法,空闲分区表(空闲区链)中的空闲分区要按地址由低到高进行排序。该算法优先使用低址部分空闲区,在低址空间造成许多小的空闲区,在高地址空间保留大的空闲区。
代码实现
import java.util.*;
public class FF {
private static class Node {
int id; // 作业id,为-1代表空闲分区;大于0代表已分配
int start; // 初始地址
int size; // 大小
public String toString() {
return String.format("[%4d, %4d, %4d]", id, start, size);
}
}
private static final int SIZE = 4; // 定义碎片大小
private static Scanner sc = new Scanner(System.in);
// 返回分区链表
private static List<Node> init() {
List<Node> list = new ArrayList<>();
Node node = new Node();
// 初始化,为整个内存空间分配一个空闲节点
node.id = -1;
node.start = 0;
System.out.print("请输入内存空间大小: ");
node.size = sc.nextInt();
list.add(node);
return list;
}
// 为作业id在分区链表list中分配大小为size的内存
private static boolean add(List<Node> list, int id, int size) {
Node p = null;
int i;
// 找到第一个未分配且大于size的内存空间节点p,i为其下标
for (i = 0; i < list.size(); i++) {
p = list.get(i);
if (p.id == -1 && p.size >= size)
break;
}
if (i == list.size()) return false; // 不存在未分配且大于或等于size的内存空间节点,分配失败
// 当原来节点的大小大于size+SIZE时需要创建一个新节点temp保留余下的分区,并插在p的后面
if (p.size - size > SIZE) {
Node temp = new Node();
temp.id = -1;
temp.start = p.start + size;
temp.size = p.size - size;
list.add(i + 1, temp);
}
// 将原来节点变成已分配的节点,当剩余空间大于SIZE时,该节点大小为size;当剩余空间小于或等于SIZE时,该节点大小不变,因为剩余大小已经不够再次分配任务;
p.id = id;
p.size = (p.size - size > SIZE ? size : p.size);
return true;
}
// 回收作业id的内存,并合并相邻的空闲分区
private static boolean del(List<Node> list, int id) {
Node p = null;
int i;
// 找到作业id所在的节点p,i为其下标
for (i = 0; i < list.size(); i++) {
p = list.get(i);
if (p.id == id) break;
}
if (i == list.size()) return false;//此作业id不存在
p.id = -1; // 回收分区
Node a, b;
if (i != 0) { // 若第i-1个节点和第i个节点相邻,合并两个分区
a = list.get(i - 1);
b = list.get(i);
if (a.id == -1 && b.id == -1 && a.start + a.size == b.start) {
a.size += b.size;
list.remove(i);
i--;
}
// i--是因为可能存在合并后的节点可能与后一个节点相邻
}
if (i != list.size() - 1) { // 若第i个节点和第i+1个节点相邻,合并两个分区
a = list.get(i);
b = list.get(i + 1);
if (a.id == -1 && b.id == -1 && a.start + a.size == b.start) {
a.size += b.size;
list.remove(i + 1);
}
}
return true;
}
private static void show(List<Node> list) {
System.out.println("已分配分区:");
int i = 1;
for (Node temp : list) {
if (temp.id != -1) System.out.println("分区号:" + i + " 分配情况:" + temp);
i++;
}
i = 1;
System.out.println("未分配分区:");
for (Node temp : list) {
if (temp.id == -1) System.out.println("分区号:" + i + " 分配情况:" + temp);
i++;
}
// System.out.println(list);
}
public static void main(String[] args) {
List<Node> list = init();
int id, size, op;
while (true) {
System.out.println("\n************************************************");
System.out.println(" 1: 为新作业分配内存 2: 撤销作业释放内存");
System.out.println(" 3: 查看FF算法内存分配 4: 退出");
System.out.print("请输入操作: ");
op = sc.nextInt();
switch (op) {
case 1:
System.out.print("请输入作业id和作业大小size: ");
id = sc.nextInt();
size = sc.nextInt();
if (add(list, id, size)) System.out.println("分配成功");
else System.out.println("分配失败");
break;
case 2:
System.out.print("请输入需要撤销的作业id: ");
id = sc.nextInt();
if (del(list, id)) System.out.println("撤销成功");
else System.out.println("撤销失败,此作业id不存在");
break;
case 3:
show(list);
break;
case 4:
return;
}
}
}
}
最佳适应和最差适应算法:
最佳适应算法(Best Fit):
它从全部空闲区中找出能满足作业要求的、且大小最小的空闲分区,这种方法能使碎片尽量小。为适应此算法,空闲分区表(空闲区链)中的空闲分区要按从小到大进行排序,自表头开始查找到第一个满足要求的自由分区分配。该算法保留大的空闲区,但造成许多小的空闲区。
最差适应算法(Worst Fit)
也称最差适配算法:
它从全部空闲区中找出能满足作业要求的、且大小最大的空闲分区,从而使链表中的结点大小趋于均匀,适用于请求分配的内存大小范围较窄的系统。为适应此算法,空闲分区表(空闲区链)中的空闲分区要按大小从大到小进行排序,自表头开始查找到第一个满足要求的自由分区分配。该算法保留小的空闲区,尽量减少小的碎片产生。
代码实现(其中将Integer.compare(this.size, node.size)中的两个参数互换位置即为WF(最差适应)算法)
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class BF {
private static class Node implements Comparable {
int id; // 作业id,为-1代表空闲分区;大于0代表已分配
int start; // 初始地址
int size; // 大小
public String toString() {
return String.format("[分区:%d, 起始地址:%d, 分区大小%d]", id, start, size);
}
@Override
public int compareTo(Object o) {
Node node = (Node) o;
return Integer.compare(this.size, node.size);//升序,此处将compare中的参数颠倒顺序传入即可实现最差适应算法
}
}
private static final int SIZE = 4;
private static Scanner sc = new Scanner(System.in);
//返回分区表
public static List<Node> init() {
List<Node> list = new ArrayList<>();
System.out.println("请输入分区总大小:");
Node node = new Node();
node.size = sc.nextInt();
node.start = 0;
node.id = -1;
list.add(node);
return list;
}
//为作业分配分区
public static boolean add(List<Node> list, int id, int size) {
Node p = null;
list.sort(Node::compareTo);
//找到空闲分区最小且大于碎片大小的分区
int i;
for (i = 0; i < list.size(); i++) {
p = list.get(i);
if (p.size >= size && p.id == -1)
break;
}
if (i == list.size())
return false;
// 当原来节点的大小大于size+SIZE时需要创建一个新节点temp保留余下的分区,并插在p的后面
if (p.size - size > SIZE) {
Node tNode = new Node();
tNode.start = p.start + size;
tNode.id = -1;
tNode.size = p.size - size;
list.add(i + 1, tNode);
}
//修改p中的值
p.id = id;
p.size = (p.size - size > SIZE ? size : p.size);
return true;
}
//撤销作业释放分区
public static boolean delete(List<Node> list, int id) {
Node p = null;
Node t = null;
int i, j;
for (i = 0; i < list.size(); i++) {
p = list.get(i);
if (p.id == id)
break;
}
if (i == list.size())
return false;//此作业id不存在
p.id = -1;//回收作业
//合并分区
int count = 0;
for (j = 0; j < list.size(); j++) {
t = list.get(j);
//合并p前面的分区
if (t.start + t.size == p.start && t.id == -1) {
p.start = t.start;
p.size += t.size;
list.remove(j);
count++;
if (count == 2)
break;
}
//合并p后面的分区
if (p.start + p.size == t.start && t.id == -1) {
p.size += t.size;
list.remove(j);
count++;
if (count == 2)
break;
}
}
return true;//撤销成功
}
private static void show(List<Node> list) {
System.out.println("已分配分区:");
for (Node t : list) {
if (t.id != -1) {
System.out.println("分配情况" + t);
}
}
System.out.println("未分配分区:");
for (Node t : list) {
if (t.id == -1) {
System.out.println("分配情况" + t);
}
}
}
// public static List<Node>
public static void main(String[] args) {
List<Node> list = init();
int id, size, op;
while (true) {
System.out.println("\n************************************************");
System.out.println(" 1: 为新作业分配分区 2: 撤销作业释放内存");
System.out.println(" 3: 查看内存分区情况 4: 退出");
System.out.print("请输入操作: ");
op = sc.nextInt();
switch (op) {
case 1:
System.out.print("请输入作业id和作业大小size: ");
id = sc.nextInt();
size = sc.nextInt();
if (add(list, id, size)) System.out.println("分配成功");
else System.out.println("分配失败");
break;
case 2:
System.out.print("请输入撤销的作业id: ");
id = sc.nextInt();
if (delete(list, id)) System.out.println("撤销成功");
else System.out.println("撤销失败,此作业id不存在");
break;
case 3:
show(list);
break;
case 4:
return;
}
}
}
}