From 427adbd874ca730f8170aa5e70e9e8250413af7a Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 17:05:00 +0800 Subject: [PATCH 01/16] Add boundary traversal of binary tree Both time complexity and space complexity are O(n) --- .../trees/BoundaryTraversal.java | 163 ++++++++++++++++++ .../trees/BoundaryTraversalTest.java | 111 ++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java new file mode 100644 index 000000000000..a071a80634a5 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -0,0 +1,163 @@ +package com.thealgorithms.datastructures.trees; + +import java.util.*; + +/**BoundaryTraversal + * + * Start with the Root: + * Add the root node to the boundary list. + * Traverse the Left Boundary (Excluding Leaf Nodes): + * Move down the left side of the tree, adding each non-leaf node to the boundary list. + * If a node has a left child, go left; otherwise, go right. + * Visit All Leaf Nodes: + * Traverse the tree and add all leaf nodes to the boundary list, from left to right. + * Traverse the Right Boundary (Excluding Leaf Nodes) in Reverse Order: + * Move up the right side of the tree, adding each non-leaf node to a temporary list. + * If a node has a right child, go right; otherwise, go left. + * Reverse the temporary list and add it to the boundary list. + * Combine and Output: + * The final boundary list contains the root, left boundary, leaf nodes, and reversed right boundary in that order. + */ +public final class BoundaryTraversal { + private BoundaryTraversal() {} + + // Main function for boundary traversal, returns a list of boundary nodes in order + public static List boundaryTraversal(BinaryTree.Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + + // Add root node if it's not a leaf node + if (!isLeaf(root)) { + result.add(root.data); + } + + // Add left boundary + addLeftBoundary(root, result); + + // Add leaf nodes + addLeaves(root, result); + + // Add right boundary + addRightBoundary(root, result); + + return result; + } + + // Adds the left boundary, including nodes that have no left child but have a right child + private static void addLeftBoundary(BinaryTree.Node node, List result) { + BinaryTree.Node cur = node.left; + + // If there is no left child but there is a right child, treat the right child as part of the left boundary + if (cur == null && node.right != null) { + cur = node.right; + } + + while (cur != null) { + if (!isLeaf(cur)) { + result.add(cur.data); // Add non-leaf nodes to result + } + if (cur.left != null) { + cur = cur.left; // Move to the left child + } else if (cur.right != null) { + cur = cur.right; // If left child is null, move to the right child + } else { + break; // Stop if there are no children + } + } + } + + // Adds leaf nodes (nodes without children) + private static void addLeaves(BinaryTree.Node node, List result) { + if (node == null) { + return; + } + if (isLeaf(node)) { + result.add(node.data); // Add leaf node + } else { + addLeaves(node.left, result); // Recur for left subtree + addLeaves(node.right, result); // Recur for right subtree + } + } + + // Adds the right boundary, excluding leaf nodes + private static void addRightBoundary(BinaryTree.Node node, List result) { + BinaryTree.Node cur = node.right; + List temp = new ArrayList<>(); + + // If no right boundary is present and there is no left subtree, skip + if (cur != null && node.left == null) { + return; + } + while (cur != null) { + if (!isLeaf(cur)) { + temp.add(cur.data); // Store non-leaf nodes temporarily + } + if (cur.right != null) { + cur = cur.right; // Move to the right child + } else if (cur.left != null) { + cur = cur.left; // If right child is null, move to the left child + } else { + break; // Stop if there are no children + } + } + + // Add the right boundary nodes in reverse order + for (int i = temp.size() - 1; i >= 0; i--) { + result.add(temp.get(i)); + } + } + + // Checks if a node is a leaf node + private static boolean isLeaf(BinaryTree.Node node) { + return (node.left == null && node.right == null); + } + + // Iterative boundary traversal + public static List iterativeBoundaryTraversal(BinaryTree.Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + + // Add root node if it's not a leaf node + if (!isLeaf(root)) { + result.add(root.data); + } + + // Handle the left boundary + BinaryTree.Node cur = root.left; + if (cur == null && root.right != null) { + cur = root.right; + } + while (cur != null) { + if (!isLeaf(cur)) { + result.add(cur.data); // Add non-leaf nodes to result + } + cur = (cur.left != null) ? cur.left : cur.right; // Prioritize left child, move to right if left is null + } + + // Add leaf nodes + addLeaves(root, result); + + // Handle the right boundary using a stack (reverse order) + cur = root.right; + Deque stack = new LinkedList<>(); + if (cur != null && root.left == null) { + return result; + } + while (cur != null) { + if (!isLeaf(cur)) { + stack.push(cur.data); // Temporarily store right boundary nodes in a stack + } + cur = (cur.right != null) ? cur.right : cur.left; // Prioritize right child, move to left if right is null + } + + // Add the right boundary nodes from the stack to maintain the correct order + while (!stack.isEmpty()) { + result.add(stack.pop()); + } + return result; + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java new file mode 100644 index 000000000000..5c4222eba372 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -0,0 +1,111 @@ +package com.thealgorithms.datastructures.trees; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * + */ +public class BoundaryTraversalTest { + + + @Test + public void testNullRoot() { + assertEquals(Collections.emptyList(), BoundaryTraversal.boundaryTraversal(null)); + assertEquals(Collections.emptyList(), BoundaryTraversal.iterativeBoundaryTraversal(null)); + } + + @Test + public void testSingleNodeTree() { + final BinaryTree.Node root = new BinaryTree.Node(1); + + List expected = List.of(1); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 + + */ + @Test + public void testCompleteBinaryTree() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + 1, 2, 3, 4, 5, 6, 7 + }); + + List expected = List.of(1, 2, 4, 5, 6, 7, 3); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 1 + / \ + 2 7 + / \ + 3 8 + \ / + 4 9 + / \ + 5 6 + / \ + 10 11 + */ + @Test + public void testBoundaryTraversal() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + 1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11 + }); + + List expected = List.of(1, 2, 3, 4, 5, 6, 10, 11, 9, 8, 7); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 1 + / + 2 + / + 3 + / + 4 + */ + @Test + public void testLeftSkewedTree() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1,2,null,3,null,4,null}); + + List expected = List.of(1,2,3,4); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 5 + \ + 6 + \ + 7 + \ + 8 + */ + @Test + public void testRightSkewedTree() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5,null,6,null,7,null,8}); + + List expected = List.of(5, 6, 7,8); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + + +} From c04a8d2efa5005f7929df9da2e8e3018a66e12c7 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 18:14:00 +0800 Subject: [PATCH 02/16] format modification --- .../trees/BoundaryTraversal.java | 15 ++++++++----- .../trees/BoundaryTraversalTest.java | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java index a071a80634a5..ade5232a8b2f 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -1,9 +1,13 @@ package com.thealgorithms.datastructures.trees; -import java.util.*; - -/**BoundaryTraversal - * +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +/** + * BoundaryTraversal + *

* Start with the Root: * Add the root node to the boundary list. * Traverse the Left Boundary (Excluding Leaf Nodes): @@ -19,7 +23,8 @@ * The final boundary list contains the root, left boundary, leaf nodes, and reversed right boundary in that order. */ public final class BoundaryTraversal { - private BoundaryTraversal() {} + private BoundaryTraversal() { + } // Main function for boundary traversal, returns a list of boundary nodes in order public static List boundaryTraversal(BinaryTree.Node root) { diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java index 5c4222eba372..49a047e6c5dc 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -1,10 +1,11 @@ package com.thealgorithms.datastructures.trees; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; import java.util.Collections; import java.util.List; -import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * @@ -27,6 +28,7 @@ public void testSingleNodeTree() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 1 / \ @@ -37,7 +39,7 @@ public void testSingleNodeTree() { */ @Test public void testCompleteBinaryTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ 1, 2, 3, 4, 5, 6, 7 }); @@ -46,6 +48,7 @@ public void testCompleteBinaryTree() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 1 / \ @@ -61,7 +64,7 @@ public void testCompleteBinaryTree() { */ @Test public void testBoundaryTraversal() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ 1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11 }); @@ -70,6 +73,7 @@ public void testBoundaryTraversal() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 1 / @@ -81,13 +85,14 @@ public void testBoundaryTraversal() { */ @Test public void testLeftSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1,2,null,3,null,4,null}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{1, 2, null, 3, null, 4, null}); - List expected = List.of(1,2,3,4); + List expected = List.of(1, 2, 3, 4); assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 5 \ @@ -99,9 +104,9 @@ public void testLeftSkewedTree() { */ @Test public void testRightSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5,null,6,null,7,null,8}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{5, null, 6, null, 7, null, 8}); - List expected = List.of(5, 6, 7,8); + List expected = List.of(5, 6, 7, 8); assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); From 7bbcc8b32a046eb35c4ed405256759a38f34d0ed Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 19:22:31 +0800 Subject: [PATCH 03/16] Update BoundaryTraversal.java --- .../thealgorithms/datastructures/trees/BoundaryTraversal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java index ade5232a8b2f..eb09f900d6a4 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -165,4 +165,4 @@ public static List iterativeBoundaryTraversal(BinaryTree.Node root) { } return result; } -} \ No newline at end of file +} From e5129585fe865a90a99a6a9585f64e3fdc1610d8 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 19:28:59 +0800 Subject: [PATCH 04/16] Update BoundaryTraversal.java --- .../thealgorithms/datastructures/trees/BoundaryTraversal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java index eb09f900d6a4..9a79902cc598 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -116,7 +116,7 @@ private static void addRightBoundary(BinaryTree.Node node, List result) // Checks if a node is a leaf node private static boolean isLeaf(BinaryTree.Node node) { - return (node.left == null && node.right == null); + return node.left == null && node.right == null; } // Iterative boundary traversal From f01eed065684cd678d62deca057b02b0e71f913d Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 22:42:53 +0800 Subject: [PATCH 05/16] Update BoundaryTraversalTest.java --- .../trees/BoundaryTraversalTest.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java index 49a047e6c5dc..7b7f9a316f73 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -1,11 +1,11 @@ package com.thealgorithms.datastructures.trees; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Collections; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @@ -39,9 +39,7 @@ public void testSingleNodeTree() { */ @Test public void testCompleteBinaryTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ - 1, 2, 3, 4, 5, 6, 7 - }); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, 3, 4, 5, 6, 7}); List expected = List.of(1, 2, 4, 5, 6, 7, 3); @@ -64,9 +62,7 @@ public void testCompleteBinaryTree() { */ @Test public void testBoundaryTraversal() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ - 1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11 - }); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11}); List expected = List.of(1, 2, 3, 4, 5, 6, 10, 11, 9, 8, 7); @@ -85,7 +81,7 @@ public void testBoundaryTraversal() { */ @Test public void testLeftSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{1, 2, null, 3, null, 4, null}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, null, 3, null, 4, null}); List expected = List.of(1, 2, 3, 4); @@ -104,7 +100,7 @@ public void testLeftSkewedTree() { */ @Test public void testRightSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{5, null, 6, null, 7, null, 8}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5, null, 6, null, 7, null, 8}); List expected = List.of(5, 6, 7, 8); From f25a77a25add933f17a81ecd3b492f0295d696d9 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 22:45:17 +0800 Subject: [PATCH 06/16] Update BoundaryTraversalTest.java --- .../datastructures/trees/BoundaryTraversalTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java index 7b7f9a316f73..515dac88ce09 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -4,7 +4,6 @@ import java.util.Collections; import java.util.List; - import org.junit.jupiter.api.Test; /** @@ -12,7 +11,6 @@ */ public class BoundaryTraversalTest { - @Test public void testNullRoot() { assertEquals(Collections.emptyList(), BoundaryTraversal.boundaryTraversal(null)); @@ -107,6 +105,4 @@ public void testRightSkewedTree() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } - - } From 93814640f50a99f68b9dc2c4851bc076a2109025 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Thu, 10 Oct 2024 19:08:28 +0800 Subject: [PATCH 07/16] Add Elliptic Curve Cryptography Algorithm Implementation of ECC encryption algorithm and unit test with java --- .../java/com/thealgorithms/ciphers/ECC.java | 238 ++++++++++++++++++ .../com/thealgorithms/ciphers/ECCTest.java | 108 ++++++++ 2 files changed, 346 insertions(+) create mode 100644 src/main/java/com/thealgorithms/ciphers/ECC.java create mode 100644 src/test/java/com/thealgorithms/ciphers/ECCTest.java diff --git a/src/main/java/com/thealgorithms/ciphers/ECC.java b/src/main/java/com/thealgorithms/ciphers/ECC.java new file mode 100644 index 000000000000..3d9ac1d0360d --- /dev/null +++ b/src/main/java/com/thealgorithms/ciphers/ECC.java @@ -0,0 +1,238 @@ +package com.thealgorithms.ciphers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * ECC - Elliptic Curve Cryptography + * Elliptic Curve Cryptography is a public-key cryptography method that uses the algebraic structure of + * elliptic curves over finite fields. ECC provides a higher level of security with smaller key sizes compared + * to other public-key methods like RSA, making it particularly suitable for environments where computational + * resources are limited, such as mobile devices and embedded systems. + * + * This class implements elliptic curve cryptography, providing encryption and decryption + * functionalities based on public and private key pairs. + * + * @author xuyang + */ +public class ECC { + + private BigInteger privateKey; // Private key used for decryption + private ECPoint publicKey; // Public key used for encryption + private EllipticCurve curve; // Elliptic curve used in cryptography + private ECPoint basePoint; // Base point G on the elliptic curve + + public EllipticCurve getCurve() { + return curve; // Returns the elliptic curve + } + + public ECC(int bits) { + generateKeys(bits); // Generates public-private key pair + } + + // Getter and Setter for private key + public BigInteger getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(BigInteger privateKey) { + this.privateKey = privateKey; + } + + public void setCurve(EllipticCurve curve) { + this.curve = curve; + } + + /** + * Encrypts the message using the public key. + * The message is transformed into an ECPoint and encrypted with elliptic curve operations. + * + * @param message The plain message to be encrypted + * @return The encrypted message as an array of ECPoints (R, S) + */ + public synchronized ECPoint[] encrypt(String message) { + BigInteger m = new BigInteger(message.getBytes()); // Convert message to BigInteger + SecureRandom r = new SecureRandom(); // Generate random value for k + BigInteger k = new BigInteger(curve.getFieldSize(), r); // Generate random scalar k + + // Calculate point R = k * G, where G is the base point + ECPoint R = basePoint.multiply(k, curve.getP(), curve.getA()); + + // Calculate point S = k * publicKey + encodedMessage + ECPoint S = publicKey.multiply(k, curve.getP(), curve.getA()).add(curve.encodeMessage(m), curve.getP(), curve.getA()); + + return new ECPoint[] { R, S }; // Return encrypted message as two ECPoints + } + + /** + * Decrypts the encrypted message using the private key. + * The decryption process is the reverse of encryption, recovering the original message. + * + * @param encryptedMessage The encrypted message as an array of ECPoints (R, S) + * @return The decrypted plain message as a String + */ + public synchronized String decrypt(ECPoint[] encryptedMessage) { + ECPoint R = encryptedMessage[0]; // First part of ciphertext + ECPoint S = encryptedMessage[1]; // Second part of ciphertext + + // Perform decryption: S - R * privateKey + ECPoint decodedMessage = S.subtract(R.multiply(privateKey, curve.getP(), curve.getA()), curve.getP(), curve.getA()); + + BigInteger m = curve.decodeMessage(decodedMessage); // Decode the message from ECPoint + + return new String(m.toByteArray()); // Convert BigInteger back to String + } + + /** + * Generates a new public-private key pair for encryption and decryption. + * + * @param bits The size (in bits) of the keys to generate + */ + public final synchronized void generateKeys(int bits) { + SecureRandom r = new SecureRandom(); + curve = new EllipticCurve(bits); // Initialize a new elliptic curve + basePoint = curve.getBasePoint(); // Set the base point G + + // Generate private key as a random BigInteger + privateKey = new BigInteger(bits, r); + + // Generate public key as the point publicKey = privateKey * G + publicKey = basePoint.multiply(privateKey, curve.getP(), curve.getA()); + } + + /** + * Class representing an elliptic curve with the form y^2 = x^3 + ax + b. + */ + public static class EllipticCurve { + private final BigInteger a; // Coefficient a in the curve equation + private final BigInteger b; // Coefficient b in the curve equation + private final BigInteger p; // Prime number p, defining the finite field + private final ECPoint basePoint; // Base point G on the curve + + // Constructor with explicit parameters for a, b, p, and base point + public EllipticCurve(BigInteger a, BigInteger b, BigInteger p, ECPoint basePoint) { + this.a = a; + this.b = b; + this.p = p; + this.basePoint = basePoint; + } + + // Constructor that randomly generates the curve parameters + public EllipticCurve(int bits) { + SecureRandom r = new SecureRandom(); + this.p = BigInteger.probablePrime(bits, r); // Random prime p + this.a = new BigInteger(bits, r); // Random coefficient a + this.b = new BigInteger(bits, r); // Random coefficient b + this.basePoint = new ECPoint(BigInteger.valueOf(4), BigInteger.valueOf(8)); // Fixed base point G + } + + public ECPoint getBasePoint() { + return basePoint; + } + + public BigInteger getP() { + return p; + } + + public BigInteger getA() { + return a; + } + + public BigInteger getB() { + return b; + } + + public int getFieldSize() { + return p.bitLength(); + } + + public ECPoint encodeMessage(BigInteger message) { + // Simple encoding of a message as an ECPoint (this is a simplified example) + return new ECPoint(message, message); + } + + public BigInteger decodeMessage(ECPoint point) { + return point.getX(); // Decode the message from ECPoint (simplified) + } + } + + /** + * Class representing a point on the elliptic curve. + */ + public static class ECPoint { + private final BigInteger x; // X-coordinate of the point + private final BigInteger y; // Y-coordinate of the point + + public ECPoint(BigInteger x, BigInteger y) { + this.x = x; + this.y = y; + } + + public BigInteger getX() { + return x; + } + + public BigInteger getY() { + return y; + } + + @Override + public String toString() { + return "ECPoint(x=" + x.toString() + ", y=" + y.toString() + ")"; + } + + /** + * Add two points on the elliptic curve. + */ + public ECPoint add(ECPoint other, BigInteger p, BigInteger a) { + if (this.x.equals(BigInteger.ZERO) && this.y.equals(BigInteger.ZERO)) { + return other; // If this point is the identity, return the other point + } + if (other.x.equals(BigInteger.ZERO) && other.y.equals(BigInteger.ZERO)) { + return this; // If the other point is the identity, return this point + } + + BigInteger lambda; + if (this.equals(other)) { + // Special case: point doubling + lambda = (this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a)) + .multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p); + } else { + // General case: adding two different points + lambda = (other.y.subtract(this.y)) + .multiply(other.x.subtract(this.x).modInverse(p)).mod(p); + } + + BigInteger xr = lambda.pow(2).subtract(this.x).subtract(other.x).mod(p); + BigInteger yr = lambda.multiply(this.x.subtract(xr)).subtract(this.y).mod(p); + + return new ECPoint(xr, yr); + } + + /** + * Subtract two points on the elliptic curve. + */ + public ECPoint subtract(ECPoint other, BigInteger p, BigInteger a) { + ECPoint negOther = new ECPoint(other.x, p.subtract(other.y)); // Negate the Y coordinate + return this.add(negOther, p, a); // Add the negated point + } + + /** + * Multiply a point by a scalar (repeated addition). + */ + public ECPoint multiply(BigInteger k, BigInteger p, BigInteger a) { + ECPoint result = new ECPoint(BigInteger.ZERO, BigInteger.ZERO); // Identity point + ECPoint addend = this; + + while (k.signum() > 0) { + if (k.testBit(0)) { + result = result.add(addend, p, a); // Add when k's bit is 1 + } + addend = addend.add(addend, p, a); // Double the point + k = k.shiftRight(1); // Shift k to the right by 1 bit + } + + return result; // Return the resulting point + } + } +} diff --git a/src/test/java/com/thealgorithms/ciphers/ECCTest.java b/src/test/java/com/thealgorithms/ciphers/ECCTest.java new file mode 100644 index 000000000000..413830ace3a2 --- /dev/null +++ b/src/test/java/com/thealgorithms/ciphers/ECCTest.java @@ -0,0 +1,108 @@ +package com.thealgorithms.ciphers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.api.Test; +import java.math.BigInteger; + +/** + * ECCTest - Unit tests for the ECC (Elliptic Curve Cryptography) implementation. + * This class contains various test cases to validate the encryption and decryption functionalities. + * It ensures the correctness and randomness of ECC operations. + * + * @author xuyang + */ +public class ECCTest { + ECC ecc = new ECC(256); // Generate a 256-bit ECC key pair. Calls generateKeys(bits) to create keys including privateKey and publicKey. + + /** + * Test the encryption functionality: convert plaintext to ciphertext and output relevant encryption data. + */ + @Test + void testEncrypt() { + String textToEncrypt = "Elliptic Curve Cryptography"; + + ECC.ECPoint[] cipherText = ecc.encrypt(textToEncrypt); // Perform encryption + + // Output private key information + System.out.println("Private Key: " + ecc.getPrivateKey()); + + // Output elliptic curve parameters + ECC.EllipticCurve curve = ecc.getCurve(); + System.out.println("Elliptic Curve Parameters:"); + System.out.println("a: " + curve.getA()); + System.out.println("b: " + curve.getB()); + System.out.println("p: " + curve.getP()); + System.out.println("Base Point G: " + curve.getBasePoint()); + + // Verify that the ciphertext is not empty + assertEquals(cipherText.length, 2); // Check if the ciphertext contains two points (R and S) + + // Output the encrypted coordinate points + System.out.println("Encrypted Points:"); + for (ECC.ECPoint point : cipherText) { + System.out.println(point); // Calls ECPoint's toString() method + } + } + + /** + * Test the decryption functionality: convert ciphertext back to plaintext using known private key and elliptic curve parameters. + */ + @Test + void testDecryptWithKnownValues() { + // 1. Define the known private key + BigInteger knownPrivateKey = new BigInteger("28635978664199231399690075483195602260051035216440375973817268759912070302603"); + + // 2. Define the known elliptic curve parameters + BigInteger a = new BigInteger("64505295837372135469230827475895976532873592609649950000895066186842236488761"); // Replace with known a value + BigInteger b = new BigInteger("89111668838830965251111555638616364203833415376750835901427122343021749874324"); // Replace with known b value + BigInteger p = new BigInteger("107276428198310591598877737561885175918069075479103276920057092968372930219921"); // Replace with known p value + ECC.ECPoint basePoint = new ECC.ECPoint(new BigInteger("4"), new BigInteger("8")); // Replace with known base point coordinates + + // 3. Create the elliptic curve object + ECC.EllipticCurve curve = new ECC.EllipticCurve(a, b, p, basePoint); + + // 4. Define the known ciphertext containing two ECPoints (R, S) + ECC.ECPoint R = new ECC.ECPoint(new BigInteger("103077584019003058745849614420912636617007257617156724481937620119667345237687"), + new BigInteger("68193862907937248121971710522760893811582068323088661566426323952783362061817")); + ECC.ECPoint S = new ECC.ECPoint(new BigInteger("31932232426664380635434632300383525435115368414929679432313910646436992147798"), + new BigInteger("77299754382292904069123203569944908076819220797512755280123348910207308129766")); + ECC.ECPoint[] cipherText = new ECC.ECPoint[] { R, S }; + + // 5. Create an ECC instance and set the private key and curve parameters + ecc.setPrivateKey(knownPrivateKey); // Use setter method to set the private key + ecc.setCurve(curve); // Use setter method to set the elliptic curve + + // 6. Decrypt the known ciphertext + String decryptedMessage = ecc.decrypt(cipherText); + + // 7. Compare the decrypted plaintext with the expected value + String expectedMessage = "Elliptic Curve Cryptography"; // Expected plaintext + assertEquals(expectedMessage, decryptedMessage); + } + + /** + * Test that encrypting the same plaintext with ECC produces different ciphertexts. + */ + @Test + void testCipherTextRandomness() { + String message = "Elliptic Curve Cryptography"; + + ECC.ECPoint[] cipherText1 = ecc.encrypt(message); + ECC.ECPoint[] cipherText2 = ecc.encrypt(message); + + assertNotEquals(cipherText1, cipherText2); // Ensure that the two ciphertexts are different + } + + /** + * Test the entire ECC encryption and decryption process. + */ + @Test + void testECCEncryptionAndDecryption() { + String textToEncrypt = "Elliptic Curve Cryptography"; + ECC.ECPoint[] cipherText = ecc.encrypt(textToEncrypt); + String decryptedText = ecc.decrypt(cipherText); + assertEquals(textToEncrypt, decryptedText); // Verify that the decrypted text matches the original text + } +} From 9c42a5fdef86e0c9659b79f5561cef7442dc60df Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Thu, 10 Oct 2024 20:32:00 +0800 Subject: [PATCH 08/16] Code update --- .../java/com/thealgorithms/ciphers/ECC.java | 72 +++++++++---------- .../com/thealgorithms/ciphers/ECCTest.java | 12 ++-- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/thealgorithms/ciphers/ECC.java b/src/main/java/com/thealgorithms/ciphers/ECC.java index 3d9ac1d0360d..c8f20946336e 100644 --- a/src/main/java/com/thealgorithms/ciphers/ECC.java +++ b/src/main/java/com/thealgorithms/ciphers/ECC.java @@ -17,17 +17,21 @@ */ public class ECC { - private BigInteger privateKey; // Private key used for decryption - private ECPoint publicKey; // Public key used for encryption - private EllipticCurve curve; // Elliptic curve used in cryptography - private ECPoint basePoint; // Base point G on the elliptic curve + private BigInteger privateKey; // Private key used for decryption + private ECPoint publicKey; // Public key used for encryption + private EllipticCurve curve; // Elliptic curve used in cryptography + private ECPoint basePoint; // Base point G on the elliptic curve + + public ECC(int bits) { + generateKeys(bits); // Generates public-private key pair + } public EllipticCurve getCurve() { return curve; // Returns the elliptic curve } - public ECC(int bits) { - generateKeys(bits); // Generates public-private key pair + public void setCurve(EllipticCurve curve) { + this.curve = curve; } // Getter and Setter for private key @@ -39,10 +43,6 @@ public void setPrivateKey(BigInteger privateKey) { this.privateKey = privateKey; } - public void setCurve(EllipticCurve curve) { - this.curve = curve; - } - /** * Encrypts the message using the public key. * The message is transformed into an ECPoint and encrypted with elliptic curve operations. @@ -50,18 +50,18 @@ public void setCurve(EllipticCurve curve) { * @param message The plain message to be encrypted * @return The encrypted message as an array of ECPoints (R, S) */ - public synchronized ECPoint[] encrypt(String message) { + public ECPoint[] encrypt(String message) { BigInteger m = new BigInteger(message.getBytes()); // Convert message to BigInteger SecureRandom r = new SecureRandom(); // Generate random value for k BigInteger k = new BigInteger(curve.getFieldSize(), r); // Generate random scalar k - // Calculate point R = k * G, where G is the base point - ECPoint R = basePoint.multiply(k, curve.getP(), curve.getA()); + // Calculate point r = k * G, where G is the base point + ECPoint rPoint = basePoint.multiply(k, curve.getP(), curve.getA()); - // Calculate point S = k * publicKey + encodedMessage - ECPoint S = publicKey.multiply(k, curve.getP(), curve.getA()).add(curve.encodeMessage(m), curve.getP(), curve.getA()); + // Calculate point s = k * publicKey + encodedMessage + ECPoint sPoint = publicKey.multiply(k, curve.getP(), curve.getA()).add(curve.encodeMessage(m), curve.getP(), curve.getA()); - return new ECPoint[] { R, S }; // Return encrypted message as two ECPoints + return new ECPoint[] {rPoint, sPoint}; // Return encrypted message as two ECPoints } /** @@ -71,12 +71,12 @@ public synchronized ECPoint[] encrypt(String message) { * @param encryptedMessage The encrypted message as an array of ECPoints (R, S) * @return The decrypted plain message as a String */ - public synchronized String decrypt(ECPoint[] encryptedMessage) { - ECPoint R = encryptedMessage[0]; // First part of ciphertext - ECPoint S = encryptedMessage[1]; // Second part of ciphertext + public String decrypt(ECPoint[] encryptedMessage) { + ECPoint rPoint = encryptedMessage[0]; // First part of ciphertext + ECPoint sPoint = encryptedMessage[1]; // Second part of ciphertext - // Perform decryption: S - R * privateKey - ECPoint decodedMessage = S.subtract(R.multiply(privateKey, curve.getP(), curve.getA()), curve.getP(), curve.getA()); + // Perform decryption: s - r * privateKey + ECPoint decodedMessage = sPoint.subtract(rPoint.multiply(privateKey, curve.getP(), curve.getA()), curve.getP(), curve.getA()); BigInteger m = curve.decodeMessage(decodedMessage); // Decode the message from ECPoint @@ -88,7 +88,7 @@ public synchronized String decrypt(ECPoint[] encryptedMessage) { * * @param bits The size (in bits) of the keys to generate */ - public final synchronized void generateKeys(int bits) { + public final void generateKeys(int bits) { SecureRandom r = new SecureRandom(); curve = new EllipticCurve(bits); // Initialize a new elliptic curve basePoint = curve.getBasePoint(); // Set the base point G @@ -104,10 +104,10 @@ public final synchronized void generateKeys(int bits) { * Class representing an elliptic curve with the form y^2 = x^3 + ax + b. */ public static class EllipticCurve { - private final BigInteger a; // Coefficient a in the curve equation - private final BigInteger b; // Coefficient b in the curve equation - private final BigInteger p; // Prime number p, defining the finite field - private final ECPoint basePoint; // Base point G on the curve + private final BigInteger a; // Coefficient a in the curve equation + private final BigInteger b; // Coefficient b in the curve equation + private final BigInteger p; // Prime number p, defining the finite field + private final ECPoint basePoint; // Base point G on the curve // Constructor with explicit parameters for a, b, p, and base point public EllipticCurve(BigInteger a, BigInteger b, BigInteger p, ECPoint basePoint) { @@ -121,8 +121,8 @@ public EllipticCurve(BigInteger a, BigInteger b, BigInteger p, ECPoint basePoint public EllipticCurve(int bits) { SecureRandom r = new SecureRandom(); this.p = BigInteger.probablePrime(bits, r); // Random prime p - this.a = new BigInteger(bits, r); // Random coefficient a - this.b = new BigInteger(bits, r); // Random coefficient b + this.a = new BigInteger(bits, r); // Random coefficient a + this.b = new BigInteger(bits, r); // Random coefficient b this.basePoint = new ECPoint(BigInteger.valueOf(4), BigInteger.valueOf(8)); // Fixed base point G } @@ -160,8 +160,8 @@ public BigInteger decodeMessage(ECPoint point) { * Class representing a point on the elliptic curve. */ public static class ECPoint { - private final BigInteger x; // X-coordinate of the point - private final BigInteger y; // Y-coordinate of the point + private final BigInteger x; // X-coordinate of the point + private final BigInteger y; // Y-coordinate of the point public ECPoint(BigInteger x, BigInteger y) { this.x = x; @@ -195,12 +195,10 @@ public ECPoint add(ECPoint other, BigInteger p, BigInteger a) { BigInteger lambda; if (this.equals(other)) { // Special case: point doubling - lambda = (this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a)) - .multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p); + lambda = (this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a)).multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p); } else { // General case: adding two different points - lambda = (other.y.subtract(this.y)) - .multiply(other.x.subtract(this.x).modInverse(p)).mod(p); + lambda = (other.y.subtract(this.y)).multiply(other.x.subtract(this.x).modInverse(p)).mod(p); } BigInteger xr = lambda.pow(2).subtract(this.x).subtract(other.x).mod(p); @@ -226,13 +224,13 @@ public ECPoint multiply(BigInteger k, BigInteger p, BigInteger a) { while (k.signum() > 0) { if (k.testBit(0)) { - result = result.add(addend, p, a); // Add when k's bit is 1 + result = result.add(addend, p, a); // Add the current point } addend = addend.add(addend, p, a); // Double the point - k = k.shiftRight(1); // Shift k to the right by 1 bit + k = k.shiftRight(1); // Divide k by 2 } - return result; // Return the resulting point + return result; } } } diff --git a/src/test/java/com/thealgorithms/ciphers/ECCTest.java b/src/test/java/com/thealgorithms/ciphers/ECCTest.java index 413830ace3a2..86e296f3cb9c 100644 --- a/src/test/java/com/thealgorithms/ciphers/ECCTest.java +++ b/src/test/java/com/thealgorithms/ciphers/ECCTest.java @@ -3,8 +3,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -import org.junit.jupiter.api.Test; import java.math.BigInteger; +import org.junit.jupiter.api.Test; /** * ECCTest - Unit tests for the ECC (Elliptic Curve Cryptography) implementation. @@ -64,15 +64,13 @@ void testDecryptWithKnownValues() { ECC.EllipticCurve curve = new ECC.EllipticCurve(a, b, p, basePoint); // 4. Define the known ciphertext containing two ECPoints (R, S) - ECC.ECPoint R = new ECC.ECPoint(new BigInteger("103077584019003058745849614420912636617007257617156724481937620119667345237687"), - new BigInteger("68193862907937248121971710522760893811582068323088661566426323952783362061817")); - ECC.ECPoint S = new ECC.ECPoint(new BigInteger("31932232426664380635434632300383525435115368414929679432313910646436992147798"), - new BigInteger("77299754382292904069123203569944908076819220797512755280123348910207308129766")); - ECC.ECPoint[] cipherText = new ECC.ECPoint[] { R, S }; + ECC.ECPoint R = new ECC.ECPoint(new BigInteger("103077584019003058745849614420912636617007257617156724481937620119667345237687"), new BigInteger("68193862907937248121971710522760893811582068323088661566426323952783362061817")); + ECC.ECPoint S = new ECC.ECPoint(new BigInteger("31932232426664380635434632300383525435115368414929679432313910646436992147798"), new BigInteger("77299754382292904069123203569944908076819220797512755280123348910207308129766")); + ECC.ECPoint[] cipherText = new ECC.ECPoint[] {R, S}; // 5. Create an ECC instance and set the private key and curve parameters ecc.setPrivateKey(knownPrivateKey); // Use setter method to set the private key - ecc.setCurve(curve); // Use setter method to set the elliptic curve + ecc.setCurve(curve);// Use setter method to set the elliptic curve // 6. Decrypt the known ciphertext String decryptedMessage = ecc.decrypt(cipherText); From a6acec8b4456ad9b75be2ff8ada941137e345be6 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Thu, 10 Oct 2024 20:52:21 +0800 Subject: [PATCH 09/16] Update ECCTest.java --- src/test/java/com/thealgorithms/ciphers/ECCTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/thealgorithms/ciphers/ECCTest.java b/src/test/java/com/thealgorithms/ciphers/ECCTest.java index 86e296f3cb9c..701f801af1c8 100644 --- a/src/test/java/com/thealgorithms/ciphers/ECCTest.java +++ b/src/test/java/com/thealgorithms/ciphers/ECCTest.java @@ -64,13 +64,13 @@ void testDecryptWithKnownValues() { ECC.EllipticCurve curve = new ECC.EllipticCurve(a, b, p, basePoint); // 4. Define the known ciphertext containing two ECPoints (R, S) - ECC.ECPoint R = new ECC.ECPoint(new BigInteger("103077584019003058745849614420912636617007257617156724481937620119667345237687"), new BigInteger("68193862907937248121971710522760893811582068323088661566426323952783362061817")); - ECC.ECPoint S = new ECC.ECPoint(new BigInteger("31932232426664380635434632300383525435115368414929679432313910646436992147798"), new BigInteger("77299754382292904069123203569944908076819220797512755280123348910207308129766")); - ECC.ECPoint[] cipherText = new ECC.ECPoint[] {R, S}; + ECC.ECPoint rPoint = new ECC.ECPoint(new BigInteger("103077584019003058745849614420912636617007257617156724481937620119667345237687"), new BigInteger("68193862907937248121971710522760893811582068323088661566426323952783362061817")); + ECC.ECPoint sPoint = new ECC.ECPoint(new BigInteger("31932232426664380635434632300383525435115368414929679432313910646436992147798"), new BigInteger("77299754382292904069123203569944908076819220797512755280123348910207308129766")); + ECC.ECPoint[] cipherText = new ECC.ECPoint[] {rPoint, sPoint}; // 5. Create an ECC instance and set the private key and curve parameters ecc.setPrivateKey(knownPrivateKey); // Use setter method to set the private key - ecc.setCurve(curve);// Use setter method to set the elliptic curve + ecc.setCurve(curve); // Use setter method to set the elliptic curve // 6. Decrypt the known ciphertext String decryptedMessage = ecc.decrypt(cipherText); From 1b384d6a7d794b457b6d201cd6483247fac0adde Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Thu, 10 Oct 2024 20:59:12 +0800 Subject: [PATCH 10/16] Update ECC.java --- src/main/java/com/thealgorithms/ciphers/ECC.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/ciphers/ECC.java b/src/main/java/com/thealgorithms/ciphers/ECC.java index c8f20946336e..7b1e37f0e1e1 100644 --- a/src/main/java/com/thealgorithms/ciphers/ECC.java +++ b/src/main/java/com/thealgorithms/ciphers/ECC.java @@ -195,10 +195,10 @@ public ECPoint add(ECPoint other, BigInteger p, BigInteger a) { BigInteger lambda; if (this.equals(other)) { // Special case: point doubling - lambda = (this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a)).multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p); + lambda = this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a).multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p); } else { // General case: adding two different points - lambda = (other.y.subtract(this.y)).multiply(other.x.subtract(this.x).modInverse(p)).mod(p); + lambda = other.y.subtract(this.y).multiply(other.x.subtract(this.x).modInverse(p)).mod(p); } BigInteger xr = lambda.pow(2).subtract(this.x).subtract(other.x).mod(p); From b080a367256e20ef48a0e59a515b3e4c4019dad2 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Sun, 13 Oct 2024 02:29:44 +0800 Subject: [PATCH 11/16] Add Disk Scheduling Algorithm --- .../CircularLookScheduling.java | 89 +++++++++++++++++ .../CircularScanScheduling.java | 83 ++++++++++++++++ .../diskscheduling/LookScheduling.java | 95 +++++++++++++++++++ .../diskscheduling/SSFScheduling.java | 56 +++++++++++ .../diskscheduling/ScanScheduling.java | 82 ++++++++++++++++ .../CircularLookSchedulingTest.java | 55 +++++++++++ .../CircularScanSchedulingTest.java | 49 ++++++++++ .../diskscheduling/LookSchedulingTest.java | 68 +++++++++++++ .../diskscheduling/SSFSchedulingTest.java | 56 +++++++++++ .../diskscheduling/ScanSchedulingTest.java | 56 +++++++++++ 10 files changed, 689 insertions(+) create mode 100644 src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java create mode 100644 src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java create mode 100644 src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java create mode 100644 src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java create mode 100644 src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java create mode 100644 src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java create mode 100644 src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java create mode 100644 src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java create mode 100644 src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java create mode 100644 src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java new file mode 100644 index 000000000000..61d5cf01d048 --- /dev/null +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java @@ -0,0 +1,89 @@ +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 execute(List requests) { + List result = new ArrayList<>(); + + // Filter and sort valid requests in both directions + List upRequests = new ArrayList<>(); + List 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 + for (int request : upRequests) { + result.add(request); + } + + // Jump to the lowest request and process all requests in the downward direction + if (!downRequests.isEmpty()) { + result.addAll(downRequests); + } + } else { + // Process all requests in the downward direction (in reverse order) + for (int i = downRequests.size() - 1; i >= 0; i--) { + result.add(downRequests.get(i)); + } + + // Jump to the highest request and process all requests in the upward direction (in reverse order) + if (!upRequests.isEmpty()) { + for (int i = upRequests.size() - 1; i >= 0; i--) { + result.add(upRequests.get(i)); + } + } + + } + + // 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; + } +} \ No newline at end of file diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java new file mode 100644 index 000000000000..b5408daf4a1f --- /dev/null +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java @@ -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 execute(List requests) { + if (requests.isEmpty()) { + return new ArrayList<>(); // Return empty list if there are no requests + } + + List sortedRequests = new ArrayList<>(requests); + Collections.sort(sortedRequests); + + List result = new ArrayList<>(); + + if (movingUp) { + // Moving up: process requests >= current position + for (int request : sortedRequests) { + if (request >= currentPosition) { + 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; + } +} diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java new file mode 100644 index 000000000000..ad76196fe1b6 --- /dev/null +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java @@ -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 execute(List requests) { + List result = new ArrayList<>(); + List lower = new ArrayList<>(); + List upper = new ArrayList<>(); + + // Split requests into two lists based on their position relative to current position + for (int request : requests) { + 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; + } +} diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java new file mode 100644 index 000000000000..30838821a2de --- /dev/null +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java @@ -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 execute(List requests) { + List result = new ArrayList<>(requests); + List 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 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; + } +} diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java new file mode 100644 index 000000000000..2c4fa7844a12 --- /dev/null +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java @@ -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 execute(List requests) { + // If the request list is empty, return an empty result + if (requests.isEmpty()) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + List left = new ArrayList<>(); + List 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; + } +} diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java new file mode 100644 index 000000000000..b87224378803 --- /dev/null +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java @@ -0,0 +1,55 @@ +package com.thealgorithms.scheduling.diskscheduling; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CircularLookSchedulingTest { + + @Test + public void testCircularLookScheduling_MovingUp() { + CircularLookScheduling scheduling = new CircularLookScheduling(50, true, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expected = Arrays.asList(55, 58, 90, 150, 160, 18, 39); + + List result = scheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testCircularLookScheduling_MovingDown() { + CircularLookScheduling scheduling = new CircularLookScheduling(50, false, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expected = Arrays.asList(39, 18, 160, 150, 90, 58, 55); + + List result = scheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testCircularLookScheduling_EmptyRequests() { + CircularLookScheduling scheduling = new CircularLookScheduling(50, true, 200); + List requests = Arrays.asList(); + List expected = Arrays.asList(); + + List result = scheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testCircularLookScheduling_PrintStatus() { + CircularLookScheduling scheduling = new CircularLookScheduling(50, true, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List result = scheduling.execute(requests); + + // Print the final status + System.out.println("Final CircularLookScheduling Position: " + scheduling.getCurrentPosition()); + System.out.println("CircularLookScheduling Moving Up: " + scheduling.isMovingUp()); + + // Print the order of request processing + System.out.println("Request Order: " + result); + } +} diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java new file mode 100644 index 000000000000..5208e4167033 --- /dev/null +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java @@ -0,0 +1,49 @@ +package com.thealgorithms.scheduling.diskscheduling; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CircularScanSchedulingTest { + + @Test + public void testCircularScanScheduling_MovingUp() { + CircularScanScheduling circularScan = new CircularScanScheduling(50, true, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expectedOrder = Arrays.asList(55, 58, 90, 150, 160, 18, 39); + + List result = circularScan.execute(requests); + assertEquals(expectedOrder, result); + + System.out.println("Final CircularScan Position: " + circularScan.getCurrentPosition()); + System.out.println("CircularScan Moving Up: " + circularScan.isMovingUp()); + System.out.println("Request Order: " + result); + } + + @Test + public void testCircularScanScheduling_MovingDown() { + CircularScanScheduling circularScan = new CircularScanScheduling(50, false, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expectedOrder = Arrays.asList(39, 18, 160, 150, 90, 58, 55); + + List result = circularScan.execute(requests); + assertEquals(expectedOrder, result); + + System.out.println("Final CircularScan Position: " + circularScan.getCurrentPosition()); + System.out.println("CircularScan Moving Down: " + circularScan.isMovingUp()); + System.out.println("Request Order: " + result); + } + + @Test + public void testCircularScanScheduling_EmptyRequests() { + CircularScanScheduling circularScan = new CircularScanScheduling(50, true, 200); + List requests = Arrays.asList(); + List expectedOrder = Arrays.asList(); + + List result = circularScan.execute(requests); + assertEquals(expectedOrder, result); + } +} diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java new file mode 100644 index 000000000000..397a7b3c93aa --- /dev/null +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java @@ -0,0 +1,68 @@ +package com.thealgorithms.scheduling.diskscheduling; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class LookSchedulingTest { + + @Test + public void testLookScheduling_MovingUp() { + LookScheduling lookScheduling = new LookScheduling(50, true, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expected = Arrays.asList(55, 58, 90, 150, 160, 39, 18); + + List result = lookScheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testLookScheduling_MovingDown() { + LookScheduling lookScheduling = new LookScheduling(50, false, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expected = Arrays.asList(39, 18, 55, 58, 90, 150, 160); + + List result = lookScheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testLookScheduling_EmptyRequests() { + LookScheduling lookScheduling = new LookScheduling(50, true, 200); + List requests = Arrays.asList(); + List expected = Arrays.asList(); + + List result = lookScheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testLookScheduling_CurrentPosition() { + LookScheduling lookScheduling = new LookScheduling(50, true, 200); + + // Testing current position remains unchanged after scheduling. + assertEquals(50, lookScheduling.getCurrentPosition()); + } + + @Test + public void testLookScheduling_PrintStatus() { + LookScheduling lookScheduling = new LookScheduling(50, true, 200); + + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + + List result = lookScheduling.execute(requests); + + List expectedOrder = Arrays.asList(55, 58, 90, 150, 160, 39, 18); + assertEquals(expectedOrder, result); + + System.out.println("Final LookScheduling Position: " + lookScheduling.getCurrentPosition()); + System.out.println("LookScheduling Moving Up: " + lookScheduling.isMovingUp()); + + System.out.println("Farthest Position Reached: " + lookScheduling.getFarthestPosition()); + + System.out.println("Request Order: " + result); + } +} diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java new file mode 100644 index 000000000000..b70217fa30dd --- /dev/null +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java @@ -0,0 +1,56 @@ +package com.thealgorithms.scheduling.diskscheduling; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SSFSchedulingTest { + + private SSFScheduling scheduler; + + @BeforeEach + public void setUp() { + scheduler = new SSFScheduling(50); + } + + @Test + public void testExecuteWithEmptyList() { + List requests = new ArrayList<>(); + List result = scheduler.execute(requests); + assertTrue(result.isEmpty(), "Result should be empty for an empty request list."); + } + + @Test + public void testExecuteWithSingleRequest() { + List requests = new ArrayList<>(List.of(100)); + List result = scheduler.execute(requests); + assertEquals(List.of(100), result, "The only request should be served first."); + } + + @Test + public void testExecuteWithMultipleRequests() { + List requests = new ArrayList<>(List.of(10, 90, 60, 40, 30, 70)); + List result = scheduler.execute(requests); + assertEquals(List.of(60, 70, 90, 40, 30, 10), result, "Requests should be served in the shortest seek first order."); + } + + @Test + public void testExecuteWithSameDistanceRequests() { + List requests = new ArrayList<>(List.of(45, 55)); + List result = scheduler.execute(requests); + assertEquals(List.of(45, 55), result, "When distances are equal, requests should be served in the order they appear in the list."); + } + + @Test + public void testGetCurrentPositionAfterExecution() { + List requests = new ArrayList<>(List.of(10, 90, 60, 40, 30, 70)); + scheduler.execute(requests); + int currentPosition = scheduler.getCurrentPosition(); + assertEquals(10, currentPosition, "Current position should be the last request after execution."); + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java new file mode 100644 index 000000000000..656835df151c --- /dev/null +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java @@ -0,0 +1,56 @@ +package com.thealgorithms.scheduling.diskscheduling; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ScanSchedulingTest { + + @Test + public void testScanScheduling_MovingUp() { + ScanScheduling scanScheduling = new ScanScheduling(50, true, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expected = Arrays.asList(55, 58, 90, 150, 160, 199, 39, 18); + + List result = scanScheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testScanScheduling_MovingDown() { + ScanScheduling scanScheduling = new ScanScheduling(50, false, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + List expected = Arrays.asList(39, 18, 0, 55, 58, 90, 150, 160); + + List result = scanScheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testScanScheduling_EmptyRequests() { + ScanScheduling scanScheduling = new ScanScheduling(50, true, 200); + List requests = Arrays.asList(); + List expected = Arrays.asList(); + + List result = scanScheduling.execute(requests); + assertEquals(expected, result); + } + + @Test + public void testScanScheduling() { + ScanScheduling scanScheduling = new ScanScheduling(50, true, 200); + List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); + + List result = scanScheduling.execute(requests); + List expectedOrder = Arrays.asList(55, 58, 90, 150, 160, 199, 39, 18); + assertEquals(expectedOrder, result); + + System.out.println("Final Head Position: " + scanScheduling.getHeadPosition()); + System.out.println("Head Moving Up: " + scanScheduling.isMovingUp()); + System.out.println("Request Order: " + result); + } +} + From c73217276b9d688a2a64867136719ff722688024 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Sun, 13 Oct 2024 11:36:57 +0800 Subject: [PATCH 12/16] Update code --- .../diskscheduling/CircularLookScheduling.java | 2 +- .../diskscheduling/CircularLookSchedulingTest.java | 12 ++++++------ .../diskscheduling/CircularScanSchedulingTest.java | 10 +++++----- .../diskscheduling/LookSchedulingTest.java | 14 +++++++------- .../diskscheduling/SSFSchedulingTest.java | 10 +++++----- .../diskscheduling/ScanSchedulingTest.java | 10 +++++----- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java index 61d5cf01d048..092509816c4d 100644 --- a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java @@ -86,4 +86,4 @@ public int getCurrentPosition() { public boolean isMovingUp() { return movingUp; } -} \ No newline at end of file +} diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java index b87224378803..f75873d0ba0f 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java @@ -1,16 +1,16 @@ package com.thealgorithms.scheduling.diskscheduling; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class CircularLookSchedulingTest { @Test - public void testCircularLookScheduling_MovingUp() { + public void testCircularLookSchedulingMovingUp() { CircularLookScheduling scheduling = new CircularLookScheduling(50, true, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expected = Arrays.asList(55, 58, 90, 150, 160, 18, 39); @@ -20,7 +20,7 @@ public void testCircularLookScheduling_MovingUp() { } @Test - public void testCircularLookScheduling_MovingDown() { + public void testCircularLookSchedulingMovingDown() { CircularLookScheduling scheduling = new CircularLookScheduling(50, false, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expected = Arrays.asList(39, 18, 160, 150, 90, 58, 55); @@ -30,7 +30,7 @@ public void testCircularLookScheduling_MovingDown() { } @Test - public void testCircularLookScheduling_EmptyRequests() { + public void testCircularLookSchedulingEmptyRequests() { CircularLookScheduling scheduling = new CircularLookScheduling(50, true, 200); List requests = Arrays.asList(); List expected = Arrays.asList(); @@ -40,7 +40,7 @@ public void testCircularLookScheduling_EmptyRequests() { } @Test - public void testCircularLookScheduling_PrintStatus() { + public void testCircularLookSchedulingPrintStatus() { CircularLookScheduling scheduling = new CircularLookScheduling(50, true, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List result = scheduling.execute(requests); diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java index 5208e4167033..2d2af5aa155c 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java @@ -1,16 +1,16 @@ package com.thealgorithms.scheduling.diskscheduling; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class CircularScanSchedulingTest { @Test - public void testCircularScanScheduling_MovingUp() { + public void testCircularScanSchedulingMovingUp() { CircularScanScheduling circularScan = new CircularScanScheduling(50, true, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expectedOrder = Arrays.asList(55, 58, 90, 150, 160, 18, 39); @@ -24,7 +24,7 @@ public void testCircularScanScheduling_MovingUp() { } @Test - public void testCircularScanScheduling_MovingDown() { + public void testCircularScanSchedulingMovingDown() { CircularScanScheduling circularScan = new CircularScanScheduling(50, false, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expectedOrder = Arrays.asList(39, 18, 160, 150, 90, 58, 55); @@ -38,7 +38,7 @@ public void testCircularScanScheduling_MovingDown() { } @Test - public void testCircularScanScheduling_EmptyRequests() { + public void testCircularScanSchedulingEmptyRequests() { CircularScanScheduling circularScan = new CircularScanScheduling(50, true, 200); List requests = Arrays.asList(); List expectedOrder = Arrays.asList(); diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java index 397a7b3c93aa..783b57999cd9 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java @@ -1,16 +1,16 @@ package com.thealgorithms.scheduling.diskscheduling; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class LookSchedulingTest { @Test - public void testLookScheduling_MovingUp() { + public void testLookSchedulingMovingUp() { LookScheduling lookScheduling = new LookScheduling(50, true, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expected = Arrays.asList(55, 58, 90, 150, 160, 39, 18); @@ -20,7 +20,7 @@ public void testLookScheduling_MovingUp() { } @Test - public void testLookScheduling_MovingDown() { + public void testLookSchedulingMovingDown() { LookScheduling lookScheduling = new LookScheduling(50, false, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expected = Arrays.asList(39, 18, 55, 58, 90, 150, 160); @@ -30,7 +30,7 @@ public void testLookScheduling_MovingDown() { } @Test - public void testLookScheduling_EmptyRequests() { + public void testLookSchedulingEmptyRequests() { LookScheduling lookScheduling = new LookScheduling(50, true, 200); List requests = Arrays.asList(); List expected = Arrays.asList(); @@ -40,7 +40,7 @@ public void testLookScheduling_EmptyRequests() { } @Test - public void testLookScheduling_CurrentPosition() { + public void testLookSchedulingCurrentPosition() { LookScheduling lookScheduling = new LookScheduling(50, true, 200); // Testing current position remains unchanged after scheduling. @@ -48,7 +48,7 @@ public void testLookScheduling_CurrentPosition() { } @Test - public void testLookScheduling_PrintStatus() { + public void testLookSchedulingPrintStatus() { LookScheduling lookScheduling = new LookScheduling(50, true, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java index b70217fa30dd..b0d352a62a88 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java @@ -1,13 +1,13 @@ package com.thealgorithms.scheduling.diskscheduling; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class SSFSchedulingTest { @@ -53,4 +53,4 @@ public void testGetCurrentPositionAfterExecution() { int currentPosition = scheduler.getCurrentPosition(); assertEquals(10, currentPosition, "Current position should be the last request after execution."); } -} \ No newline at end of file + } diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java index 656835df151c..da1ec2ff74a3 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java @@ -1,16 +1,16 @@ package com.thealgorithms.scheduling.diskscheduling; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class ScanSchedulingTest { @Test - public void testScanScheduling_MovingUp() { + public void testScanSchedulingMovingUp() { ScanScheduling scanScheduling = new ScanScheduling(50, true, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expected = Arrays.asList(55, 58, 90, 150, 160, 199, 39, 18); @@ -20,7 +20,7 @@ public void testScanScheduling_MovingUp() { } @Test - public void testScanScheduling_MovingDown() { + public void testScanSchedulingMovingDown() { ScanScheduling scanScheduling = new ScanScheduling(50, false, 200); List requests = Arrays.asList(55, 58, 39, 18, 90, 160, 150); List expected = Arrays.asList(39, 18, 0, 55, 58, 90, 150, 160); @@ -30,7 +30,7 @@ public void testScanScheduling_MovingDown() { } @Test - public void testScanScheduling_EmptyRequests() { + public void testScanSchedulingEmptyRequests() { ScanScheduling scanScheduling = new ScanScheduling(50, true, 200); List requests = Arrays.asList(); List expected = Arrays.asList(); From 2fe1a2a157a08658e01132b003c5885f88a68e2e Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Sun, 13 Oct 2024 11:52:42 +0800 Subject: [PATCH 13/16] Update code --- .../CircularLookScheduling.java | 21 ++++++------------- .../CircularLookSchedulingTest.java | 1 - .../CircularScanSchedulingTest.java | 1 - .../diskscheduling/LookSchedulingTest.java | 1 - .../diskscheduling/SSFSchedulingTest.java | 2 +- .../diskscheduling/ScanSchedulingTest.java | 2 -- 6 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java index 092509816c4d..2230ecaf35a6 100644 --- a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java @@ -48,27 +48,18 @@ public List execute(List requests) { if (movingUp) { // Process all requests in the upward direction - for (int request : upRequests) { - result.add(request); - } + result.addAll(upRequests); // Jump to the lowest request and process all requests in the downward direction - if (!downRequests.isEmpty()) { - result.addAll(downRequests); - } + result.addAll(downRequests); } else { // Process all requests in the downward direction (in reverse order) - for (int i = downRequests.size() - 1; i >= 0; i--) { - result.add(downRequests.get(i)); - } + Collections.reverse(downRequests); + result.addAll(downRequests); // Jump to the highest request and process all requests in the upward direction (in reverse order) - if (!upRequests.isEmpty()) { - for (int i = upRequests.size() - 1; i >= 0; i--) { - result.add(upRequests.get(i)); - } - } - + Collections.reverse(upRequests); + result.addAll(upRequests); } // Update current position to the last processed request diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java index f75873d0ba0f..ae04e725cde5 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; - import org.junit.jupiter.api.Test; public class CircularLookSchedulingTest { diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java index 2d2af5aa155c..06bd53c0b392 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; - import org.junit.jupiter.api.Test; public class CircularScanSchedulingTest { diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java index 783b57999cd9..91acc4837243 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; - import org.junit.jupiter.api.Test; public class LookSchedulingTest { diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java index b0d352a62a88..2a11d482a20d 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.List; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,4 +52,5 @@ public void testGetCurrentPositionAfterExecution() { int currentPosition = scheduler.getCurrentPosition(); assertEquals(10, currentPosition, "Current position should be the last request after execution."); } + } diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java index da1ec2ff74a3..1dbcd4893cb9 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; - import org.junit.jupiter.api.Test; public class ScanSchedulingTest { @@ -53,4 +52,3 @@ public void testScanScheduling() { System.out.println("Request Order: " + result); } } - From 069fdace9299edf59756703cfea78faa4703077c Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Sun, 13 Oct 2024 12:52:12 +0800 Subject: [PATCH 14/16] Update code --- .../diskscheduling/CircularScanScheduling.java | 2 +- .../scheduling/diskscheduling/LookScheduling.java | 12 +++++++----- .../scheduling/diskscheduling/SSFSchedulingTest.java | 3 +-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java index b5408daf4a1f..a31c3d99a89e 100644 --- a/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java @@ -37,7 +37,7 @@ public List execute(List requests) { if (movingUp) { // Moving up: process requests >= current position for (int request : sortedRequests) { - if (request >= currentPosition) { + if (request >= currentPosition && request < diskSize) { result.add(request); } } diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java index ad76196fe1b6..a1977607507a 100644 --- a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java @@ -11,12 +11,12 @@ * 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; @@ -36,10 +36,12 @@ public List execute(List requests) { // Split requests into two lists based on their position relative to current position for (int request : requests) { - if (request < currentPosition) { - lower.add(request); - } else { - upper.add(request); + if (request >= 0 && request < maxTrack) { + if (request < currentPosition) { + lower.add(request); + } else { + upper.add(request); + } } } diff --git a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java index 2a11d482a20d..0239b0117f1b 100644 --- a/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java @@ -52,5 +52,4 @@ public void testGetCurrentPositionAfterExecution() { int currentPosition = scheduler.getCurrentPosition(); assertEquals(10, currentPosition, "Current position should be the last request after execution."); } - - } +} From cd329245689a54068498a5fb96296b870c3d9be6 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Sun, 13 Oct 2024 12:56:43 +0800 Subject: [PATCH 15/16] Update LookScheduling.java --- .../scheduling/diskscheduling/LookScheduling.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java index a1977607507a..9fc5492f4069 100644 --- a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java @@ -15,8 +15,7 @@ public class LookScheduling { private final int currentPosition; private boolean movingUp; private int farthestPosition; - - + public LookScheduling(int startPosition, boolean initialDirection, int maxTrack) { this.currentPosition = startPosition; this.movingUp = initialDirection; From a7345569a5c9de17b696f76e05038cf08073162b Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Sun, 13 Oct 2024 12:58:57 +0800 Subject: [PATCH 16/16] Update LookScheduling.java --- .../thealgorithms/scheduling/diskscheduling/LookScheduling.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java index 9fc5492f4069..beba69b05eca 100644 --- a/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java @@ -15,7 +15,6 @@ public class LookScheduling { private final int currentPosition; private boolean movingUp; private int farthestPosition; - public LookScheduling(int startPosition, boolean initialDirection, int maxTrack) { this.currentPosition = startPosition; this.movingUp = initialDirection;