mirror of
https://github.com/TheAlgorithms/Java.git
synced 2026-03-13 08:40:43 +08:00
refactor: Refactor SJFScheduling and Tests (#6372)
* refactor: Refactor SJFScheduling and Tests * refactor: fix checkstyle * refactor: add full imports * refactor: add full imports * refactor: remove redundant newline * refactor: fix indexed list iteration
This commit is contained in:
committed by
GitHub
parent
dba2d869f2
commit
910d5b880a
@@ -2,78 +2,62 @@ package com.thealgorithms.scheduling;
|
||||
|
||||
import com.thealgorithms.devutils.entities.ProcessDetails;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of Shortest Job First Algorithm: The algorithm allows the waiting process with the
|
||||
* minimal burst time to be executed first. see more here:
|
||||
* https://www.guru99.com/shortest-job-first-sjf-scheduling.html
|
||||
* Shortest Job First (SJF) Scheduling Algorithm:
|
||||
* Executes processes with the shortest burst time first among the ones that have arrived.
|
||||
*/
|
||||
|
||||
public class SJFScheduling {
|
||||
protected ArrayList<ProcessDetails> processes;
|
||||
protected ArrayList<String> schedule;
|
||||
private final List<ProcessDetails> processes;
|
||||
private final List<String> schedule;
|
||||
|
||||
private static void sortProcessesByArrivalTime(List<ProcessDetails> processes) {
|
||||
for (int i = 0; i < processes.size(); i++) {
|
||||
for (int j = i + 1; j < processes.size() - 1; j++) {
|
||||
if (processes.get(j).getArrivalTime() > processes.get(j + 1).getArrivalTime()) {
|
||||
final var temp = processes.get(j);
|
||||
processes.set(j, processes.get(j + 1));
|
||||
processes.set(j + 1, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a simple constructor
|
||||
* @param processes a list of processes the user wants to schedule
|
||||
* it also sorts the processes based on the time of their arrival
|
||||
*/
|
||||
SJFScheduling(final ArrayList<ProcessDetails> processes) {
|
||||
this.processes = processes;
|
||||
schedule = new ArrayList<>();
|
||||
public SJFScheduling(final List<ProcessDetails> processes) {
|
||||
this.processes = new ArrayList<>(processes);
|
||||
this.schedule = new ArrayList<>();
|
||||
sortProcessesByArrivalTime(this.processes);
|
||||
}
|
||||
protected void sortByArrivalTime() {
|
||||
sortProcessesByArrivalTime(processes);
|
||||
|
||||
private static void sortProcessesByArrivalTime(List<ProcessDetails> processes) {
|
||||
processes.sort(Comparator.comparingInt(ProcessDetails::getArrivalTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* this functions returns the order of the executions
|
||||
* Executes the SJF scheduling algorithm and builds the execution order.
|
||||
*/
|
||||
|
||||
public void scheduleProcesses() {
|
||||
ArrayList<ProcessDetails> ready = new ArrayList<>();
|
||||
|
||||
List<ProcessDetails> ready = new ArrayList<>();
|
||||
int size = processes.size();
|
||||
int runtime;
|
||||
int time = 0;
|
||||
int executed = 0;
|
||||
int j;
|
||||
int k = 0;
|
||||
ProcessDetails running;
|
||||
|
||||
if (size == 0) {
|
||||
return;
|
||||
Iterator<ProcessDetails> processIterator = processes.iterator();
|
||||
|
||||
// This will track the next process to be checked for arrival time
|
||||
ProcessDetails nextProcess = null;
|
||||
if (processIterator.hasNext()) {
|
||||
nextProcess = processIterator.next();
|
||||
}
|
||||
|
||||
while (executed < size) {
|
||||
while (k < size && processes.get(k).getArrivalTime() <= time) // here we find the processes that have arrived.
|
||||
{
|
||||
ready.add(processes.get(k));
|
||||
k++;
|
||||
// Load all processes that have arrived by current time
|
||||
while (nextProcess != null && nextProcess.getArrivalTime() <= time) {
|
||||
ready.add(nextProcess);
|
||||
if (processIterator.hasNext()) {
|
||||
nextProcess = processIterator.next();
|
||||
} else {
|
||||
nextProcess = null;
|
||||
}
|
||||
}
|
||||
|
||||
running = findShortestJob(ready);
|
||||
ProcessDetails running = findShortestJob(ready);
|
||||
if (running == null) {
|
||||
time++;
|
||||
} else {
|
||||
runtime = running.getBurstTime();
|
||||
for (j = 0; j < runtime; j++) {
|
||||
time++;
|
||||
}
|
||||
time += running.getBurstTime();
|
||||
schedule.add(running.getProcessId());
|
||||
ready.remove(running);
|
||||
executed++;
|
||||
@@ -82,30 +66,23 @@ public class SJFScheduling {
|
||||
}
|
||||
|
||||
/**
|
||||
* this function evaluates the shortest job of all the ready processes (based on a process
|
||||
* burst time)
|
||||
* Finds the process with the shortest job of all the ready processes (based on a process
|
||||
* @param readyProcesses an array list of ready processes
|
||||
* @return returns the process' with the shortest burst time OR NULL if there are no ready
|
||||
* processes
|
||||
*/
|
||||
private ProcessDetails findShortestJob(List<ProcessDetails> readyProcesses) {
|
||||
if (readyProcesses.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
int i;
|
||||
int size = readyProcesses.size();
|
||||
int minBurstTime = readyProcesses.get(0).getBurstTime();
|
||||
int temp;
|
||||
int positionOfShortestJob = 0;
|
||||
private ProcessDetails findShortestJob(Collection<ProcessDetails> readyProcesses) {
|
||||
return readyProcesses.stream().min(Comparator.comparingInt(ProcessDetails::getBurstTime)).orElse(null);
|
||||
}
|
||||
|
||||
for (i = 1; i < size; i++) {
|
||||
temp = readyProcesses.get(i).getBurstTime();
|
||||
if (minBurstTime > temp) {
|
||||
minBurstTime = temp;
|
||||
positionOfShortestJob = i;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the computed schedule after calling scheduleProcesses().
|
||||
*/
|
||||
public List<String> getSchedule() {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
return readyProcesses.get(positionOfShortestJob);
|
||||
public List<ProcessDetails> getProcesses() {
|
||||
return List.copyOf(processes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,107 +4,46 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.thealgorithms.devutils.entities.ProcessDetails;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
class SJFSchedulingTest {
|
||||
private ArrayList<ProcessDetails> process;
|
||||
void initialisation0() {
|
||||
|
||||
process = new ArrayList<>();
|
||||
process.add(new ProcessDetails("1", 0, 6));
|
||||
process.add(new ProcessDetails("2", 1, 2));
|
||||
}
|
||||
void initialisation1() {
|
||||
|
||||
process = new ArrayList<>();
|
||||
process.add(new ProcessDetails("1", 0, 6));
|
||||
process.add(new ProcessDetails("2", 1, 2));
|
||||
process.add(new ProcessDetails("3", 4, 3));
|
||||
process.add(new ProcessDetails("4", 3, 1));
|
||||
process.add(new ProcessDetails("5", 6, 4));
|
||||
process.add(new ProcessDetails("6", 5, 5));
|
||||
private static Stream<Arguments> schedulingTestData() {
|
||||
return Stream.of(Arguments.of(List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2)), List.of("1", "2")),
|
||||
Arguments.of(List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2), new ProcessDetails("3", 4, 3), new ProcessDetails("4", 3, 1), new ProcessDetails("5", 6, 4), new ProcessDetails("6", 5, 5)), List.of("1", "4", "2", "3", "5", "6")),
|
||||
Arguments.of(List.of(new ProcessDetails("1", 0, 3), new ProcessDetails("2", 1, 2), new ProcessDetails("3", 2, 1)), List.of("1", "3", "2")), Arguments.of(List.of(new ProcessDetails("1", 0, 3), new ProcessDetails("2", 5, 2), new ProcessDetails("3", 9, 1)), List.of("1", "2", "3")),
|
||||
Arguments.of(Collections.emptyList(), List.of()));
|
||||
}
|
||||
|
||||
void initialisation2() {
|
||||
|
||||
process = new ArrayList<>();
|
||||
process.add(new ProcessDetails("1", 0, 3));
|
||||
process.add(new ProcessDetails("2", 1, 2));
|
||||
process.add(new ProcessDetails("3", 2, 1));
|
||||
}
|
||||
void initialisation3() {
|
||||
process = new ArrayList<>();
|
||||
process.add(new ProcessDetails("1", 0, 3));
|
||||
process.add(new ProcessDetails("2", 5, 2));
|
||||
process.add(new ProcessDetails("3", 9, 1));
|
||||
}
|
||||
@Test
|
||||
void constructor() {
|
||||
initialisation0();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
assertEquals(6, a.processes.get(0).getBurstTime());
|
||||
assertEquals(2, a.processes.get(1).getBurstTime());
|
||||
@ParameterizedTest(name = "Test SJF schedule: {index}")
|
||||
@MethodSource("schedulingTestData")
|
||||
void testSJFScheduling(List<ProcessDetails> inputProcesses, List<String> expectedSchedule) {
|
||||
SJFScheduling scheduler = new SJFScheduling(inputProcesses);
|
||||
scheduler.scheduleProcesses();
|
||||
assertEquals(expectedSchedule, scheduler.getSchedule());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sort() {
|
||||
initialisation1();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
a.sortByArrivalTime();
|
||||
assertEquals("1", a.processes.get(0).getProcessId());
|
||||
assertEquals("2", a.processes.get(1).getProcessId());
|
||||
assertEquals("3", a.processes.get(3).getProcessId());
|
||||
assertEquals("4", a.processes.get(2).getProcessId());
|
||||
assertEquals("5", a.processes.get(5).getProcessId());
|
||||
assertEquals("6", a.processes.get(4).getProcessId());
|
||||
@DisplayName("Test sorting by arrival order")
|
||||
void testProcessArrivalOrderIsSorted() {
|
||||
List<ProcessDetails> processes = List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2), new ProcessDetails("4", 3, 1), new ProcessDetails("3", 4, 3), new ProcessDetails("6", 5, 5), new ProcessDetails("5", 6, 4));
|
||||
SJFScheduling scheduler = new SJFScheduling(processes);
|
||||
List<String> actualOrder = scheduler.getProcesses().stream().map(ProcessDetails::getProcessId).toList();
|
||||
|
||||
assertEquals(List.of("1", "2", "4", "3", "6", "5"), actualOrder);
|
||||
}
|
||||
|
||||
@Test
|
||||
void scheduling() {
|
||||
initialisation1();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
a.scheduleProcesses();
|
||||
assertEquals("1", a.schedule.get(0));
|
||||
assertEquals("4", a.schedule.get(1));
|
||||
assertEquals("2", a.schedule.get(2));
|
||||
assertEquals("3", a.schedule.get(3));
|
||||
assertEquals("5", a.schedule.get(4));
|
||||
assertEquals("6", a.schedule.get(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void schedulingOfTwoProcesses() {
|
||||
initialisation0();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
a.scheduleProcesses();
|
||||
assertEquals("1", a.schedule.get(0));
|
||||
assertEquals("2", a.schedule.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void schedulingOfAShortestJobArrivingLast() {
|
||||
initialisation2();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
a.scheduleProcesses();
|
||||
assertEquals("1", a.schedule.get(0));
|
||||
assertEquals("3", a.schedule.get(1));
|
||||
assertEquals("2", a.schedule.get(2));
|
||||
}
|
||||
@Test
|
||||
void schedulingWithProcessesNotComingBackToBack() {
|
||||
initialisation3();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
a.scheduleProcesses();
|
||||
assertEquals("1", a.schedule.get(0));
|
||||
assertEquals("2", a.schedule.get(1));
|
||||
assertEquals("3", a.schedule.get(2));
|
||||
}
|
||||
@Test
|
||||
void schedulingOfNothing() {
|
||||
process = new ArrayList<>();
|
||||
SJFScheduling a = new SJFScheduling(process);
|
||||
a.scheduleProcesses();
|
||||
assertTrue(a.schedule.isEmpty());
|
||||
void testSchedulingEmptyList() {
|
||||
SJFScheduling scheduler = new SJFScheduling(Collections.emptyList());
|
||||
scheduler.scheduleProcesses();
|
||||
assertTrue(scheduler.getSchedule().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user