From 9252fe61c32ed09e175b9de12f86f86485be97f7 Mon Sep 17 00:00:00 2001 From: alxkm Date: Sat, 12 Jul 2025 22:02:44 +0200 Subject: [PATCH 1/6] refactor: Refactor SJFScheduling and Tests --- .../scheduling/SJFScheduling.java | 94 +++++--------- .../scheduling/SJFSchedulingTest.java | 121 +++++------------- 2 files changed, 60 insertions(+), 155 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java index cbbc65a3afc5..180ac9d1ce82 100644 --- a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java @@ -2,78 +2,49 @@ import com.thealgorithms.devutils.entities.ProcessDetails; import java.util.ArrayList; +import java.util.Comparator; 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 processes; - protected ArrayList schedule; - - private static void sortProcessesByArrivalTime(List 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); - } - } - } - } + private final List processes; + private final List schedule; - /** - * 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 processes) { - this.processes = processes; - schedule = new ArrayList<>(); + public SJFScheduling(final List processes) { + this.processes = new ArrayList<>(processes); + this.schedule = new ArrayList<>(); sortProcessesByArrivalTime(this.processes); } - protected void sortByArrivalTime() { - sortProcessesByArrivalTime(processes); + + private static void sortProcessesByArrivalTime(List 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 ready = new ArrayList<>(); - + List 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; - } while (executed < size) { - while (k < size && processes.get(k).getArrivalTime() <= time) // here we find the processes that have arrived. - { + // Load arrived processes into ready queue + while (k < size && processes.get(k).getArrivalTime() <= time) { ready.add(processes.get(k)); k++; } - 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 +53,25 @@ public void scheduleProcesses() { } /** - * 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 readyProcesses) { - if (readyProcesses.isEmpty()) { - return null; - } - int i; - int size = readyProcesses.size(); - int minBurstTime = readyProcesses.get(0).getBurstTime(); - int temp; - int positionOfShortestJob = 0; + 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 getSchedule() { + return schedule; + } - return readyProcesses.get(positionOfShortestJob); + public List getProcesses() { + return List.copyOf(processes); } } diff --git a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java index aab5c64c847f..1f83ec2f30b5 100644 --- a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java @@ -1,110 +1,49 @@ package com.thealgorithms.scheduling; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import com.thealgorithms.devutils.entities.ProcessDetails; -import java.util.ArrayList; +import java.util.*; +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 process; - void initialisation0() { - process = new ArrayList<>(); - process.add(new ProcessDetails("1", 0, 6)); - process.add(new ProcessDetails("2", 1, 2)); + private static Stream 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 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)); - } - - 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 inputProcesses, List 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 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 actualOrder = scheduler.getProcesses().stream() + .map(ProcessDetails::getProcessId) + .toList(); - @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)); + assertEquals(List.of("1", "2", "4", "3", "6", "5"), actualOrder); } @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()); } } From dee1d841b2a2b00322075b6a7ca7d3dc7bb39a1b Mon Sep 17 00:00:00 2001 From: alxkm Date: Sat, 12 Jul 2025 22:08:36 +0200 Subject: [PATCH 2/6] refactor: fix checkstyle --- .../thealgorithms/scheduling/SJFScheduling.java | 4 +--- .../scheduling/SJFSchedulingTest.java | 14 ++++++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java index 180ac9d1ce82..cb85c2b5e449 100644 --- a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java @@ -59,9 +59,7 @@ public void scheduleProcesses() { * processes */ private ProcessDetails findShortestJob(List readyProcesses) { - return readyProcesses.stream() - .min(Comparator.comparingInt(ProcessDetails::getBurstTime)) - .orElse(null); + return readyProcesses.stream().min(Comparator.comparingInt(ProcessDetails::getBurstTime)).orElse(null); } /** diff --git a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java index 1f83ec2f30b5..2c701066133f 100644 --- a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java @@ -15,10 +15,9 @@ class SJFSchedulingTest { private static Stream 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())); + 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())); } @ParameterizedTest(name = "Test SJF schedule: {index}") @@ -31,11 +30,10 @@ void testSJFScheduling(List inputProcesses, List expecte @Test @DisplayName("Test sorting by arrival order") - void testProcessArrivalOrderIsSorted() {List 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)); + void testProcessArrivalOrderIsSorted() { + List 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 actualOrder = scheduler.getProcesses().stream() - .map(ProcessDetails::getProcessId) - .toList(); + List actualOrder = scheduler.getProcesses().stream().map(ProcessDetails::getProcessId).toList(); assertEquals(List.of("1", "2", "4", "3", "6", "5"), actualOrder); } From c1be7393dd372609fd4f5c853c445c38d7ca3457 Mon Sep 17 00:00:00 2001 From: alxkm Date: Sat, 12 Jul 2025 22:14:06 +0200 Subject: [PATCH 3/6] refactor: add full imports --- .../java/com/thealgorithms/scheduling/SJFSchedulingTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java index 2c701066133f..b17232e4710e 100644 --- a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java @@ -3,7 +3,9 @@ import static org.junit.jupiter.api.Assertions.*; import com.thealgorithms.devutils.entities.ProcessDetails; -import java.util.*; + +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; From c779fa0675ccd4f3bd14c781cec75246d274f89b Mon Sep 17 00:00:00 2001 From: alxkm Date: Sat, 12 Jul 2025 22:14:33 +0200 Subject: [PATCH 4/6] refactor: add full imports --- .../java/com/thealgorithms/scheduling/SJFSchedulingTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java index b17232e4710e..5e1e43414d72 100644 --- a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.scheduling; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.thealgorithms.devutils.entities.ProcessDetails; From e3afbe8aaa0021e69809a365c147745153476fc6 Mon Sep 17 00:00:00 2001 From: alxkm Date: Sat, 12 Jul 2025 22:16:17 +0200 Subject: [PATCH 5/6] refactor: remove redundant newline --- .../java/com/thealgorithms/scheduling/SJFSchedulingTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java index 5e1e43414d72..660a53299ab0 100644 --- a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.thealgorithms.devutils.entities.ProcessDetails; - import java.util.Collections; import java.util.List; import java.util.stream.Stream; From 750ecea89668c9b90253ca2801ea35dfec65c497 Mon Sep 17 00:00:00 2001 From: alxkm Date: Sat, 12 Jul 2025 22:28:05 +0200 Subject: [PATCH 6/6] refactor: fix indexed list iteration --- .../scheduling/SJFScheduling.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java index cb85c2b5e449..e3f4a8d03d07 100644 --- a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java @@ -2,7 +2,9 @@ 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; /** @@ -31,13 +33,24 @@ public void scheduleProcesses() { int size = processes.size(); int time = 0; int executed = 0; - int k = 0; + + Iterator 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) { - // Load arrived processes into ready queue - while (k < size && processes.get(k).getArrivalTime() <= time) { - 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; + } } ProcessDetails running = findShortestJob(ready); @@ -58,7 +71,7 @@ public void scheduleProcesses() { * @return returns the process' with the shortest burst time OR NULL if there are no ready * processes */ - private ProcessDetails findShortestJob(List readyProcesses) { + private ProcessDetails findShortestJob(Collection readyProcesses) { return readyProcesses.stream().min(Comparator.comparingInt(ProcessDetails::getBurstTime)).orElse(null); }