diff --git a/src/main/java/com/thealgorithms/ciphers/HillCipher.java b/src/main/java/com/thealgorithms/ciphers/HillCipher.java index c0f6aef12..5566b07e6 100644 --- a/src/main/java/com/thealgorithms/ciphers/HillCipher.java +++ b/src/main/java/com/thealgorithms/ciphers/HillCipher.java @@ -12,7 +12,7 @@ import java.util.Scanner; */ public class HillCipher { - static Scanner in = new Scanner(System.in); + static Scanner userInput = new Scanner(System.in); /* Following function encrypts the message */ @@ -20,26 +20,23 @@ public class HillCipher { message = message.toUpperCase(); // Get key matrix System.out.println("Enter key matrix size"); - int n = in.nextInt(); + int matrixSize = userInput.nextInt(); System.out.println("Enter Key/encryptionKey matrix "); - int keyMatrix[][] = new int[n][n]; - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - keyMatrix[i][j] = in.nextInt(); + int keyMatrix[][] = new int[matrixSize][matrixSize]; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + keyMatrix[i][j] = userInput.nextInt(); } } //check if det = 0 - if (determinant(keyMatrix, n) % 26 == 0) { - System.out.println("Invalid key, as determinant = 0. Program Terminated"); - return; - } + validateDeterminant(keyMatrix,matrixSize); - int[][] messageVector = new int[n][1]; + int[][] messageVector = new int[matrixSize][1]; String CipherText = ""; - int cipherMatrix[][] = new int[n][1]; + int cipherMatrix[][] = new int[matrixSize][1]; int j = 0; while (j < message.length()) { - for (int i = 0; i < n; i++) { + for (int i = 0; i < matrixSize; i++) { if (j >= message.length()) { messageVector[i][0] = 23; } else { @@ -49,16 +46,16 @@ public class HillCipher { j++; } int x, i; - for (i = 0; i < n; i++) { + for (i = 0; i < matrixSize; i++) { cipherMatrix[i][0] = 0; - for (x = 0; x < n; x++) { + for (x = 0; x < matrixSize; x++) { cipherMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0]; } System.out.println(cipherMatrix[i][0]); cipherMatrix[i][0] = cipherMatrix[i][0] % 26; } - for (i = 0; i < n; i++) { + for (i = 0; i < matrixSize; i++) { CipherText += (char) (cipherMatrix[i][0] + 65); } } @@ -70,19 +67,17 @@ public class HillCipher { message = message.toUpperCase(); // Get key matrix System.out.println("Enter key matrix size"); - int n = in.nextInt(); + int n = userInput.nextInt(); System.out.println("Enter inverseKey/decryptionKey matrix "); int keyMatrix[][] = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - keyMatrix[i][j] = in.nextInt(); + keyMatrix[i][j] = userInput.nextInt(); } } //check if det = 0 - if (determinant(keyMatrix, n) % 26 == 0) { - System.out.println("Invalid key, as determinant = 0. Program Terminated"); - return; - } + validateDeterminant(keyMatrix,n); + //solving for the required plaintext message int[][] messageVector = new int[n][1]; String PlainText = ""; @@ -145,12 +140,12 @@ public class HillCipher { } // Function to implement Hill Cipher - static void hillcipher(String message) { + static void hillCipher(String message) { message.toUpperCase(); System.out.println("What do you want to process from the message?"); System.out.println("Press 1: To Encrypt"); System.out.println("Press 2: To Decrypt"); - short sc = in.nextShort(); + short sc = userInput.nextShort(); if (sc == 1) { encrypt(message); } else if (sc == 2) { @@ -160,11 +155,18 @@ public class HillCipher { } } + static void validateDeterminant(int[][] keyMatrix, int n){ + if (determinant(keyMatrix, n) % 26 == 0) { + System.out.println("Invalid key, as determinant = 0. Program Terminated"); + return; + } + } + // Driver code public static void main(String[] args) { // Get the message to be encrypted System.out.println("Enter message"); - String message = in.nextLine(); - hillcipher(message); + String message = userInput.nextLine(); + hillCipher(message); } -} +} \ No newline at end of file diff --git a/src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java index 095904fdf..36b026a16 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java @@ -18,11 +18,15 @@ public class DoublyLinkedList { /** * Head refers to the front of the list */ - private Link head; + protected Link head; /** * Tail refers to the back of the list */ private Link tail; + /** + * Link Operations to perform operations on nodes of the list + */ + private LinkOperations linkOperations; /** * Size refers to the number of elements present in the list @@ -49,19 +53,152 @@ public class DoublyLinkedList { throw new NullPointerException(); } for (int i : array) { - insertTail(i); + linkOperations.insertTail(i,this); } size = array.length; } + /** + * Returns true if list is empty + * + * @return true if list is empty + */ + public boolean isEmpty() { + return (head == null); + } + + /** + * Prints contents of the list + */ + public void display() { // Prints contents of the list + Link current = head; + while (current != null) { + current.displayLink(); + current = current.next; + } + System.out.println(); + } + + /** + * Prints the contents of the list in reverse order + */ + public void displayBackwards() { + Link current = tail; + while (current != null) { + current.displayLink(); + current = current.previous; + } + System.out.println(); + } +} + +/** + * This class is used to implement the nodes of the linked list. + * + * @author Unknown + */ +class Link { + + /** + * Value of node + */ + public int value; + /** + * This points to the link in front of the new link + */ + public Link next; + /** + * This points to the link behind the new link + */ + public Link previous; + + /** + * Constructor + * + * @param value Value of node + */ + public Link(int value) { + this.value = value; + } + + /** + * Displays the node + */ + public void displayLink() { + System.out.print(value + " "); + } + + /** + * Main Method + * + * @param args Command line arguments + */ + public static void main(String args[]) { + DoublyLinkedList myList = new DoublyLinkedList(); + LinkOperations linkOperations = new LinkOperations(); + linkOperations.insertHead(13,myList); + linkOperations.insertHead(7,myList); + linkOperations.insertHead(10,myList); + myList.display(); // <-- 10(head) <--> 7 <--> 13(tail) --> + myList.displayBackwards(); + + linkOperations.insertTail(11,myList); + myList.display(); // <-- 10(head) <--> 7 <--> 13 <--> 11(tail) --> + myList.displayBackwards(); + + linkOperations.deleteTail(); + myList.display(); // <-- 10(head) <--> 7 <--> 13(tail) --> + myList.displayBackwards(); + + linkOperations.delete(7); + myList.display(); // <-- 10(head) <--> 13(tail) --> + myList.displayBackwards(); + + linkOperations.insertOrdered(23,myList); + linkOperations.insertOrdered(67,myList); + linkOperations.insertOrdered(3,myList); + myList.display(); // <-- 3(head) <--> 10 <--> 13 <--> 23 <--> 67(tail) --> + linkOperations.insertElementByIndex(5, 1,myList); + myList.display(); // <-- 3(head) <--> 5 <--> 10 <--> 13 <--> 23 <--> 67(tail) --> + myList.displayBackwards(); + linkOperations.reverse(); // <-- 67(head) <--> 23 <--> 13 <--> 10 <--> 5 <--> 3(tail) --> + myList.display(); + + linkOperations.clearList(); + myList.display(); + myList.displayBackwards(); + linkOperations.insertHead(20,myList); + myList.display(); + myList.displayBackwards(); + } +} + +/* + * This class implements the operations of the Link nodes. + */ +class LinkOperations{ + /** + * Head refers to the front of the list + */ + private Link head; + /** + * Tail refers to the back of the list + */ + private Link tail; + + /** + * Size refers to the number of elements present in the list + */ + private int size; + /** * Insert an element at the head * * @param x Element to be inserted */ - public void insertHead(int x) { + public void insertHead(int x,DoublyLinkedList doublyLinkedList) { Link newLink = new Link(x); // Create a new link with a value attached to it - if (isEmpty()) // Set the first element added to be the tail + if (doublyLinkedList.isEmpty()) // Set the first element added to be the tail { tail = newLink; } else { @@ -77,10 +214,10 @@ public class DoublyLinkedList { * * @param x Element to be inserted */ - public void insertTail(int x) { + public void insertTail(int x,DoublyLinkedList doublyLinkedList) { Link newLink = new Link(x); newLink.next = null; // currentTail(tail) newlink --> - if (isEmpty()) { // Check if there are no elements in list then it adds first element + if (doublyLinkedList.isEmpty()) { // Check if there are no elements in list then it adds first element tail = newLink; head = tail; } else { @@ -97,15 +234,15 @@ public class DoublyLinkedList { * @param x Element to be inserted * @param index Index(from start) at which the element x to be inserted */ - public void insertElementByIndex(int x, int index) { + public void insertElementByIndex(int x, int index,DoublyLinkedList doublyLinkedList) { if (index > size) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } if (index == 0) { - insertHead(x); + insertHead(x,doublyLinkedList); } else { if (index == size) { - insertTail(x); + insertTail(x,doublyLinkedList); } else { Link newLink = new Link(x); Link previousLink = head; // @@ -192,7 +329,7 @@ public class DoublyLinkedList { * * @param x Element to be added */ - public void insertOrdered(int x) { + public void insertOrdered(int x,DoublyLinkedList doublyLinkedList) { Link newLink = new Link(x); Link current = head; while (current != null && x > current.value) // Find the position to insert @@ -201,9 +338,9 @@ public class DoublyLinkedList { } if (current == head) { - insertHead(x); + insertHead(x,doublyLinkedList); } else if (current == null) { - insertTail(x); + insertTail(x,doublyLinkedList); } else { // Before: 1 <--> 2(current) <--> 3 newLink.previous = current.previous; // 1 <-- newLink current.previous.next = newLink; // 1 <--> newLink @@ -230,14 +367,14 @@ public class DoublyLinkedList { --size; } - public static void removeDuplicates(DoublyLinkedList l) { + public void removeDuplicates(DoublyLinkedList l) { Link linkOne = l.head; while (linkOne.next != null) { // list is present Link linkTwo = linkOne.next; // second link for comparison while (linkTwo.next != null) { if (linkOne.value == linkTwo.value) // if there are duplicates values then { - l.delete(linkTwo.value); // delete the link + delete(linkTwo.value); // delete the link } linkTwo = linkTwo.next; // go to next link } @@ -247,8 +384,6 @@ public class DoublyLinkedList { /** * Reverses the list in place - * - * @param l the DoublyLinkedList to reverse */ public void reverse() { // Keep references to the head and tail @@ -282,116 +417,4 @@ public class DoublyLinkedList { size = 0; } - /** - * Returns true if list is empty - * - * @return true if list is empty - */ - public boolean isEmpty() { - return (head == null); - } - - /** - * Prints contents of the list - */ - public void display() { // Prints contents of the list - Link current = head; - while (current != null) { - current.displayLink(); - current = current.next; - } - System.out.println(); - } - - /** - * Prints the contents of the list in reverse order - */ - public void displayBackwards() { - Link current = tail; - while (current != null) { - current.displayLink(); - current = current.previous; - } - System.out.println(); - } -} - -/** - * This class is used to implement the nodes of the linked list. - * - * @author Unknown - */ -class Link { - - /** - * Value of node - */ - public int value; - /** - * This points to the link in front of the new link - */ - public Link next; - /** - * This points to the link behind the new link - */ - public Link previous; - - /** - * Constructor - * - * @param value Value of node - */ - public Link(int value) { - this.value = value; - } - - /** - * Displays the node - */ - public void displayLink() { - System.out.print(value + " "); - } - - /** - * Main Method - * - * @param args Command line arguments - */ - public static void main(String args[]) { - DoublyLinkedList myList = new DoublyLinkedList(); - myList.insertHead(13); - myList.insertHead(7); - myList.insertHead(10); - myList.display(); // <-- 10(head) <--> 7 <--> 13(tail) --> - myList.displayBackwards(); - - myList.insertTail(11); - myList.display(); // <-- 10(head) <--> 7 <--> 13 <--> 11(tail) --> - myList.displayBackwards(); - - myList.deleteTail(); - myList.display(); // <-- 10(head) <--> 7 <--> 13(tail) --> - myList.displayBackwards(); - - myList.delete(7); - myList.display(); // <-- 10(head) <--> 13(tail) --> - myList.displayBackwards(); - - myList.insertOrdered(23); - myList.insertOrdered(67); - myList.insertOrdered(3); - myList.display(); // <-- 3(head) <--> 10 <--> 13 <--> 23 <--> 67(tail) --> - myList.insertElementByIndex(5, 1); - myList.display(); // <-- 3(head) <--> 5 <--> 10 <--> 13 <--> 23 <--> 67(tail) --> - myList.displayBackwards(); - myList.reverse(); // <-- 67(head) <--> 23 <--> 13 <--> 10 <--> 5 <--> 3(tail) --> - myList.display(); - - myList.clearList(); - myList.display(); - myList.displayBackwards(); - myList.insertHead(20); - myList.display(); - myList.displayBackwards(); - } } diff --git a/src/main/java/com/thealgorithms/datastructures/lists/RemoveDuplicateNodes.java b/src/main/java/com/thealgorithms/datastructures/lists/RemoveDuplicateNodes.java deleted file mode 100644 index 268951f12..000000000 --- a/src/main/java/com/thealgorithms/datastructures/lists/RemoveDuplicateNodes.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.thealgorithms.datastructures.lists; - -public class RemoveDuplicateNodes { - - public Node deleteDuplicates(Node head) { - // sentinel - Node sentinel = new Node(0, head); - - // predecessor = the last node - // before the sublist of duplicates - Node pred = sentinel; - - while (head != null) { - // if it's a beginning of duplicates sublist - // skip all duplicates - if (head.next != null && head.value == head.next.value) { - // move till the end of duplicates sublist - while (head.next != null && head.value == head.next.value) { - head = head.next; - } - // skip all duplicates - pred.next = head.next; - // otherwise, move predecessor - } else { - pred = pred.next; - } - - // move forward - head = head.next; - } - return sentinel.next; - } - - public void print(Node head) { - Node temp = head; - while (temp != null && temp.next != null) { - System.out.print(temp.value + "->"); - temp = temp.next; - } - if (temp != null) { - System.out.print(temp.value); - } - } - - public static void main(String arg[]) { - RemoveDuplicateNodes instance = new RemoveDuplicateNodes(); - Node head = new Node(0, new Node(2, new Node(3, new Node(3, new Node(4))))); - head = instance.deleteDuplicates(head); - instance.print(head); - } -} diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java index ae06688bc..104b95980 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java @@ -5,7 +5,7 @@ import java.util.StringJoiner; /** * https://en.wikipedia.org/wiki/Linked_list */ -public class SinglyLinkedList { +public class SinglyLinkedList extends Node{ /** * Head refer to the front of the list @@ -36,58 +36,10 @@ public class SinglyLinkedList { this.size = size; } - /** - * Inserts an element at the head of the list - * - * @param x element to be added - */ - public void insertHead(int x) { - insertNth(x, 0); - } - - /** - * Insert an element at the tail of the list - * - * @param data element to be added - */ - public void insert(int data) { - insertNth(data, size); - } - - /** - * Inserts a new node at a specified position of the list - * - * @param data data to be stored in a new node - * @param position position at which a new node is to be inserted - */ - public void insertNth(int data, int position) { - checkBounds(position, 0, size); - Node newNode = new Node(data); - if (head == null) { - /* the list is empty */ - head = newNode; - size++; - return; - } else if (position == 0) { - /* insert at the head of the list */ - newNode.next = head; - head = newNode; - size++; - return; - } - Node cur = head; - for (int i = 0; i < position - 1; ++i) { - cur = cur.next; - } - newNode.next = cur.next; - cur.next = newNode; - size++; - } - /** * Detects if there is a loop in the singly linked list using floy'd turtle * and hare algorithm. - * + * */ public boolean detectLoop() { Node currentNodeFast = head; @@ -104,27 +56,9 @@ public class SinglyLinkedList { return flag; } - /** - * Swaps nodes of two given values a and b. - * - */ - public void swapNodes(int a, int b) { - Node currentNode = head; - Node temp = null; - while (currentNode != null) { - if (currentNode.next.value == a) { - temp = currentNode.next; - } - if (currentNode.next.value == b) { - currentNode.next = temp; - } - currentNode = currentNode.next; - } - } - /** * Reverse a singly linked list from a given node till the end - * + * */ Node reverseList(Node node) { Node prev = null, curr = node, next; @@ -138,58 +72,6 @@ public class SinglyLinkedList { return node; } - /** - * Deletes a node at the head - */ - public void deleteHead() { - deleteNth(0); - } - - /** - * Deletes an element at the tail - */ - public void delete() { - deleteNth(size - 1); - } - - /** - * Deletes an element at Nth position - */ - public void deleteNth(int position) { - checkBounds(position, 0, size - 1); - if (position == 0) { - Node destroy = head; - head = head.next; - destroy = null; - /* clear to let GC do its work */ - size--; - return; - } - Node cur = head; - for (int i = 0; i < position - 1; ++i) { - cur = cur.next; - } - - Node destroy = cur.next; - cur.next = cur.next.next; - destroy = null; // clear to let GC do its work - - size--; - } - - /** - * @param position to check position - * @param low low index - * @param high high index - * @throws IndexOutOfBoundsException if {@code position} not in range - * {@code low} to {@code high} - */ - public void checkBounds(int position, int low, int high) { - if (position > high || position < low) { - throw new IndexOutOfBoundsException(position + ""); - } - } - /** * Clear all nodes in the list */ @@ -264,21 +146,6 @@ public class SinglyLinkedList { return false; } - /** - * Return element at special index. - * - * @param index given index of element - * @return element at special index. - */ - public int getNth(int index) { - checkBounds(index, 0, size - 1); - Node cur = head; - for (int i = 0; i < index; ++i) { - cur = cur.next; - } - return cur.value; - } - @Override public String toString() { StringJoiner joiner = new StringJoiner("->"); @@ -332,6 +199,12 @@ public class SinglyLinkedList { assert true; /* this should happen */ } + + Node instance = new Node(); + Node head = new Node(0, new Node(2, new Node(3, new Node(3, new Node(4))))); + head = instance.deleteDuplicates(head); + instance.print(head); + } } @@ -341,6 +214,18 @@ public class SinglyLinkedList { */ class Node { + /** + * Head refer to the front of the list + */ + public Node head; + + /** + * Size of SinglyLinkedList + */ + public int size; + + + /** * The value of the node */ @@ -373,4 +258,177 @@ class Node { this.value = value; this.next = next; } + + public Node deleteDuplicates(Node head) { + // sentinel + Node sentinel = new Node(0, head); + + // predecessor = the last node + // before the sublist of duplicates + Node pred = sentinel; + + while (head != null) { + // if it's a beginning of duplicates sublist + // skip all duplicates + if (head.next != null && head.value == head.next.value) { + // move till the end of duplicates sublist + while (head.next != null && head.value == head.next.value) { + head = head.next; + } + // skip all duplicates + pred.next = head.next; + // otherwise, move predecessor + } else { + pred = pred.next; + } + + // move forward + head = head.next; + } + return sentinel.next; + } + + public void print(Node head) { + Node temp = head; + while (temp != null && temp.next != null) { + System.out.print(temp.value + "->"); + temp = temp.next; + } + if (temp != null) { + System.out.print(temp.value); + } + } + + /** + * Inserts an element at the head of the list + * + * @param x element to be added + */ + public void insertHead(int x) { + insertNth(x, 0); + } + + /** + * Insert an element at the tail of the list + * + * @param data element to be added + */ + public void insert(int data) { + insertNth(data, size); + } + + /** + * Inserts a new node at a specified position of the list + * + * @param data data to be stored in a new node + * @param position position at which a new node is to be inserted + */ + public void insertNth(int data, int position) { + checkBounds(position, 0, size); + Node newNode = new Node(data); + if (head == null) { + /* the list is empty */ + head = newNode; + size++; + return; + } else if (position == 0) { + /* insert at the head of the list */ + newNode.next = head; + head = newNode; + size++; + return; + } + Node cur = head; + for (int i = 0; i < position - 1; ++i) { + cur = cur.next; + } + newNode.next = cur.next; + cur.next = newNode; + size++; + } + + /** + * Swaps nodes of two given values a and b. + * + */ + public void swapNodes(int a, int b) { + Node currentNode = head; + Node temp = null; + while (currentNode != null) { + if (currentNode.next.value == a) { + temp = currentNode.next; + } + if (currentNode.next.value == b) { + currentNode.next = temp; + } + currentNode = currentNode.next; + } + } + + /** + * Deletes a node at the head + */ + public void deleteHead() { + deleteNth(0); + } + + /** + * Deletes an element at the tail + */ + public void delete() { + deleteNth(size - 1); + } + + /** + * Deletes an element at Nth position + */ + public void deleteNth(int position) { + checkBounds(position, 0, size - 1); + if (position == 0) { + Node destroy = head; + head = head.next; + destroy = null; + /* clear to let GC do its work */ + size--; + return; + } + Node cur = head; + for (int i = 0; i < position - 1; ++i) { + cur = cur.next; + } + + Node destroy = cur.next; + cur.next = cur.next.next; + destroy = null; // clear to let GC do its work + + size--; + } + + /** + * Return element at special index. + * + * @param index given index of element + * @return element at special index. + */ + public int getNth(int index) { + checkBounds(index, 0, size - 1); + Node cur = head; + for (int i = 0; i < index; ++i) { + cur = cur.next; + } + return cur.value; + } + + /** + * @param position to check position + * @param low low index + * @param high high index + * @throws IndexOutOfBoundsException if {@code position} not in range + * {@code low} to {@code high} + */ + public void checkBounds(int position, int low, int high) { + if (position > high || position < low) { + throw new IndexOutOfBoundsException(position + ""); + } + } }