Skip to content

Commit 910d5b8

Browse files
authored
refactor: Refactor SJFScheduling and Tests (TheAlgorithms#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
1 parent dba2d86 commit 910d5b8

File tree

2 files changed

+71
-155
lines changed

2 files changed

+71
-155
lines changed

src/main/java/com/thealgorithms/scheduling/SJFScheduling.java

Lines changed: 43 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,62 @@
22

33
import com.thealgorithms.devutils.entities.ProcessDetails;
44
import java.util.ArrayList;
5+
import java.util.Collection;
6+
import java.util.Comparator;
7+
import java.util.Iterator;
58
import java.util.List;
69

710
/**
8-
* Implementation of Shortest Job First Algorithm: The algorithm allows the waiting process with the
9-
* minimal burst time to be executed first. see more here:
10-
* https://www.guru99.com/shortest-job-first-sjf-scheduling.html
11+
* Shortest Job First (SJF) Scheduling Algorithm:
12+
* Executes processes with the shortest burst time first among the ones that have arrived.
1113
*/
12-
1314
public class SJFScheduling {
14-
protected ArrayList<ProcessDetails> processes;
15-
protected ArrayList<String> schedule;
16-
17-
private static void sortProcessesByArrivalTime(List<ProcessDetails> processes) {
18-
for (int i = 0; i < processes.size(); i++) {
19-
for (int j = i + 1; j < processes.size() - 1; j++) {
20-
if (processes.get(j).getArrivalTime() > processes.get(j + 1).getArrivalTime()) {
21-
final var temp = processes.get(j);
22-
processes.set(j, processes.get(j + 1));
23-
processes.set(j + 1, temp);
24-
}
25-
}
26-
}
27-
}
15+
private final List<ProcessDetails> processes;
16+
private final List<String> schedule;
2817

29-
/**
30-
* a simple constructor
31-
* @param processes a list of processes the user wants to schedule
32-
* it also sorts the processes based on the time of their arrival
33-
*/
34-
SJFScheduling(final ArrayList<ProcessDetails> processes) {
35-
this.processes = processes;
36-
schedule = new ArrayList<>();
18+
public SJFScheduling(final List<ProcessDetails> processes) {
19+
this.processes = new ArrayList<>(processes);
20+
this.schedule = new ArrayList<>();
3721
sortProcessesByArrivalTime(this.processes);
3822
}
39-
protected void sortByArrivalTime() {
40-
sortProcessesByArrivalTime(processes);
23+
24+
private static void sortProcessesByArrivalTime(List<ProcessDetails> processes) {
25+
processes.sort(Comparator.comparingInt(ProcessDetails::getArrivalTime));
4126
}
4227

4328
/**
44-
* this functions returns the order of the executions
29+
* Executes the SJF scheduling algorithm and builds the execution order.
4530
*/
46-
4731
public void scheduleProcesses() {
48-
ArrayList<ProcessDetails> ready = new ArrayList<>();
49-
32+
List<ProcessDetails> ready = new ArrayList<>();
5033
int size = processes.size();
51-
int runtime;
5234
int time = 0;
5335
int executed = 0;
54-
int j;
55-
int k = 0;
56-
ProcessDetails running;
5736

58-
if (size == 0) {
59-
return;
37+
Iterator<ProcessDetails> processIterator = processes.iterator();
38+
39+
// This will track the next process to be checked for arrival time
40+
ProcessDetails nextProcess = null;
41+
if (processIterator.hasNext()) {
42+
nextProcess = processIterator.next();
6043
}
6144

6245
while (executed < size) {
63-
while (k < size && processes.get(k).getArrivalTime() <= time) // here we find the processes that have arrived.
64-
{
65-
ready.add(processes.get(k));
66-
k++;
46+
// Load all processes that have arrived by current time
47+
while (nextProcess != null && nextProcess.getArrivalTime() <= time) {
48+
ready.add(nextProcess);
49+
if (processIterator.hasNext()) {
50+
nextProcess = processIterator.next();
51+
} else {
52+
nextProcess = null;
53+
}
6754
}
6855

69-
running = findShortestJob(ready);
56+
ProcessDetails running = findShortestJob(ready);
7057
if (running == null) {
7158
time++;
7259
} else {
73-
runtime = running.getBurstTime();
74-
for (j = 0; j < runtime; j++) {
75-
time++;
76-
}
60+
time += running.getBurstTime();
7761
schedule.add(running.getProcessId());
7862
ready.remove(running);
7963
executed++;
@@ -82,30 +66,23 @@ public void scheduleProcesses() {
8266
}
8367

8468
/**
85-
* this function evaluates the shortest job of all the ready processes (based on a process
86-
* burst time)
69+
* Finds the process with the shortest job of all the ready processes (based on a process
8770
* @param readyProcesses an array list of ready processes
8871
* @return returns the process' with the shortest burst time OR NULL if there are no ready
8972
* processes
9073
*/
91-
private ProcessDetails findShortestJob(List<ProcessDetails> readyProcesses) {
92-
if (readyProcesses.isEmpty()) {
93-
return null;
94-
}
95-
int i;
96-
int size = readyProcesses.size();
97-
int minBurstTime = readyProcesses.get(0).getBurstTime();
98-
int temp;
99-
int positionOfShortestJob = 0;
74+
private ProcessDetails findShortestJob(Collection<ProcessDetails> readyProcesses) {
75+
return readyProcesses.stream().min(Comparator.comparingInt(ProcessDetails::getBurstTime)).orElse(null);
76+
}
10077

101-
for (i = 1; i < size; i++) {
102-
temp = readyProcesses.get(i).getBurstTime();
103-
if (minBurstTime > temp) {
104-
minBurstTime = temp;
105-
positionOfShortestJob = i;
106-
}
107-
}
78+
/**
79+
* Returns the computed schedule after calling scheduleProcesses().
80+
*/
81+
public List<String> getSchedule() {
82+
return schedule;
83+
}
10884

109-
return readyProcesses.get(positionOfShortestJob);
85+
public List<ProcessDetails> getProcesses() {
86+
return List.copyOf(processes);
11087
}
11188
}

src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java

Lines changed: 28 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,107 +4,46 @@
44
import static org.junit.jupiter.api.Assertions.assertTrue;
55

66
import com.thealgorithms.devutils.entities.ProcessDetails;
7-
import java.util.ArrayList;
7+
import java.util.Collections;
8+
import java.util.List;
9+
import java.util.stream.Stream;
10+
import org.junit.jupiter.api.DisplayName;
811
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.Arguments;
14+
import org.junit.jupiter.params.provider.MethodSource;
915

1016
class SJFSchedulingTest {
11-
private ArrayList<ProcessDetails> process;
12-
void initialisation0() {
1317

14-
process = new ArrayList<>();
15-
process.add(new ProcessDetails("1", 0, 6));
16-
process.add(new ProcessDetails("2", 1, 2));
18+
private static Stream<Arguments> schedulingTestData() {
19+
return Stream.of(Arguments.of(List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2)), List.of("1", "2")),
20+
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")),
21+
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")),
22+
Arguments.of(Collections.emptyList(), List.of()));
1723
}
18-
void initialisation1() {
1924

20-
process = new ArrayList<>();
21-
process.add(new ProcessDetails("1", 0, 6));
22-
process.add(new ProcessDetails("2", 1, 2));
23-
process.add(new ProcessDetails("3", 4, 3));
24-
process.add(new ProcessDetails("4", 3, 1));
25-
process.add(new ProcessDetails("5", 6, 4));
26-
process.add(new ProcessDetails("6", 5, 5));
27-
}
28-
29-
void initialisation2() {
30-
31-
process = new ArrayList<>();
32-
process.add(new ProcessDetails("1", 0, 3));
33-
process.add(new ProcessDetails("2", 1, 2));
34-
process.add(new ProcessDetails("3", 2, 1));
35-
}
36-
void initialisation3() {
37-
process = new ArrayList<>();
38-
process.add(new ProcessDetails("1", 0, 3));
39-
process.add(new ProcessDetails("2", 5, 2));
40-
process.add(new ProcessDetails("3", 9, 1));
41-
}
42-
@Test
43-
void constructor() {
44-
initialisation0();
45-
SJFScheduling a = new SJFScheduling(process);
46-
assertEquals(6, a.processes.get(0).getBurstTime());
47-
assertEquals(2, a.processes.get(1).getBurstTime());
25+
@ParameterizedTest(name = "Test SJF schedule: {index}")
26+
@MethodSource("schedulingTestData")
27+
void testSJFScheduling(List<ProcessDetails> inputProcesses, List<String> expectedSchedule) {
28+
SJFScheduling scheduler = new SJFScheduling(inputProcesses);
29+
scheduler.scheduleProcesses();
30+
assertEquals(expectedSchedule, scheduler.getSchedule());
4831
}
4932

5033
@Test
51-
void sort() {
52-
initialisation1();
53-
SJFScheduling a = new SJFScheduling(process);
54-
a.sortByArrivalTime();
55-
assertEquals("1", a.processes.get(0).getProcessId());
56-
assertEquals("2", a.processes.get(1).getProcessId());
57-
assertEquals("3", a.processes.get(3).getProcessId());
58-
assertEquals("4", a.processes.get(2).getProcessId());
59-
assertEquals("5", a.processes.get(5).getProcessId());
60-
assertEquals("6", a.processes.get(4).getProcessId());
61-
}
34+
@DisplayName("Test sorting by arrival order")
35+
void testProcessArrivalOrderIsSorted() {
36+
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));
37+
SJFScheduling scheduler = new SJFScheduling(processes);
38+
List<String> actualOrder = scheduler.getProcesses().stream().map(ProcessDetails::getProcessId).toList();
6239

63-
@Test
64-
void scheduling() {
65-
initialisation1();
66-
SJFScheduling a = new SJFScheduling(process);
67-
a.scheduleProcesses();
68-
assertEquals("1", a.schedule.get(0));
69-
assertEquals("4", a.schedule.get(1));
70-
assertEquals("2", a.schedule.get(2));
71-
assertEquals("3", a.schedule.get(3));
72-
assertEquals("5", a.schedule.get(4));
73-
assertEquals("6", a.schedule.get(5));
40+
assertEquals(List.of("1", "2", "4", "3", "6", "5"), actualOrder);
7441
}
7542

7643
@Test
77-
void schedulingOfTwoProcesses() {
78-
initialisation0();
79-
SJFScheduling a = new SJFScheduling(process);
80-
a.scheduleProcesses();
81-
assertEquals("1", a.schedule.get(0));
82-
assertEquals("2", a.schedule.get(1));
83-
}
84-
85-
@Test
86-
void schedulingOfAShortestJobArrivingLast() {
87-
initialisation2();
88-
SJFScheduling a = new SJFScheduling(process);
89-
a.scheduleProcesses();
90-
assertEquals("1", a.schedule.get(0));
91-
assertEquals("3", a.schedule.get(1));
92-
assertEquals("2", a.schedule.get(2));
93-
}
94-
@Test
95-
void schedulingWithProcessesNotComingBackToBack() {
96-
initialisation3();
97-
SJFScheduling a = new SJFScheduling(process);
98-
a.scheduleProcesses();
99-
assertEquals("1", a.schedule.get(0));
100-
assertEquals("2", a.schedule.get(1));
101-
assertEquals("3", a.schedule.get(2));
102-
}
103-
@Test
104-
void schedulingOfNothing() {
105-
process = new ArrayList<>();
106-
SJFScheduling a = new SJFScheduling(process);
107-
a.scheduleProcesses();
108-
assertTrue(a.schedule.isEmpty());
44+
void testSchedulingEmptyList() {
45+
SJFScheduling scheduler = new SJFScheduling(Collections.emptyList());
46+
scheduler.scheduleProcesses();
47+
assertTrue(scheduler.getSchedule().isEmpty());
10948
}
11049
}

0 commit comments

Comments
 (0)