Skip to content

Commit b17567a

Browse files
Merge branch 'master' into refactor/TwoPointers
2 parents 75a7741 + 182118b commit b17567a

File tree

3 files changed

+104
-172
lines changed

3 files changed

+104
-172
lines changed
Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,52 @@
11
package com.thealgorithms.recursion;
22

3-
// program to find power set of a string
4-
53
import java.util.ArrayList;
64
import java.util.List;
75

6+
/**
7+
* Utility class to generate all subsets (power set) of a given string using recursion.
8+
*
9+
* <p>For example, the string "ab" will produce: ["ab", "a", "b", ""]
10+
*/
811
public final class GenerateSubsets {
912

1013
private GenerateSubsets() {
11-
throw new UnsupportedOperationException("Utility class");
1214
}
1315

16+
/**
17+
* Generates all subsets (power set) of the given string using recursion.
18+
*
19+
* @param str the input string to generate subsets for
20+
* @return a list of all subsets of the input string
21+
*/
1422
public static List<String> subsetRecursion(String str) {
15-
return doRecursion("", str);
23+
return generateSubsets("", str);
1624
}
1725

18-
private static List<String> doRecursion(String p, String up) {
19-
if (up.isEmpty()) {
20-
List<String> list = new ArrayList<>();
21-
list.add(p);
22-
return list;
26+
/**
27+
* Recursive helper method to generate subsets by including or excluding characters.
28+
*
29+
* @param current the current prefix being built
30+
* @param remaining the remaining string to process
31+
* @return list of subsets formed from current and remaining
32+
*/
33+
private static List<String> generateSubsets(String current, String remaining) {
34+
if (remaining.isEmpty()) {
35+
List<String> result = new ArrayList<>();
36+
result.add(current);
37+
return result;
2338
}
2439

25-
// Taking the character
26-
char ch = up.charAt(0);
27-
// Adding the character in the recursion
28-
List<String> left = doRecursion(p + ch, up.substring(1));
29-
// Not adding the character in the recursion
30-
List<String> right = doRecursion(p, up.substring(1));
40+
char ch = remaining.charAt(0);
41+
String next = remaining.substring(1);
42+
43+
// Include the character
44+
List<String> withChar = generateSubsets(current + ch, next);
3145

32-
left.addAll(right);
46+
// Exclude the character
47+
List<String> withoutChar = generateSubsets(current, next);
3348

34-
return left;
49+
withChar.addAll(withoutChar);
50+
return withChar;
3551
}
3652
}

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)