Skip to content

Add HighestResponseRatioNextScheduling.java new algorithm with tests #5607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Oct 7, 2024
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@
* [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java)
* scheduling
* [FCFSScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java)
* [HighestResponseRatioNextScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java)
* [MLFQScheduler](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/MLFQScheduler.java)
* [PreemptivePriorityScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java)
* [RRScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/RRScheduling.java)
Expand Down Expand Up @@ -916,6 +917,7 @@
* [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java)
* scheduling
* [FCFSSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java)
* [HighestResponseRatioNextSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/HighestResponseRatioNextSchedulingTest.java)
* [MLFQSchedulerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/MLFQSchedulerTest.java)
* [PreemptivePrioritySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java)
* [RRSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/RRSchedulingTest.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package com.thealgorithms.scheduling;

import java.util.Arrays;
import java.util.Comparator;

/**
* The {@code HighestResponseRatioNextScheduling} class implements the
* Highest Response Ratio Next (HRRN) scheduling algorithm.
* HRRN is a non-preemptive scheduling algorithm that selects the process with
* the highest response ratio for execution.
* The response ratio is calculated as:
*
* <pre>
* Response Ratio = (waiting time + burst time) / burst time
* </pre>
*
* HRRN is designed to reduce the average waiting time and improve overall
* system performance by balancing between short and long processes,
* minimizing process starvation.
*/
public final class HighestResponseRatioNextScheduling {

private static final int PROCESS_NOT_FOUND = -1;
private static final double INITIAL_MAX_RESPONSE_RATIO = -1.0;

private HighestResponseRatioNextScheduling() {
}

/**
* Represents a process in the scheduling algorithm.
*/
private static class Process {
String name;
int arrivalTime;
int burstTime;
int turnAroundTime;
boolean finished;

Process(String name, int arrivalTime, int burstTime) {
this.name = name;
this.arrivalTime = arrivalTime;
this.burstTime = burstTime;
this.turnAroundTime = 0;
this.finished = false;
}

/**
* Calculates the response ratio for this process.
*
* @param currentTime The current time in the scheduling process.
* @return The response ratio for this process.
*/
double calculateResponseRatio(int currentTime) {
return (double) (burstTime + currentTime - arrivalTime) / burstTime;
}
}

/**
* Calculates the Turn Around Time (TAT) for each process.
*
* <p>Turn Around Time is calculated as the total time a process spends
* in the system from arrival to completion. It is the sum of the burst time
* and the waiting time.</p>
*
* @param processNames Array of process names.
* @param arrivalTimes Array of arrival times corresponding to each process.
* @param burstTimes Array of burst times for each process.
* @param noOfProcesses The number of processes.
* @return An array of Turn Around Times for each process.
*/
public static int[] calculateTurnAroundTime(final String[] processNames, final int[] arrivalTimes, final int[] burstTimes, final int noOfProcesses) {
int currentTime = 0;
int[] turnAroundTime = new int[noOfProcesses];
Process[] processes = new Process[noOfProcesses];

for (int i = 0; i < noOfProcesses; i++) {
processes[i] = new Process(processNames[i], arrivalTimes[i], burstTimes[i]);
}

Arrays.sort(processes, Comparator.comparingInt(p -> p.arrivalTime));

int finishedProcessCount = 0;
while (finishedProcessCount < noOfProcesses) {
int nextProcessIndex = findNextProcess(processes, currentTime);
if (nextProcessIndex == PROCESS_NOT_FOUND) {
currentTime++;
continue;
}

Process currentProcess = processes[nextProcessIndex];
currentTime = Math.max(currentTime, currentProcess.arrivalTime);
currentProcess.turnAroundTime = currentTime + currentProcess.burstTime - currentProcess.arrivalTime;
currentTime += currentProcess.burstTime;
currentProcess.finished = true;
finishedProcessCount++;
}

for (int i = 0; i < noOfProcesses; i++) {
turnAroundTime[i] = processes[i].turnAroundTime;
}

return turnAroundTime;
}

/**
* Calculates the Waiting Time (WT) for each process.
*
* @param turnAroundTime The Turn Around Times for each process.
* @param burstTimes The burst times for each process.
* @return An array of Waiting Times for each process.
*/
public static int[] calculateWaitingTime(int[] turnAroundTime, int[] burstTimes) {
int[] waitingTime = new int[turnAroundTime.length];
for (int i = 0; i < turnAroundTime.length; i++) {
waitingTime[i] = turnAroundTime[i] - burstTimes[i];
}
return waitingTime;
}

/**
* Finds the next process to be scheduled based on arrival times and the current time.
*
* @param processes Array of Process objects.
* @param currentTime The current time in the scheduling process.
* @return The index of the next process to be scheduled, or PROCESS_NOT_FOUND if no process is ready.
*/
private static int findNextProcess(Process[] processes, int currentTime) {
return findHighestResponseRatio(processes, currentTime);
}

/**
* Finds the process with the highest response ratio.
*
* <p>The response ratio is calculated as:
* (waiting time + burst time) / burst time
* where waiting time = current time - arrival time</p>
*
* @param processes Array of Process objects.
* @param currentTime The current time in the scheduling process.
* @return The index of the process with the highest response ratio, or PROCESS_NOT_FOUND if no process is ready.
*/
private static int findHighestResponseRatio(Process[] processes, int currentTime) {
double maxResponseRatio = INITIAL_MAX_RESPONSE_RATIO;
int maxIndex = PROCESS_NOT_FOUND;

for (int i = 0; i < processes.length; i++) {
Process process = processes[i];
if (!process.finished && process.arrivalTime <= currentTime) {
double responseRatio = process.calculateResponseRatio(currentTime);
if (responseRatio > maxResponseRatio) {
maxResponseRatio = responseRatio;
maxIndex = i;
}
}
}
return maxIndex;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.thealgorithms.scheduling;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

import org.junit.jupiter.api.Test;

public class HighestResponseRatioNextSchedulingTest {

@Test
public void testCalculateTurnAroundTime() {
String[] processNames = {"A", "B", "C"};
int[] arrivalTimes = {0, 2, 4};
int[] burstTimes = {3, 1, 2};
int noOfProcesses = 3;

int[] expectedTurnAroundTimes = {3, 2, 2};
int[] actualTurnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, noOfProcesses);

assertArrayEquals(expectedTurnAroundTimes, actualTurnAroundTimes, "Turn Around Times do not match");
}

@Test
public void testCalculateWaitingTime() {
int[] turnAroundTimes = {3, 1, 5};
int[] burstTimes = {3, 1, 2};

int[] expectedWaitingTimes = {0, 0, 3};
int[] actualWaitingTimes = HighestResponseRatioNextScheduling.calculateWaitingTime(turnAroundTimes, burstTimes);

assertArrayEquals(expectedWaitingTimes, actualWaitingTimes, "Waiting Times do not match");
}

@Test
public void testCompleteSchedulingScenario() {
String[] processNames = {"A", "B", "C"};
int[] arrivalTimes = {0, 1, 2};
int[] burstTimes = {5, 2, 1};

int[] expectedTurnAroundTimes = {5, 7, 4};
int[] turnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, processNames.length);
assertArrayEquals(expectedTurnAroundTimes, turnAroundTimes, "Turn Around Times do not match");

int[] expectedWaitingTimes = {0, 5, 3};
int[] waitingTimes = HighestResponseRatioNextScheduling.calculateWaitingTime(turnAroundTimes, burstTimes);
assertArrayEquals(expectedWaitingTimes, waitingTimes, "Waiting Times do not match");
}

@Test
public void testZeroProcesses() {
String[] processNames = {};
int[] arrivalTimes = {};
int[] burstTimes = {};
int noOfProcesses = 0;

int[] expectedTurnAroundTimes = {};
int[] actualTurnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, noOfProcesses);

assertArrayEquals(expectedTurnAroundTimes, actualTurnAroundTimes, "Turn Around Times for zero processes should be an empty array");
}

@Test
public void testAllProcessesArriveAtSameTime() {
String[] processNames = {"A", "B", "C", "D"};
int[] arrivalTimes = {0, 0, 0, 0};
int[] burstTimes = {4, 3, 1, 2};
int noOfProcesses = 4;

int[] expectedTurnAroundTimes = {4, 10, 5, 7};
int[] actualTurnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, noOfProcesses);

assertArrayEquals(expectedTurnAroundTimes, actualTurnAroundTimes, "Turn Around Times for processes arriving at the same time do not match");
}

@Test
public void testProcessesWithZeroBurstTime() {
String[] processNames = {"A", "B", "C"};
int[] arrivalTimes = {0, 1, 2};
int[] burstTimes = {3, 0, 2};
int noOfProcesses = 3;

int[] expectedTurnAroundTimes = {3, 2, 3};
int[] actualTurnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, noOfProcesses);

assertArrayEquals(expectedTurnAroundTimes, actualTurnAroundTimes, "Turn Around Times for processes with zero burst time do not match");
}

@Test
public void testProcessesWithLargeGapsBetweenArrivals() {
String[] processNames = {"A", "B", "C"};
int[] arrivalTimes = {0, 100, 200};
int[] burstTimes = {10, 10, 10};
int noOfProcesses = 3;

int[] expectedTurnAroundTimes = {10, 10, 10};
int[] actualTurnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, noOfProcesses);

assertArrayEquals(expectedTurnAroundTimes, actualTurnAroundTimes, "Turn Around Times for processes with large gaps between arrivals do not match");
}

@Test
public void testProcessesWithVeryLargeBurstTimes() {
String[] processNames = {"A", "B"};
int[] arrivalTimes = {0, 1};
int[] burstTimes = {Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2};
int noOfProcesses = 2;

int[] expectedTurnAroundTimes = {Integer.MAX_VALUE / 2, Integer.MAX_VALUE - 2};
int[] actualTurnAroundTimes = HighestResponseRatioNextScheduling.calculateTurnAroundTime(processNames, arrivalTimes, burstTimes, noOfProcesses);

assertArrayEquals(expectedTurnAroundTimes, actualTurnAroundTimes, "Turn Around Times for processes with very large burst times do not match");
}
}