Add disk scheduling algorithms (#5748)

This commit is contained in:
xuyang471
2024-10-14 16:22:30 +08:00
committed by GitHub
parent e9b897bdeb
commit 85b3b1dfbe
10 changed files with 674 additions and 0 deletions

View File

@ -0,0 +1,80 @@
package com.thealgorithms.scheduling.diskscheduling;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Circular Look Scheduling (C-LOOK) is a disk scheduling algorithm similar to
* the C-SCAN algorithm but with a key difference. In C-LOOK, the disk arm also
* moves in one direction to service requests, but instead of going all the way
* to the end of the disk, it only goes as far as the furthest request in the
* current direction. After servicing the last request in the current direction,
* the arm immediately jumps back to the closest request on the other side without
* moving to the disk's extreme ends. This reduces the unnecessary movement of the
* disk arm, resulting in better performance compared to C-SCAN, while still
* maintaining fair wait times for requests.
*/
public class CircularLookScheduling {
private int currentPosition;
private boolean movingUp;
private final int maxCylinder;
public CircularLookScheduling(int startPosition, boolean movingUp, int maxCylinder) {
this.currentPosition = startPosition;
this.movingUp = movingUp;
this.maxCylinder = maxCylinder;
}
public List<Integer> execute(List<Integer> requests) {
List<Integer> result = new ArrayList<>();
// Filter and sort valid requests in both directions
List<Integer> upRequests = new ArrayList<>();
List<Integer> downRequests = new ArrayList<>();
for (int request : requests) {
if (request >= 0 && request < maxCylinder) {
if (request > currentPosition) {
upRequests.add(request);
} else if (request < currentPosition) {
downRequests.add(request);
}
}
}
Collections.sort(upRequests);
Collections.sort(downRequests);
if (movingUp) {
// Process all requests in the upward direction
result.addAll(upRequests);
// Jump to the lowest request and process all requests in the downward direction
result.addAll(downRequests);
} else {
// Process all requests in the downward direction (in reverse order)
Collections.reverse(downRequests);
result.addAll(downRequests);
// Jump to the highest request and process all requests in the upward direction (in reverse order)
Collections.reverse(upRequests);
result.addAll(upRequests);
}
// Update current position to the last processed request
if (!result.isEmpty()) {
currentPosition = result.get(result.size() - 1);
}
return result;
}
public int getCurrentPosition() {
return currentPosition;
}
public boolean isMovingUp() {
return movingUp;
}
}

View File

@ -0,0 +1,83 @@
package com.thealgorithms.scheduling.diskscheduling;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Circular Scan Scheduling (C-SCAN) is a disk scheduling algorithm that
* works by moving the disk arm in one direction to service requests until
* it reaches the end of the disk. Once it reaches the end, instead of reversing
* direction like in the SCAN algorithm, the arm moves back to the starting point
* without servicing any requests. This ensures a more uniform wait time for all
* requests, especially those near the disk edges. The algorithm then continues in
* the same direction, making it effective for balancing service time across all disk sectors.
*/
public class CircularScanScheduling {
private int currentPosition;
private boolean movingUp;
private final int diskSize;
public CircularScanScheduling(int startPosition, boolean movingUp, int diskSize) {
this.currentPosition = startPosition;
this.movingUp = movingUp;
this.diskSize = diskSize;
}
public List<Integer> execute(List<Integer> requests) {
if (requests.isEmpty()) {
return new ArrayList<>(); // Return empty list if there are no requests
}
List<Integer> sortedRequests = new ArrayList<>(requests);
Collections.sort(sortedRequests);
List<Integer> result = new ArrayList<>();
if (movingUp) {
// Moving up: process requests >= current position
for (int request : sortedRequests) {
if (request >= currentPosition && request < diskSize) {
result.add(request);
}
}
// Jump to the smallest request and continue processing from the start
for (int request : sortedRequests) {
if (request < currentPosition) {
result.add(request);
}
}
} else {
// Moving down: process requests <= current position in reverse order
for (int i = sortedRequests.size() - 1; i >= 0; i--) {
int request = sortedRequests.get(i);
if (request <= currentPosition) {
result.add(request);
}
}
// Jump to the largest request and continue processing in reverse order
for (int i = sortedRequests.size() - 1; i >= 0; i--) {
int request = sortedRequests.get(i);
if (request > currentPosition) {
result.add(request);
}
}
}
// Set final position to the last request processed
if (!result.isEmpty()) {
currentPosition = result.get(result.size() - 1);
}
return result;
}
public int getCurrentPosition() {
return currentPosition;
}
public boolean isMovingUp() {
return movingUp;
}
}

View File

@ -0,0 +1,95 @@
package com.thealgorithms.scheduling.diskscheduling;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* https://en.wikipedia.org/wiki/LOOK_algorithm
* Look Scheduling algorithm implementation.
* The Look algorithm moves the disk arm to the closest request in the current direction,
* and once it processes all requests in that direction, it reverses the direction.
*/
public class LookScheduling {
private final int maxTrack;
private final int currentPosition;
private boolean movingUp;
private int farthestPosition;
public LookScheduling(int startPosition, boolean initialDirection, int maxTrack) {
this.currentPosition = startPosition;
this.movingUp = initialDirection;
this.maxTrack = maxTrack;
}
/**
* Executes the Look Scheduling algorithm on the given list of requests.
*
* @param requests List of disk requests.
* @return Order in which requests are processed.
*/
public List<Integer> execute(List<Integer> requests) {
List<Integer> result = new ArrayList<>();
List<Integer> lower = new ArrayList<>();
List<Integer> upper = new ArrayList<>();
// Split requests into two lists based on their position relative to current position
for (int request : requests) {
if (request >= 0 && request < maxTrack) {
if (request < currentPosition) {
lower.add(request);
} else {
upper.add(request);
}
}
}
// Sort the requests
Collections.sort(lower);
Collections.sort(upper);
// Process the requests depending on the initial moving direction
if (movingUp) {
// Process requests in the upward direction
result.addAll(upper);
if (!upper.isEmpty()) {
farthestPosition = upper.get(upper.size() - 1);
}
// Reverse the direction and process downward
movingUp = false;
Collections.reverse(lower);
result.addAll(lower);
if (!lower.isEmpty()) {
farthestPosition = Math.max(farthestPosition, lower.get(0));
}
} else {
// Process requests in the downward direction
Collections.reverse(lower);
result.addAll(lower);
if (!lower.isEmpty()) {
farthestPosition = lower.get(0);
}
// Reverse the direction and process upward
movingUp = true;
result.addAll(upper);
if (!upper.isEmpty()) {
farthestPosition = Math.max(farthestPosition, upper.get(upper.size() - 1));
}
}
return result;
}
public int getCurrentPosition() {
return currentPosition;
}
public boolean isMovingUp() {
return movingUp;
}
public int getFarthestPosition() {
return farthestPosition;
}
}

View File

@ -0,0 +1,56 @@
package com.thealgorithms.scheduling.diskscheduling;
import java.util.ArrayList;
import java.util.List;
/**
*https://en.wikipedia.org/wiki/Shortest_seek_first
* Shortest Seek First (SFF) Scheduling algorithm implementation.
* The SFF algorithm selects the next request to be serviced based on the shortest distance
* from the current position of the disk arm. It continuously evaluates all pending requests
* and chooses the one that requires the least amount of movement to service.
*
* This approach minimizes the average seek time, making it efficient in terms of response
* time for individual requests. However, it may lead to starvation for requests located
* further away from the current position of the disk arm.
*
* The SFF algorithm is particularly effective in systems where quick response time
* is crucial, as it ensures that the most accessible requests are prioritized for servicing.
*/
public class SSFScheduling {
private int currentPosition;
public SSFScheduling(int currentPosition) {
this.currentPosition = currentPosition;
}
public List<Integer> execute(List<Integer> requests) {
List<Integer> result = new ArrayList<>(requests);
List<Integer> orderedRequests = new ArrayList<>();
while (!result.isEmpty()) {
int closest = findClosest(result);
orderedRequests.add(closest);
result.remove(Integer.valueOf(closest));
currentPosition = closest;
}
return orderedRequests;
}
private int findClosest(List<Integer> requests) {
int minDistance = Integer.MAX_VALUE;
int closest = -1;
for (int request : requests) {
int distance = Math.abs(currentPosition - request);
if (distance < minDistance) {
minDistance = distance;
closest = request;
}
}
return closest;
}
public int getCurrentPosition() {
return currentPosition;
}
}

View File

@ -0,0 +1,82 @@
package com.thealgorithms.scheduling.diskscheduling;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* https://en.wikipedia.org/wiki/Elevator_algorithm
* SCAN Scheduling algorithm implementation.
* The SCAN algorithm moves the disk arm towards one end of the disk, servicing all requests
* along the way until it reaches the end. Once it reaches the end, it reverses direction
* and services the requests on its way back.
*
* This algorithm ensures that all requests are serviced in a fair manner,
* while minimizing the seek time for requests located close to the current position
* of the disk arm.
*
* The SCAN algorithm is particularly useful in environments with a large number of
* disk requests, as it reduces the overall movement of the disk arm compared to
*/
public class ScanScheduling {
private int headPosition;
private int diskSize;
private boolean movingUp;
public ScanScheduling(int headPosition, boolean movingUp, int diskSize) {
this.headPosition = headPosition;
this.movingUp = movingUp;
this.diskSize = diskSize;
}
public List<Integer> execute(List<Integer> requests) {
// If the request list is empty, return an empty result
if (requests.isEmpty()) {
return new ArrayList<>();
}
List<Integer> result = new ArrayList<>();
List<Integer> left = new ArrayList<>();
List<Integer> right = new ArrayList<>();
// Separate requests into those smaller than the current head position and those larger
for (int request : requests) {
if (request < headPosition) {
left.add(request);
} else {
right.add(request);
}
}
// Sort the requests
Collections.sort(left);
Collections.sort(right);
// Simulate the disk head movement
if (movingUp) {
// Head moving upward, process right-side requests first
result.addAll(right);
// After reaching the end of the disk, reverse direction and process left-side requests
result.add(diskSize - 1); // Simulate the head reaching the end of the disk
Collections.reverse(left);
result.addAll(left);
} else {
// Head moving downward, process left-side requests first
Collections.reverse(left);
result.addAll(left);
// After reaching the start of the disk, reverse direction and process right-side requests
result.add(0); // Simulate the head reaching the start of the disk
result.addAll(right);
}
return result;
}
public int getHeadPosition() {
return headPosition;
}
public boolean isMovingUp() {
return movingUp;
}
}