├── Day_01 ├── Array_Example.java ├── InputData.class ├── InputData.java ├── README.md ├── SingleArray.class └── SingleArray.java ├── Day_02 ├── Example.class ├── Example.java ├── LinkedList.class ├── LinkedList_Example.class ├── LinkedList_Example.java ├── ListExample01.java ├── Node.class └── README.md ├── Day_03 ├── DoublyLinkedList.class ├── Doubly_Linked_List.class ├── Doubly_Linked_List.java ├── Node.class └── README.md ├── Day_04 ├── Circular_Linked_List.java └── README.md ├── Day_05 ├── README.md └── Stack_Example.java ├── Day_06 ├── Parsing_Expressions_Example.java └── README.md ├── Day_07 ├── Queue_Example.java └── README.md ├── Day_08 ├── PriorityQueueExample.java └── README.md ├── Day_09 ├── BinarySearchTreeExample.java └── README.md ├── Day_10 ├── HashTable$Entry.class ├── HashTable.class ├── HashTable.java ├── HashTable_Example1.java └── README.md ├── Day_11 ├── MaxHeap.java ├── MaxHeap_01.java └── README.md ├── Day_12 ├── Graph.java ├── Graph_Data_Structure.java └── README.md ├── Day_13 ├── LinearSearchExample.java ├── README.md └── SearchExample.java ├── Day_14 ├── BubbleSort.java ├── README.md └── SortingExample.java ├── Day_15 ├── BinarySearchRecursion.java ├── README.md ├── RecursionExample1.java └── RecursionExample2.java └── README.md /Day_01/Array_Example.java: -------------------------------------------------------------------------------- 1 | package Day_01; 2 | // www.codeswithpankaj.com 3 | // www.p4n.in 4 | public class Array_Example { 5 | public static void main(String[] args){ 6 | 7 | // Declare an array 8 | int intArray[]; 9 | 10 | // Initialize an array of 8 int 11 | // set aside memory of 8 int 12 | intArray = new int[8]; 13 | 14 | System.out.println("Array before adding data."); 15 | 16 | // Display elements of an array. 17 | display(intArray); 18 | 19 | // Operation : Insertion 20 | // Add elements in the array 21 | for(int i = 0; i< intArray.length; i++) 22 | { 23 | // place value of i at index i. 24 | System.out.println("Adding "+i+" at index "+i); 25 | intArray[i] = i; 26 | } 27 | System.out.println(); 28 | 29 | System.out.println("Array after adding data."); 30 | display(intArray); 31 | 32 | // Operation : Insertion 33 | // Element at any location can be updated directly 34 | int index = 5; 35 | intArray[index] = 10; 36 | 37 | System.out.println("Array after updating element at index " + index); 38 | display(intArray); 39 | 40 | // Operation : Search using index 41 | // Search an element using index. 42 | System.out.println("Data at index " + index + ": "+ intArray[index]); 43 | 44 | // Operation : Search using value 45 | // Search an element using value. 46 | int value = 4; 47 | for(int i = 0; i< intArray.length; i++) 48 | { 49 | if(intArray[i] == value ){ 50 | System.out.println(value + " Found at index "+i); 51 | break; 52 | } 53 | } 54 | System.out.println("Data at index " + index + ": "+ intArray[index]); 55 | } 56 | 57 | private static void display(int[] intArray){ 58 | System.out.print("Array : ["); 59 | for(int i = 0; i< intArray.length; i++) 60 | { 61 | // display value of element at index i. 62 | System.out.print(" "+intArray[i]); 63 | } 64 | System.out.println(" ]"); 65 | System.out.println(); 66 | } 67 | } -------------------------------------------------------------------------------- /Day_01/InputData.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_01/InputData.class -------------------------------------------------------------------------------- /Day_01/InputData.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | class InputData{ 3 | public static void main(String[] args) { 4 | // create a object 5 | Scanner sc = new Scanner(System.in); 6 | System.out.println("Your Array Size - "); 7 | int size = sc.nextInt(); 8 | 9 | String[] data = new String[size]; 10 | 11 | for (int i = 0; i < size; i++) { 12 | System.out.println("Enter Data into Array = "+(i+1)); 13 | data[i] = sc.next(); 14 | } 15 | System.out.println("------output-------------"); 16 | for (int i = 0; i < size; i++) { 17 | System.out.println(i+" = "+data[i]); 18 | 19 | } 20 | 21 | 22 | } 23 | } -------------------------------------------------------------------------------- /Day_01/README.md: -------------------------------------------------------------------------------- 1 | ## Data Structures and Algorithms (DSA) concept of an array in Java. 2 | 3 | In Java, an array is a fixed-size collection of elements of the same type. It allows you to store multiple values of the same data type in contiguous memory locations. Each element in the array is accessed using an index, starting from 0. 4 | 5 | Here's an example of creating and using an array in Java: 6 | 7 | ```java 8 | public class p4n_ArrayExample { 9 | public static void main(String[] args) { 10 | // Creating an array of integers 11 | int[] numbers = new int[5]; 12 | 13 | // Assigning values to array elements 14 | numbers[0] = 10; 15 | numbers[1] = 20; 16 | numbers[2] = 30; 17 | numbers[3] = 40; 18 | numbers[4] = 50; 19 | 20 | // Accessing and printing array elements 21 | System.out.println(numbers[0]); // Output: 10 22 | System.out.println(numbers[2]); // Output: 30 23 | 24 | // Array length 25 | int length = numbers.length; 26 | System.out.println("Array length: " + length); // Output: 5 27 | } 28 | } 29 | ``` 30 | 31 | In the example above, we first declare an array called `numbers` of type `int` with a size of 5 using the syntax `int[] numbers = new int[5]`. This creates an array with five elements, indexed from 0 to 4. 32 | 33 | We then assign values to each element of the array using the index notation. For example, `numbers[0] = 10` assigns the value 10 to the first element of the array. 34 | 35 | To access and print the values of specific elements, we use the index notation as well. For instance, `System.out.println(numbers[0])` outputs the value 10. 36 | 37 | The length of an array can be obtained using the `length` property of the array, as shown in the example. In this case, `numbers.length` returns 5, which represents the number of elements in the array. 38 | 39 | It's important to note that arrays in Java have a fixed size, meaning once you define the size of an array, you cannot change it. If you need a dynamic collection that can grow or shrink, you might consider using other data structures like ArrayList or LinkedList. 40 | 41 | 42 | -------------------------------------------------------------------------------- /Day_01/SingleArray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_01/SingleArray.class -------------------------------------------------------------------------------- /Day_01/SingleArray.java: -------------------------------------------------------------------------------- 1 | class SingleArray{ 2 | 3 | public static void main(String[] args) { 4 | 5 | int[] data = new int[5]; 6 | 7 | data[0] = 18; 8 | data[1] = 19; 9 | data[2] = 20; 10 | data[3] = 21; 11 | data[4] = 22; 12 | 13 | System.out.println(data[0]);// single access data 14 | 15 | for (int i : data) { 16 | System.out.println("Number - "+i); 17 | } 18 | System.out.println("------------------"); 19 | for (int i = 0; i < data.length; i++) { 20 | System.out.println(i+"Number = "+data[i]); 21 | } 22 | 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /Day_02/Example.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_02/Example.class -------------------------------------------------------------------------------- /Day_02/Example.java: -------------------------------------------------------------------------------- 1 | package Day_02; 2 | 3 | public class Example { 4 | 5 | int Node; 6 | Example(int node){ 7 | Node = node; 8 | System.out.println(node); 9 | 10 | } 11 | 12 | public static void main(String[] args) { 13 | Example obj = new Example(12); 14 | System.out.println("NODE :- "+obj.Node); 15 | } 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /Day_02/LinkedList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_02/LinkedList.class -------------------------------------------------------------------------------- /Day_02/LinkedList_Example.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_02/LinkedList_Example.class -------------------------------------------------------------------------------- /Day_02/LinkedList_Example.java: -------------------------------------------------------------------------------- 1 | package Day_02; 2 | //www.codeswithpankaj.com 3 | //www.p4n.in 4 | //Node class for linked list 5 | class Node { 6 | int data; 7 | Node next; 8 | Node(int value) { 9 | data = value; 10 | next = null; 11 | } 12 | } 13 | 14 | //Linked list class 15 | class LinkedList { 16 | private Node head; 17 | 18 | LinkedList() { 19 | head = null; 20 | } 21 | 22 | // Function to insert a new node at the beginning of the linked list 23 | void insertAtBeginning(int value) { 24 | Node newNode = new Node(value); 25 | newNode.next = head; 26 | head = newNode; 27 | } 28 | 29 | // Function to insert a new node at the end of the linked list 30 | void insertAtEnd(int value) { 31 | Node newNode = new Node(value); 32 | 33 | if (head == null) { 34 | head = newNode; 35 | } else { 36 | Node current = head; 37 | while (current.next != null) { 38 | current = current.next; 39 | } 40 | current.next = newNode; 41 | } 42 | } 43 | 44 | // Function to display the linked list 45 | void display() { 46 | Node current = head; 47 | while (current != null) { 48 | System.out.print(current.data + " "); 49 | current = current.next; 50 | } 51 | System.out.println(); 52 | } 53 | } 54 | 55 | //Example usage 56 | public class LinkedList_Example { 57 | public static void main(String[] args) { 58 | LinkedList myList = new LinkedList(); 59 | 60 | myList.insertAtBeginning(3); 61 | myList.insertAtBeginning(2); 62 | myList.insertAtBeginning(10); 63 | myList.insertAtEnd(4); 64 | 65 | myList.display(); // Output: 2 3 4 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Day_02/ListExample01.java: -------------------------------------------------------------------------------- 1 | package Day_02; 2 | import java.util.*; 3 | import java.util.LinkedList; 4 | public class ListExample01 { 5 | 6 | public static void main(String[] args) { 7 | List data = new LinkedList(); 8 | data.add(23); 9 | data.add(45); 10 | System.out.println(data); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Day_02/Node.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_02/Node.class -------------------------------------------------------------------------------- /Day_02/README.md: -------------------------------------------------------------------------------- 1 | ## Data Structures and Algorithms (DSA) concept of a linked list in Java. 2 | 3 | In Java, a linked list is a data structure that consists of nodes, where each node contains a value and a reference (or link) to the next node in the list. Unlike arrays, linked lists do not require contiguous memory allocation and can dynamically grow or shrink as needed. 4 | 5 | Here's an example of creating and using a linked list in Java: 6 | 7 | ```java 8 | //@p4n.in 9 | public class LinkedListExample{ 10 | // Node class to represent individual nodes in the linked list 11 | static class Node { 12 | int data; // The value stored in the node 13 | Node next; // Reference to the next node 14 | 15 | public Node(int data) { 16 | this.data = data; 17 | this.next = null; 18 | } 19 | } 20 | 21 | public static void main(String[] args) { 22 | // Creating a linked list 23 | Node head = new Node(10); 24 | Node second = new Node(20); 25 | Node third = new Node(30); 26 | 27 | // Linking the nodes together 28 | head.next = second; 29 | second.next = third; 30 | 31 | // Traversing and printing the linked list 32 | Node current = head; 33 | while (current != null) { 34 | System.out.println(current.data); 35 | current = current.next; 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | In the example above, we define a `Node` class to represent individual nodes in the linked list. Each `Node` has a `data` field to store the value and a `next` field to store the reference to the next node. 42 | 43 | To create a linked list, we create instances of the `Node` class and connect them by setting the `next` references. In the example, we create three nodes: `head` with a value of 10, `second` with a value of 20, and `third` with a value of 30. Then, we link them together by setting `head.next` to `second` and `second.next` to `third`. 44 | 45 | To traverse and print the linked list, we start from the `head` node and iterate through the list by following the `next` references. We use a `current` variable to keep track of the current node being processed. The loop continues until we reach the end of the list, which is indicated by a `null` value in the `next` field of the last node. 46 | 47 | When executing the example, it will print the values of the linked list: 10, 20, and 30. 48 | 49 | Linked lists are advantageous for dynamic data structures where frequent insertions and deletions are performed. However, they have slower access times compared to arrays when accessing elements at specific indices. 50 | 51 | It's worth noting that this example shows a basic implementation of a singly linked list where each node only has a reference to the next node. There are other variations like doubly linked lists where each node has references to both the next and previous nodes, and circular linked lists where the last node's `next` reference points back to the head of the list. 52 | -------------------------------------------------------------------------------- /Day_03/DoublyLinkedList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_03/DoublyLinkedList.class -------------------------------------------------------------------------------- /Day_03/Doubly_Linked_List.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_03/Doubly_Linked_List.class -------------------------------------------------------------------------------- /Day_03/Doubly_Linked_List.java: -------------------------------------------------------------------------------- 1 | package Day_03; 2 | //www.codeswithpankaj.com 3 | //www.p4n.in 4 | //Node class for doubly linked list 5 | class Node { 6 | int data; 7 | Node prev; 8 | Node next; 9 | 10 | Node(int value) { 11 | data = value; 12 | prev = null; 13 | next = null; 14 | } 15 | } 16 | 17 | //Doubly linked list class 18 | class DoublyLinkedList { 19 | private Node head; 20 | 21 | DoublyLinkedList() { 22 | head = null; 23 | } 24 | 25 | // Function to insert a new node at the beginning of the doubly linked list 26 | void insertAtBeginning(int value) { 27 | Node newNode = new Node(value); 28 | if (head == null) { 29 | head = newNode; 30 | } else { 31 | newNode.next = head; 32 | head.prev = newNode; 33 | head = newNode; 34 | } 35 | } 36 | 37 | // Function to insert a new node at the end of the doubly linked list 38 | void insertAtEnd(int value) { 39 | Node newNode = new Node(value); 40 | if (head == null) { 41 | head = newNode; 42 | } else { 43 | Node current = head; 44 | while (current.next != null) { 45 | current = current.next; 46 | } 47 | current.next = newNode; 48 | newNode.prev = current; 49 | } 50 | } 51 | 52 | // Function to display the doubly linked list in forward direction 53 | void displayForward() { 54 | Node current = head; 55 | while (current != null) { 56 | System.out.print(current.data + " "); 57 | current = current.next; 58 | } 59 | System.out.println(); 60 | } 61 | 62 | // Function to display the doubly linked list in reverse direction 63 | void displayBackward() { 64 | Node current = head; 65 | if (current == null) { 66 | return; 67 | } 68 | while (current.next != null) { 69 | current = current.next; 70 | } 71 | while (current != null) { 72 | System.out.print(current.data + " "); 73 | current = current.prev; 74 | } 75 | System.out.println(); 76 | } 77 | } 78 | 79 | //Example usage 80 | public class Doubly_Linked_List { 81 | public static void main(String[] args) { 82 | DoublyLinkedList myList = new DoublyLinkedList(); 83 | 84 | myList.insertAtEnd(2); 85 | myList.insertAtEnd(3); 86 | myList.insertAtBeginning(1); 87 | 88 | myList.displayForward(); // Output: 1 2 3 89 | myList.displayBackward(); // Output: 3 2 1 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Day_03/Node.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_03/Node.class -------------------------------------------------------------------------------- /Day_03/README.md: -------------------------------------------------------------------------------- 1 | ## Data Structures and Algorithms (DSA) purposes. 2 | 3 | In Java, a doubly linked list is a data structure in which each node contains a value, a reference to the next node, and a reference to the previous node. This allows for efficient traversal in both directions. 4 | 5 | Here's an example of creating and using a doubly linked list in Java: 6 | 7 | ```java 8 | //@p4n.in 9 | public class DoublyLinkedListExample { 10 | // Node class to represent individual nodes in the doubly linked list 11 | static class Node { 12 | int data; // The value stored in the node 13 | Node next; // Reference to the next node 14 | Node prev; // Reference to the previous node 15 | 16 | public Node(int data) { 17 | this.data = data; 18 | this.next = null; 19 | this.prev = null; 20 | } 21 | } 22 | 23 | public static void main(String[] args) { 24 | // Creating a doubly linked list 25 | Node head = new Node(10); 26 | Node second = new Node(20); 27 | Node third = new Node(30); 28 | 29 | // Linking the nodes together 30 | head.next = second; 31 | second.prev = head; 32 | second.next = third; 33 | third.prev = second; 34 | 35 | // Traversing forward and printing the linked list 36 | Node current = head; 37 | while (current != null) { 38 | System.out.println(current.data); 39 | current = current.next; 40 | } 41 | 42 | // Traversing backward and printing the linked list 43 | Node tail = third; 44 | while (tail != null) { 45 | System.out.println(tail.data); 46 | tail = tail.prev; 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | In the example above, we define a `Node` class to represent individual nodes in the doubly linked list. Each `Node` has a `data` field to store the value, a `next` field to store the reference to the next node, and a `prev` field to store the reference to the previous node. 53 | 54 | To create a doubly linked list, we create instances of the `Node` class and connect them by setting the `next` and `prev` references. In the example, we create three nodes: `head` with a value of 10, `second` with a value of 20, and `third` with a value of 30. Then, we link them together by setting `head.next` to `second`, `second.prev` to `head`, `second.next` to `third`, and `third.prev` to `second`. 55 | 56 | To traverse and print the doubly linked list, we can start from either the `head` or the `tail` of the list. In the example, we traverse forward starting from the `head` and print the values of each node. Then, we traverse backward starting from the `tail` (which is the last node) and print the values of each node by following the `prev` references. 57 | 58 | When executing the example, it will print the values of the doubly linked list in both forward and backward directions: 10, 20, 30, and then 30, 20, 10. 59 | 60 | Doubly linked lists are advantageous when we need efficient traversal in both directions. They allow for easy insertion and deletion operations at both ends of the list. However, they require more memory compared to singly linked lists due to the extra `prev` references. 61 | -------------------------------------------------------------------------------- /Day_04/Circular_Linked_List.java: -------------------------------------------------------------------------------- 1 | package Day_04; 2 | //www.codeswithpankaj.com 3 | //www.p4n.in 4 | //Node class for circular linked list 5 | class Node { 6 | int data; 7 | Node next; 8 | 9 | Node(int value) { 10 | data = value; 11 | next = null; 12 | } 13 | } 14 | 15 | //Circular linked list class 16 | class CircularLinkedList { 17 | private Node head; 18 | 19 | CircularLinkedList() { 20 | head = null; 21 | } 22 | 23 | // Function to insert a new node at the beginning of the circular linked list 24 | void insertAtBeginning(int value) { 25 | Node newNode = new Node(value); 26 | if (head == null) { 27 | newNode.next = newNode; // Point to itself in a circular list 28 | } else { 29 | Node current = head; 30 | while (current.next != head) { 31 | current = current.next; 32 | } 33 | current.next = newNode; 34 | newNode.next = head; 35 | } 36 | head = newNode; // Update the head to the new node 37 | } 38 | 39 | // Function to insert a new node at the end of the circular linked list 40 | void insertAtEnd(int value) { 41 | Node newNode = new Node(value); 42 | if (head == null) { 43 | newNode.next = newNode; // Point to itself in a circular list 44 | head = newNode; // Update the head to the new node 45 | } else { 46 | Node current = head; 47 | while (current.next != head) { 48 | current = current.next; 49 | } 50 | current.next = newNode; 51 | newNode.next = head; 52 | } 53 | } 54 | 55 | // Function to display the circular linked list 56 | void display() { 57 | if (head == null) { 58 | return; 59 | } 60 | Node current = head; 61 | do { 62 | System.out.print(current.data + " "); 63 | current = current.next; 64 | } while (current != head); 65 | System.out.println(); 66 | } 67 | } 68 | 69 | //Example usage 70 | public class Circular_Linked_List{ 71 | public static void main(String[] args) { 72 | CircularLinkedList myList = new CircularLinkedList(); 73 | 74 | myList.insertAtEnd(2); 75 | myList.insertAtEnd(3); 76 | myList.insertAtBeginning(1); 77 | 78 | myList.display(); // Output: 1 2 3 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Day_04/README.md: -------------------------------------------------------------------------------- 1 | ## Circular linked list Data Structures and Algorithms (DSA) purposes. 2 | 3 | In Java, a circular linked list is a data structure where each node contains a value and a reference to the next node. The last node's reference points back to the head of the list, creating a circular structure. 4 | 5 | Here's an example of creating and using a circular linked list in Java: 6 | 7 | ```java 8 | //@p4n.in 9 | public class CircularLinkedListExample { 10 | // Node class to represent individual nodes in the circular linked list 11 | static class Node { 12 | int data; // The value stored in the node 13 | Node next; // Reference to the next node 14 | 15 | public Node(int data) { 16 | this.data = data; 17 | this.next = null; 18 | } 19 | } 20 | 21 | public static void main(String[] args) { 22 | // Creating a circular linked list 23 | Node head = new Node(10); 24 | Node second = new Node(20); 25 | Node third = new Node(30); 26 | 27 | // Linking the nodes together 28 | head.next = second; 29 | second.next = third; 30 | third.next = head; // Connecting the last node to the head 31 | 32 | // Traversing and printing the circular linked list 33 | Node current = head; 34 | do { 35 | System.out.println(current.data); 36 | current = current.next; 37 | } while (current != head); 38 | } 39 | } 40 | ``` 41 | 42 | In the example above, we define a `Node` class to represent individual nodes in the circular linked list. Each `Node` has a `data` field to store the value and a `next` field to store the reference to the next node. 43 | 44 | To create a circular linked list, we create instances of the `Node` class and connect them by setting the `next` references. In the example, we create three nodes: `head` with a value of 10, `second` with a value of 20, and `third` with a value of 30. Then, we link them together by setting `head.next` to `second`, `second.next` to `third`, and `third.next` to `head`, effectively closing the loop. 45 | 46 | To traverse and print the circular linked list, we start from the `head` node and iterate through the list by following the `next` references. We use a `current` variable to keep track of the current node being processed. The loop continues until we reach the `head` node again, which indicates that we have completed one full traversal of the circular list. 47 | 48 | When executing the example, it will print the values of the circular linked list: 10, 20, 30, and then it will return to 10. 49 | 50 | Circular linked lists are advantageous in scenarios where we need to traverse the list indefinitely or when we want to efficiently perform operations that involve wrapping around to the beginning of the list. For example, in applications where we need to implement circular queues or circular buffers, circular linked lists can be useful. 51 | -------------------------------------------------------------------------------- /Day_05/README.md: -------------------------------------------------------------------------------- 1 | ## Stack in Java for Data Structures and Algorithms (DSA) purposes. 2 | 3 | In Java, a stack is a linear data structure that follows the Last-In-First-Out (LIFO) principle. It allows for inserting and removing elements only at one end, which is called the top of the stack. 4 | 5 | Here's an example of creating and using a stack in Java: 6 | 7 | ```java 8 | //@p4n.in 9 | import java.util.Stack; 10 | 11 | public class StackExample { 12 | public static void main(String[] args) { 13 | // Creating a stack 14 | Stack stack = new Stack<>(); 15 | 16 | // Pushing elements onto the stack 17 | stack.push(10); 18 | stack.push(20); 19 | stack.push(30); 20 | 21 | // Peeking the top element 22 | int topElement = stack.peek(); 23 | System.out.println("Top element: " + topElement); // Output: 30 24 | 25 | // Popping elements from the stack 26 | int poppedElement = stack.pop(); 27 | System.out.println("Popped element: " + poppedElement); // Output: 30 28 | 29 | // Checking if the stack is empty 30 | boolean isEmpty = stack.isEmpty(); 31 | System.out.println("Is stack empty? " + isEmpty); // Output: false 32 | 33 | // Getting the size of the stack 34 | int size = stack.size(); 35 | System.out.println("Stack size: " + size); // Output: 2 36 | } 37 | } 38 | ``` 39 | 40 | In the example above, we use the built-in `Stack` class provided by Java's standard library (`java.util.Stack`). This class provides an implementation of a stack data structure. 41 | 42 | To create a stack, we instantiate an object of the `Stack` class, as shown in `Stack stack = new Stack<>();`. The `` part specifies that the stack will store elements of type `Integer`. You can replace `Integer` with any other data type as needed. 43 | 44 | We can push elements onto the stack using the `push` method. For example, `stack.push(10)` pushes the element 10 onto the stack, followed by pushing 20 and 30. 45 | 46 | To access the top element of the stack without removing it, we can use the `peek` method, as shown in `int topElement = stack.peek();`. This retrieves the top element (which is 30 in this case) without modifying the stack. 47 | 48 | To remove and retrieve the top element from the stack, we use the `pop` method, as shown in `int poppedElement = stack.pop();`. This removes the top element (which is 30) from the stack and returns it. 49 | 50 | We can check if the stack is empty using the `isEmpty` method, which returns `true` if the stack is empty and `false` otherwise. 51 | 52 | The `size` method gives the current size of the stack, indicating the number of elements present in it. 53 | 54 | It's important to note that the `Stack` class is a legacy class in Java, and it's recommended to use the `Deque` interface from the `java.util` package to implement a stack-like behavior. `Deque` provides more modern and efficient stack operations. 55 | -------------------------------------------------------------------------------- /Day_05/Stack_Example.java: -------------------------------------------------------------------------------- 1 | package Day_05; 2 | //www.codeswithpankaj.com 3 | //www.p4n.in 4 | 5 | import java.util.EmptyStackException; 6 | 7 | //Node class for stack 8 | class Node { 9 | int data; 10 | Node next; 11 | 12 | Node(int value) { 13 | data = value; 14 | next = null; 15 | } 16 | } 17 | 18 | //Stack class 19 | class Stack { 20 | private Node top; // Reference to the top node of the stack 21 | 22 | public Stack() { 23 | top = null; // Stack is initially empty 24 | } 25 | 26 | public void push(int value) { 27 | Node newNode = new Node(value); 28 | newNode.next = top; 29 | top = newNode; 30 | } 31 | 32 | public int pop() { 33 | if (isEmpty()) { 34 | throw new EmptyStackException(); 35 | } 36 | int value = top.data; 37 | top = top.next; 38 | return value; 39 | } 40 | 41 | public int peek() { 42 | if (isEmpty()) { 43 | throw new EmptyStackException(); 44 | } 45 | return top.data; 46 | } 47 | 48 | public boolean isEmpty() { 49 | return top == null; 50 | } 51 | } 52 | 53 | //Example usage 54 | public class Stack_Example { 55 | public static void main(String[] args) { 56 | Stack stack = new Stack(); 57 | 58 | stack.push(1); 59 | stack.push(2); 60 | stack.push(3); 61 | 62 | System.out.println(stack.pop()); // Output: 3 63 | System.out.println(stack.peek()); // Output: 2 64 | System.out.println(stack.isEmpty()); // Output: false 65 | 66 | stack.push(4); 67 | stack.push(5); 68 | 69 | System.out.println(stack.pop()); // Output: 5 70 | System.out.println(stack.pop()); // Output: 4 71 | System.out.println(stack.pop()); // Output: 2 72 | System.out.println(stack.isEmpty()); // Output: true 73 | 74 | // Trying to pop from an empty stack 75 | try { 76 | System.out.println(stack.pop()); 77 | } catch (EmptyStackException e) { 78 | System.out.println("Error: " + e.getMessage()); // Output: Error: java.util.EmptyStackException 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Day_06/Parsing_Expressions_Example.java: -------------------------------------------------------------------------------- 1 | package Day_06; 2 | //www.codeswithpankaj.com 3 | //www.p4n.in 4 | 5 | import java.util.Stack; 6 | import java.util.Queue; 7 | import java.util.LinkedList; 8 | 9 | // Operator precedence 10 | class Precedence { 11 | public static final int LOWEST = 0; 12 | public static final int ADD_SUB = 1; 13 | public static final int MUL_DIV = 2; 14 | public static final int EXPONENT = 3; 15 | } 16 | 17 | // Expression Parser class 18 | class ExpressionParser { 19 | private Stack operatorStack; 20 | private Queue outputQueue; 21 | 22 | public ExpressionParser() { 23 | operatorStack = new Stack<>(); 24 | outputQueue = new LinkedList<>(); 25 | } 26 | 27 | public String parse(String expression) { 28 | for (int i = 0; i < expression.length(); i++) { 29 | char c = expression.charAt(i); 30 | 31 | if (Character.isDigit(c)) { 32 | // If the character is a digit, enqueue it directly 33 | int j = i; 34 | while (j < expression.length() && (Character.isDigit(expression.charAt(j)) || expression.charAt(j) == '.')) { 35 | j++; 36 | } 37 | outputQueue.offer(expression.substring(i, j)); 38 | i = j - 1; // Move the index to the end of the number 39 | } else if (isOperator(c)) { 40 | // If the character is an operator, process it based on operator precedence 41 | while (!operatorStack.empty() && isOperator(operatorStack.peek()) && hasHigherPrecedence(operatorStack.peek(), c)) { 42 | outputQueue.offer(operatorStack.pop().toString()); 43 | } 44 | operatorStack.push(c); 45 | } else if (c == '(') { 46 | // If the character is an opening parenthesis, push it to the stack 47 | operatorStack.push(c); 48 | } else if (c == ')') { 49 | // If the character is a closing parenthesis, pop operators from the stack and enqueue them until an opening parenthesis is encountered 50 | while (!operatorStack.empty() && operatorStack.peek() != '(') { 51 | outputQueue.offer(operatorStack.pop().toString()); 52 | } 53 | if (!operatorStack.empty() && operatorStack.peek() == '(') { 54 | operatorStack.pop(); // Discard the opening parenthesis 55 | } else { 56 | throw new IllegalArgumentException("Mismatched parentheses"); 57 | } 58 | } 59 | } 60 | 61 | // Pop any remaining operators from the stack and enqueue them 62 | while (!operatorStack.empty()) { 63 | if (operatorStack.peek() == '(' || operatorStack.peek() == ')') { 64 | throw new IllegalArgumentException("Mismatched parentheses"); 65 | } 66 | outputQueue.offer(operatorStack.pop().toString()); 67 | } 68 | 69 | // Build the final parsed expression by joining the elements in the output queue 70 | StringBuilder parsedExpression = new StringBuilder(); 71 | while (!outputQueue.isEmpty()) { 72 | parsedExpression.append(outputQueue.poll()).append(" "); 73 | } 74 | return parsedExpression.toString().trim(); 75 | } 76 | 77 | private boolean isOperator(char c) { 78 | return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'; 79 | } 80 | 81 | private boolean hasHigherPrecedence(char op1, char op2) { 82 | int precedence1 = getPrecedence(op1); 83 | int precedence2 = getPrecedence(op2); 84 | return precedence1 >= precedence2; 85 | } 86 | 87 | private int getPrecedence(char operator) { 88 | switch (operator) { 89 | case '+': 90 | case '-': 91 | return Precedence.ADD_SUB; 92 | case '*': 93 | case '/': 94 | return Precedence.MUL_DIV; 95 | case '^': 96 | return Precedence.EXPONENT; 97 | default: 98 | return Precedence.LOWEST; 99 | } 100 | } 101 | } 102 | 103 | // Example usage 104 | public class Parsing_Expressions_Example { 105 | public static void main(String[] args) { 106 | String expression = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"; 107 | ExpressionParser parser = new ExpressionParser(); 108 | String parsedExpression = parser.parse(expression); 109 | System.out.println("Parsed Expression: " + parsedExpression); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Day_06/README.md: -------------------------------------------------------------------------------- 1 | ## Parsing expressions in DSA 2 | refers to the process of breaking down an expression, typically represented as a string, into its constituent parts and analyzing its structure. This is commonly done in computer science and programming to evaluate mathematical or logical expressions, build abstract syntax trees, or perform other operations on expressions. 3 | 4 | To parse expressions in Java, you can use various techniques such as recursive descent parsing, stack-based parsing, or leveraging existing libraries and frameworks. I'll provide a simple example using recursive descent parsing to evaluate arithmetic expressions in Java. 5 | 6 | ```java 7 | //@p4n.in 8 | import java.util.*; 9 | 10 | public class ExpressionParser { 11 | private static int index; // Current index while parsing the expression 12 | private static String expression; // The expression string 13 | 14 | public static void main(String[] args) { 15 | Scanner scanner = new Scanner(System.in); 16 | System.out.print("Enter an arithmetic expression: "); 17 | expression = scanner.nextLine(); 18 | scanner.close(); 19 | 20 | index = 0; // Reset the index to the beginning of the expression 21 | double result = evaluateExpression(); 22 | System.out.println("Result: " + result); 23 | } 24 | 25 | // Recursive descent parsing for evaluating arithmetic expressions 26 | private static double evaluateExpression() { 27 | List operands = new ArrayList<>(); 28 | List operators = new ArrayList<>(); 29 | 30 | while (index < expression.length()) { 31 | if (Character.isDigit(expression.charAt(index))) { 32 | double operand = parseOperand(); 33 | operands.add(operand); 34 | } else { 35 | char operator = parseOperator(); 36 | operators.add(operator); 37 | } 38 | } 39 | 40 | double result = operands.get(0); 41 | for (int i = 0; i < operators.size(); i++) { 42 | char operator = operators.get(i); 43 | double operand = operands.get(i + 1); 44 | 45 | if (operator == '+') { 46 | result += operand; 47 | } else if (operator == '-') { 48 | result -= operand; 49 | } else if (operator == '*') { 50 | result *= operand; 51 | } else if (operator == '/') { 52 | result /= operand; 53 | } 54 | } 55 | 56 | return result; 57 | } 58 | 59 | // Parse and return the next operand in the expression 60 | private static double parseOperand() { 61 | StringBuilder sb = new StringBuilder(); 62 | 63 | while (index < expression.length() && Character.isDigit(expression.charAt(index))) { 64 | sb.append(expression.charAt(index)); 65 | index++; 66 | } 67 | 68 | return Double.parseDouble(sb.toString()); 69 | } 70 | 71 | // Parse and return the next operator in the expression 72 | private static char parseOperator() { 73 | char operator = expression.charAt(index); 74 | index++; 75 | return operator; 76 | } 77 | } 78 | ``` 79 | 80 | In the above example, we have an `ExpressionParser` class that uses recursive descent parsing to evaluate arithmetic expressions. The main steps involved in the parsing process are as follows: 81 | 82 | 1. Read the expression from the user as a string. 83 | 2. Initialize the `index` variable to 0 to start parsing from the beginning of the expression. 84 | 3. The `evaluateExpression` method is the entry point for parsing. It uses two lists, `operands` and `operators`, to store the parsed operands and operators, respectively. 85 | 4. Inside the `evaluateExpression` method, we iterate through the expression character by character until we reach the end. 86 | 5. If the current character is a digit, we call the `parseOperand` method to extract the operand and add it to the `operands` list. 87 | 6. If the current character is an operator, we call the `parseOperator` method to extract the operator and add it to the `operators` list. 88 | 7. After parsing all the operands and operators, we perform the arithmetic operations according to the operator precedence and calculate the final result. 89 | 8. The `parseOperand` method reads the digits from the expression until it encounters a non-digit character, builds 90 | 91 | a string representation of the operand, and converts it to a `double` value. 92 | 9. The `parseOperator` method simply returns the current character as the operator and increments the `index` to move to the next character in the expression. 93 | 10. Finally, we print the result of evaluating the expression. 94 | 95 | You can modify and extend this example to handle more complex expressions, different operators, parentheses, and other features as required. 96 | -------------------------------------------------------------------------------- /Day_07/Queue_Example.java: -------------------------------------------------------------------------------- 1 | package Day_07; 2 | //www.codeswithpankaj.com 3 | //www.p4n.in 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | import java.util.NoSuchElementException; 7 | 8 | // Queue class 9 | class QueueExample { 10 | private Queue queue; 11 | 12 | public QueueExample() { 13 | queue = new LinkedList<>(); 14 | } 15 | 16 | public void enqueue(int value) { 17 | queue.offer(value); 18 | } 19 | 20 | public int dequeue() { 21 | if (isEmpty()) { 22 | throw new NoSuchElementException("Queue is empty. Cannot dequeue element."); 23 | } 24 | return queue.poll(); 25 | } 26 | 27 | public int peek() { 28 | if (isEmpty()) { 29 | throw new NoSuchElementException("Queue is empty. Cannot peek element."); 30 | } 31 | return queue.peek(); 32 | } 33 | 34 | public boolean isEmpty() { 35 | return queue.isEmpty(); 36 | } 37 | 38 | public int size() { 39 | return queue.size(); 40 | } 41 | } 42 | 43 | // Example usage 44 | public class Queue_Example { 45 | public static void main(String[] args) { 46 | QueueExample queue = new QueueExample(); 47 | 48 | queue.enqueue(1); 49 | queue.enqueue(2); 50 | queue.enqueue(3); 51 | 52 | System.out.println(queue.dequeue()); // Output: 1 53 | System.out.println(queue.peek()); // Output: 2 54 | System.out.println(queue.isEmpty()); // Output: false 55 | System.out.println(queue.size()); // Output: 2 56 | 57 | queue.enqueue(4); 58 | queue.enqueue(5); 59 | 60 | System.out.println(queue.dequeue()); // Output: 2 61 | System.out.println(queue.dequeue()); // Output: 3 62 | System.out.println(queue.isEmpty()); // Output: false 63 | System.out.println(queue.size()); // Output: 2 64 | 65 | System.out.println(queue.dequeue()); // Output: 4 66 | System.out.println(queue.dequeue()); // Output: 5 67 | System.out.println(queue.isEmpty()); // Output: true 68 | 69 | // Trying to dequeue from an empty queue 70 | try { 71 | System.out.println(queue.dequeue()); 72 | } catch (NoSuchElementException e) { 73 | System.out.println("Error: " + e.getMessage()); // Output: Error: Queue is empty. Cannot dequeue element. 74 | } 75 | } 76 | } 77 | //www.p4n.in 78 | -------------------------------------------------------------------------------- /Day_07/README.md: -------------------------------------------------------------------------------- 1 | ## Implement a queue in Java for Data Structures and Algorithms (DSA) purposes. 2 | 3 | In Java, a queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. It allows for inserting elements at one end, called the rear or tail, and removing elements from the other end, called the front or head. 4 | 5 | Here's an example of creating and using a queue in Java: 6 | 7 | ```java 8 | //@p4n.in 9 | import java.util.LinkedList; 10 | import java.util.Queue; 11 | 12 | public class QueueExample { 13 | public static void main(String[] args) { 14 | // Creating a queue 15 | Queue queue = new LinkedList<>(); 16 | 17 | // Enqueuing elements into the queue 18 | queue.offer(10); 19 | queue.offer(20); 20 | queue.offer(30); 21 | 22 | // Peeking the front element 23 | int frontElement = queue.peek(); 24 | System.out.println("Front element: " + frontElement); // Output: 10 25 | 26 | // Dequeuing elements from the queue 27 | int dequeuedElement = queue.poll(); 28 | System.out.println("Dequeued element: " + dequeuedElement); // Output: 10 29 | 30 | // Checking if the queue is empty 31 | boolean isEmpty = queue.isEmpty(); 32 | System.out.println("Is queue empty? " + isEmpty); // Output: false 33 | 34 | // Getting the size of the queue 35 | int size = queue.size(); 36 | System.out.println("Queue size: " + size); // Output: 2 37 | } 38 | } 39 | ``` 40 | 41 | In the example above, we use the built-in `Queue` interface provided by Java's standard library (`java.util.Queue`). This interface provides an implementation of a queue data structure. 42 | 43 | To create a queue, we instantiate an object of a class that implements the `Queue` interface. In the example, we use the `LinkedList` class as the implementation of the queue. 44 | 45 | We can enqueue elements into the queue using the `offer` method. For example, `queue.offer(10)` enqueues the element 10 into the queue, followed by enqueuing 20 and 30. 46 | 47 | To access the front element of the queue without removing it, we can use the `peek` method, as shown in `int frontElement = queue.peek();`. This retrieves the front element (which is 10 in this case) without modifying the queue. 48 | 49 | To remove and retrieve the front element from the queue, we use the `poll` method, as shown in `int dequeuedElement = queue.poll();`. This removes the front element (which is 10) from the queue and returns it. 50 | 51 | We can check if the queue is empty using the `isEmpty` method, which returns `true` if the queue is empty and `false` otherwise. 52 | 53 | The `size` method gives the current size of the queue, indicating the number of elements present in it. 54 | 55 | It's important to note that there are different implementations of queues in Java's standard library, such as `LinkedList`, `ArrayDeque`, and `PriorityQueue`. Each implementation has its own characteristics and is suitable for different scenarios, so you can choose the one that best fits your needs. 56 | -------------------------------------------------------------------------------- /Day_08/PriorityQueueExample.java: -------------------------------------------------------------------------------- 1 | package Day_08; 2 | //@p4n.in 3 | //codeswithpankaj.com 4 | import java.util.PriorityQueue; 5 | 6 | class Task implements Comparable { 7 | private String name; 8 | private int priority; 9 | 10 | public Task(String name, int priority) { 11 | this.name = name; 12 | this.priority = priority; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public int getPriority() { 20 | return priority; 21 | } 22 | 23 | @Override 24 | public int compareTo(Task other) { 25 | // Higher priority tasks should come first 26 | return Integer.compare(other.getPriority(), this.priority); 27 | } 28 | } 29 | 30 | public class PriorityQueueExample { 31 | public static void main(String[] args) { 32 | // Create a priority queue of tasks 33 | PriorityQueue taskQueue = new PriorityQueue<>(); 34 | 35 | // Add tasks to the priority queue 36 | taskQueue.add(new Task("Task 1", 5)); 37 | taskQueue.add(new Task("Task 2", 3)); 38 | taskQueue.add(new Task("Task 3", 8)); 39 | taskQueue.add(new Task("Task 4", 1)); 40 | 41 | // Process tasks in order of priority 42 | while (!taskQueue.isEmpty()) { 43 | Task task = taskQueue.poll(); 44 | System.out.println("Processing task: " + task.getName() + ", Priority: " + task.getPriority()); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Day_08/README.md: -------------------------------------------------------------------------------- 1 | # Priority Queue using Java 2 | 3 | implementing a priority queue using Java. In Java, you can use the `PriorityQueue` class from the `java.util` package to create a priority queue. 4 | 5 | A priority queue is a data structure that stores elements in a certain order based on their priorities. The element with the highest priority is always at the front of the queue and is the first one to be dequeued. 6 | 7 | Here's an example of how you can use the `PriorityQueue` class to implement a priority queue in Java: 8 | 9 | ```java 10 | import java.util.PriorityQueue; 11 | //@p4n.in 12 | public class PriorityQueueExample { 13 | public static void main(String[] args) { 14 | // Create a priority queue 15 | PriorityQueue pq = new PriorityQueue<>(); 16 | 17 | // Add elements to the priority queue 18 | pq.add(5); 19 | pq.add(3); 20 | pq.add(8); 21 | pq.add(1); 22 | 23 | // Print the elements of the priority queue 24 | System.out.println("Priority Queue: " + pq); 25 | 26 | // Remove the element with the highest priority (minimum value) 27 | int highestPriority = pq.poll(); 28 | System.out.println("Element with highest priority: " + highestPriority); 29 | 30 | // Print the elements of the priority queue after removing the highest priority element 31 | System.out.println("Priority Queue after poll(): " + pq); 32 | } 33 | } 34 | ``` 35 | 36 | Output: 37 | ``` 38 | Priority Queue: [1, 3, 8, 5] 39 | Element with highest priority: 1 40 | Priority Queue after poll(): [3, 5, 8] 41 | ``` 42 | 43 | In the above example, we first create a `PriorityQueue` object called `pq`. We then add elements to the priority queue using the `add()` method. The elements are automatically ordered based on their natural ordering (in this case, the minimum value is given the highest priority). 44 | 45 | We can retrieve and remove the element with the highest priority using the `poll()` method. The `poll()` method removes the head of the queue and returns it. In this example, we store the highest priority element in the `highestPriority` variable and print it. 46 | 47 | Finally, we print the updated priority queue after removing the highest priority element. 48 | 49 | You can use the `PriorityQueue` class in Java to implement various algorithms and data structures that require prioritization, such as Dijkstra's algorithm or Huffman coding. 50 | -------------------------------------------------------------------------------- /Day_09/BinarySearchTreeExample.java: -------------------------------------------------------------------------------- 1 | package Day_09; 2 | //@p4n.in 3 | //codeswithpankaj.com 4 | class TreeNode { 5 | int value; 6 | TreeNode left; 7 | TreeNode right; 8 | 9 | public TreeNode(int value) { 10 | this.value = value; 11 | this.left = null; 12 | this.right = null; 13 | } 14 | } 15 | 16 | class BinarySearchTree { 17 | private TreeNode root; 18 | 19 | public BinarySearchTree() { 20 | this.root = null; 21 | } 22 | 23 | public void insert(int value) { 24 | root = insertRecursive(root, value); 25 | } 26 | 27 | private TreeNode insertRecursive(TreeNode current, int value) { 28 | if (current == null) { 29 | return new TreeNode(value); 30 | } 31 | 32 | if (value < current.value) { 33 | current.left = insertRecursive(current.left, value); 34 | } else if (value > current.value) { 35 | current.right = insertRecursive(current.right, value); 36 | } 37 | 38 | return current; 39 | } 40 | 41 | public boolean search(int value) { 42 | return searchRecursive(root, value); 43 | } 44 | 45 | private boolean searchRecursive(TreeNode current, int value) { 46 | if (current == null) { 47 | return false; 48 | } 49 | 50 | if (value == current.value) { 51 | return true; 52 | } 53 | 54 | if (value < current.value) { 55 | return searchRecursive(current.left, value); 56 | } else { 57 | return searchRecursive(current.right, value); 58 | } 59 | } 60 | 61 | public void inorderTraversal() { 62 | inorderTraversalRecursive(root); 63 | } 64 | 65 | private void inorderTraversalRecursive(TreeNode current) { 66 | if (current != null) { 67 | inorderTraversalRecursive(current.left); 68 | System.out.print(current.value + " "); 69 | inorderTraversalRecursive(current.right); 70 | } 71 | } 72 | } 73 | 74 | public class BinarySearchTreeExample { 75 | public static void main(String[] args) { 76 | BinarySearchTree bst = new BinarySearchTree(); 77 | bst.insert(50); 78 | bst.insert(30); 79 | bst.insert(20); 80 | bst.insert(40); 81 | bst.insert(70); 82 | bst.insert(60); 83 | bst.insert(80); 84 | 85 | System.out.println("Inorder Traversal:"); 86 | bst.inorderTraversal(); 87 | 88 | int searchValue = 40; 89 | if (bst.search(searchValue)) { 90 | System.out.println("\n" + searchValue + " exists in the tree."); 91 | } else { 92 | System.out.println("\n" + searchValue + " does not exist in the tree."); 93 | } 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /Day_09/README.md: -------------------------------------------------------------------------------- 1 | # Trees 2 | 3 | 4 | Trees are a fundamental data structure in computer science. In Java, you can represent a tree using a class that defines the structure of a tree node. 5 | 6 | Here's an example of how you can create a simple binary tree in Java: 7 | 8 | ```java 9 | class TreeNode { 10 | int value; 11 | TreeNode left; 12 | TreeNode right; 13 | 14 | public TreeNode(int value) { 15 | this.value = value; 16 | this.left = null; 17 | this.right = null; 18 | } 19 | } 20 | 21 | public class BinaryTreeExample { 22 | public static void main(String[] args) { 23 | // Create the tree 24 | TreeNode root = new TreeNode(1); 25 | root.left = new TreeNode(2); 26 | root.right = new TreeNode(3); 27 | root.left.left = new TreeNode(4); 28 | root.left.right = new TreeNode(5); 29 | 30 | // Perform operations on the tree 31 | System.out.println("Inorder Traversal:"); 32 | inorderTraversal(root); 33 | 34 | System.out.println("\nPreorder Traversal:"); 35 | preorderTraversal(root); 36 | 37 | System.out.println("\nPostorder Traversal:"); 38 | postorderTraversal(root); 39 | } 40 | 41 | // Inorder traversal 42 | public static void inorderTraversal(TreeNode node) { 43 | if (node != null) { 44 | inorderTraversal(node.left); 45 | System.out.print(node.value + " "); 46 | inorderTraversal(node.right); 47 | } 48 | } 49 | 50 | // Preorder traversal 51 | public static void preorderTraversal(TreeNode node) { 52 | if (node != null) { 53 | System.out.print(node.value + " "); 54 | preorderTraversal(node.left); 55 | preorderTraversal(node.right); 56 | } 57 | } 58 | 59 | // Postorder traversal 60 | public static void postorderTraversal(TreeNode node) { 61 | if (node != null) { 62 | postorderTraversal(node.left); 63 | postorderTraversal(node.right); 64 | System.out.print(node.value + " "); 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | Output: 71 | ``` 72 | Inorder Traversal: 73 | 4 2 5 1 3 74 | Preorder Traversal: 75 | 1 2 4 5 3 76 | Postorder Traversal: 77 | 4 5 2 3 1 78 | ``` 79 | 80 | In the above example, we define a class `TreeNode` that represents a node in the binary tree. Each node has an integer value, and left and right child nodes. 81 | 82 | In the `BinaryTreeExample` class, we create a binary tree by creating instances of `TreeNode` and connecting them to form a tree structure. In this example, we create a binary tree with values 1, 2, 3, 4, and 5. 83 | 84 | We then perform three common tree traversal operations on the binary tree: 85 | 86 | 1. Inorder Traversal: In this traversal, we visit the left subtree, then the current node, and finally the right subtree. We use a recursive function `inorderTraversal()` to perform the traversal. 87 | 88 | 2. Preorder Traversal: In this traversal, we visit the current node, then the left subtree, and finally the right subtree. We use a recursive function `preorderTraversal()` to perform the traversal. 89 | 90 | 3. Postorder Traversal: In this traversal, we visit the left subtree, then the right subtree, and finally the current node. We use a recursive function `postorderTraversal()` to perform the traversal. 91 | 92 | Each traversal function checks if the current node is `null` and recursively calls itself for the left and right subtrees. It then performs the necessary operations on the current node (printing its value in this case) according to the specified traversal order. 93 | 94 | These three traversal methods demonstrate how you can traverse a binary tree and perform operations on its nodes. 95 | -------------------------------------------------------------------------------- /Day_10/HashTable$Entry.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_10/HashTable$Entry.class -------------------------------------------------------------------------------- /Day_10/HashTable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pankaj-Str/Learn-Data-Structures-JAVA/9983d6a98fb8a162f49277990929a2026b6c1121/Day_10/HashTable.class -------------------------------------------------------------------------------- /Day_10/HashTable.java: -------------------------------------------------------------------------------- 1 | package Day_10; 2 | //@p4n.in 3 | //codeswithpankaj.com 4 | import java.util.HashMap; 5 | 6 | class HashTable{ 7 | 8 | 9 | public static void main(String[] arg){ 10 | 11 | // create a new hash map instance 12 | HashMap hashMap = new HashMap<>(); 13 | // insrting key and value pairs into the hash table 14 | hashMap.put("java",1001); 15 | hashMap.put("C++",1002); 16 | hashMap.put("C",1003); 17 | hashMap.put("Python",1004); 18 | hashMap.put("JavaScript",1005); 19 | 20 | // test print 21 | System.out.println("test output - \n"+hashMap); 22 | 23 | // accessing value using key 24 | 25 | System.out.println("course id - "+hashMap.get("java")); 26 | System.out.println(" c++ course id "+hashMap.get("C++")); 27 | 28 | //updating value of keys.. 29 | hashMap.put("C++", 45001); 30 | System.out.println("update go in hashmap : "+ hashMap.get("C++")); 31 | 32 | // checking if key exists in the hash table 33 | 34 | String key = "java"; 35 | if(hashMap.containsKey(key)){ 36 | System.out.println(key+"= exists in the hash table... "); 37 | }else{ 38 | System.out.println(key+" = does not exists in the hash table ..."); 39 | } 40 | // removing a key value pair from the hash table 41 | 42 | hashMap.remove("C++"); 43 | System.out.println("size of the hash table after remove .. "+hashMap.size()); 44 | 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /Day_10/HashTable_Example1.java: -------------------------------------------------------------------------------- 1 | package Day_10; 2 | 3 | import java.util.LinkedList; 4 | 5 | // Define a class for the hash table 6 | public class HashTable_Example1 { 7 | private static final int DEFAULT_CAPACITY = 10; 8 | private LinkedList>[] table; 9 | private int size; 10 | 11 | // Define a class for the key-value pair (Entry) 12 | private static class Entry { 13 | K key; 14 | V value; 15 | 16 | Entry(K key, V value) { 17 | this.key = key; 18 | this.value = value; 19 | } 20 | } 21 | 22 | // Constructor to initialize the hash table with default capacity 23 | public HashTable_Example1() { 24 | this(DEFAULT_CAPACITY); 25 | } 26 | 27 | // Constructor to initialize the hash table with a custom capacity 28 | public HashTable_Example1(int capacity) { 29 | table = new LinkedList[capacity]; 30 | for (int i = 0; i < capacity; i++) { 31 | table[i] = new LinkedList<>(); 32 | } 33 | size = 0; 34 | } 35 | 36 | // Hash function to convert the key into an index 37 | private int hash(K key) { 38 | return Math.abs(key.hashCode()) % table.length; 39 | } 40 | 41 | // Put a key-value pair into the hash table 42 | public void put(K key, V value) { 43 | int index = hash(key); 44 | LinkedList> bucket = table[index]; 45 | 46 | for (Entry entry : bucket) { 47 | if (entry.key.equals(key)) { 48 | entry.value = value; 49 | return; 50 | } 51 | } 52 | 53 | bucket.add(new Entry<>(key, value)); 54 | size++; 55 | 56 | // Resize the hash table if the load factor exceeds a threshold (e.g., 0.75) 57 | if ((double) size / table.length > 0.75) { 58 | resize(); 59 | } 60 | } 61 | 62 | // Get the value associated with a given key 63 | public V get(K key) { 64 | int index = hash(key); 65 | LinkedList> bucket = table[index]; 66 | 67 | for (Entry entry : bucket) { 68 | if (entry.key.equals(key)) { 69 | return entry.value; 70 | } 71 | } 72 | 73 | return null; // Key not found 74 | } 75 | 76 | // Remove the key-value pair from the hash table 77 | public void remove(K key) { 78 | int index = hash(key); 79 | LinkedList> bucket = table[index]; 80 | 81 | for (Entry entry : bucket) { 82 | if (entry.key.equals(key)) { 83 | bucket.remove(entry); 84 | size--; 85 | return; 86 | } 87 | } 88 | } 89 | 90 | // Check if the hash table contains the given key 91 | public boolean containsKey(K key) { 92 | int index = hash(key); 93 | LinkedList> bucket = table[index]; 94 | 95 | for (Entry entry : bucket) { 96 | if (entry.key.equals(key)) { 97 | return true; 98 | } 99 | } 100 | 101 | return false; 102 | } 103 | 104 | // Resize the hash table when the load factor exceeds the threshold 105 | private void resize() { 106 | int newCapacity = table.length * 2; 107 | LinkedList>[] newTable = new LinkedList[newCapacity]; 108 | 109 | for (int i = 0; i < newCapacity; i++) { 110 | newTable[i] = new LinkedList<>(); 111 | } 112 | 113 | for (LinkedList> bucket : table) { 114 | for (Entry entry : bucket) { 115 | int newIndex = Math.abs(entry.key.hashCode()) % newCapacity; 116 | newTable[newIndex].add(entry); 117 | } 118 | } 119 | 120 | table = newTable; 121 | } 122 | 123 | // Get the current size of the hash table 124 | public int size() { 125 | return size; 126 | } 127 | 128 | // Check if the hash table is empty 129 | public boolean isEmpty() { 130 | return size == 0; 131 | } 132 | 133 | // Test the implementation of the hash table 134 | public static void main(String[] args) { 135 | HashTable_Example1 hashMap = new HashTable_Example1<>(); 136 | 137 | hashMap.put("Alice", 25); 138 | hashMap.put("Bob", 30); 139 | hashMap.put("Charlie", 22); 140 | hashMap.put("David", 28); 141 | hashMap.put("Eve", 35); 142 | 143 | System.out.println("Age of Alice: " + hashMap.get("Alice")); // Output: Age of Alice: 25 144 | System.out.println("Age of Charlie: " + hashMap.get("Charlie")); // Output: Age of Charlie: 22 145 | 146 | hashMap.put("Bob", 31); // Bob turned 31 147 | System.out.println("Updated age of Bob: " + hashMap.get("Bob")); // Output: Updated age of Bob: 31 148 | 149 | if (hashMap.containsKey("Eve")) { 150 | System.out.println("Eve exists in the hash table."); 151 | } else { 152 | System.out.println("Eve does not exist in the hash table."); 153 | } 154 | 155 | hashMap.remove("David"); 156 | System.out.println("Size of the hash table after removing David: " + hashMap.size()); // Output: Size of the hash table after removing David: 4 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /Day_10/README.md: -------------------------------------------------------------------------------- 1 | # Hash table data Structure in Java 2 | 3 | hash table data structure in Java. A hash table, also known as a hash map, is a data structure that allows you to store and retrieve key-value pairs efficiently. 4 | 5 | In Java, you can implement a hash table using an array of linked lists. Here's an example of a basic hash table implementation: 6 | 7 | ```java 8 | import java.util.LinkedList; 9 | 10 | public class HashTable { 11 | private LinkedList[] table; 12 | private int capacity; 13 | 14 | public HashTable(int capacity) { 15 | this.capacity = capacity; 16 | table = new LinkedList[capacity]; 17 | for (int i = 0; i < capacity; i++) { 18 | table[i] = new LinkedList<>(); 19 | } 20 | } 21 | 22 | public void put(int key, String value) { 23 | int index = hash(key); 24 | LinkedList list = table[index]; 25 | 26 | for (Entry entry : list) { 27 | if (entry.getKey() == key) { 28 | entry.setValue(value); 29 | return; 30 | } 31 | } 32 | 33 | list.add(new Entry(key, value)); 34 | } 35 | 36 | public String get(int key) { 37 | int index = hash(key); 38 | LinkedList list = table[index]; 39 | 40 | for (Entry entry : list) { 41 | if (entry.getKey() == key) { 42 | return entry.getValue(); 43 | } 44 | } 45 | 46 | return null; 47 | } 48 | 49 | public void remove(int key) { 50 | int index = hash(key); 51 | LinkedList list = table[index]; 52 | 53 | for (Entry entry : list) { 54 | if (entry.getKey() == key) { 55 | list.remove(entry); 56 | return; 57 | } 58 | } 59 | } 60 | 61 | private int hash(int key) { 62 | return key % capacity; 63 | } 64 | 65 | private class Entry { 66 | private int key; 67 | private String value; 68 | 69 | public Entry(int key, String value) { 70 | this.key = key; 71 | this.value = value; 72 | } 73 | 74 | public int getKey() { 75 | return key; 76 | } 77 | 78 | public String getValue() { 79 | return value; 80 | } 81 | 82 | public void setValue(String value) { 83 | this.value = value; 84 | } 85 | } 86 | } 87 | ``` 88 | 89 | In this implementation, we create an array of linked lists called `table`. The `capacity` parameter determines the size of the hash table. Each linked list represents a bucket in the hash table. 90 | 91 | The `put` method takes a key-value pair and stores it in the hash table. If a key already exists, it updates the corresponding value. The `get` method retrieves the value associated with a given key. The `remove` method removes a key-value pair from the hash table. 92 | 93 | The `hash` method calculates the index in the array for a given key. In this example, we use the modulo operator (`%`) to ensure the index falls within the valid range of the array. 94 | 95 | The `Entry` class represents a key-value pair stored in the hash table. It contains methods to access and modify the key and value. 96 | 97 | Note that this is a simplified implementation for demonstration purposes. In practice, you may need to handle collisions (when two keys produce the same index) using techniques like separate chaining or open addressing. 98 | 99 | # An example that demonstrates the usage of the hash table implementation in Java: 100 | 101 | ```java 102 | public class HashTableExample { 103 | public static void main(String[] args) { 104 | HashTable hashTable = new HashTable(10); 105 | 106 | // Adding key-value pairs to the hash table 107 | hashTable.put(1, "John"); 108 | hashTable.put(2, "Jane"); 109 | hashTable.put(3, "Mike"); 110 | hashTable.put(4, "Emily"); 111 | 112 | // Retrieving values from the hash table 113 | System.out.println(hashTable.get(2)); // Output: Jane 114 | System.out.println(hashTable.get(4)); // Output: Emily 115 | 116 | // Updating a value in the hash table 117 | hashTable.put(4, "Emma"); 118 | System.out.println(hashTable.get(4)); // Output: Emma 119 | 120 | // Removing a key-value pair from the hash table 121 | hashTable.remove(2); 122 | System.out.println(hashTable.get(2)); // Output: null 123 | } 124 | } 125 | ``` 126 | 127 | In this example, we create a `HashTable` object with a capacity of 10. Then, we add some key-value pairs to the hash table using the `put` method. We can retrieve values from the hash table using the `get` method. We can also update the value associated with a key using the `put` method again. Finally, we remove a key-value pair using the `remove` method. 128 | 129 | Note that this is a simplified example to demonstrate the usage of the hash table. In a real-world scenario, you might want to handle collisions and consider other factors like resizing the hash table when it becomes too full. 130 | -------------------------------------------------------------------------------- /Day_11/MaxHeap.java: -------------------------------------------------------------------------------- 1 | package Day_11; 2 | //@p4n.in 3 | //www.codeswithpankaj.com 4 | import java.util.Arrays; 5 | 6 | public class MaxHeap { 7 | private int[] heap; 8 | private int size; 9 | private int capacity; 10 | 11 | public MaxHeap(int capacity) { 12 | this.capacity = capacity; 13 | this.size = 0; 14 | this.heap = new int[capacity]; 15 | } 16 | 17 | public int getSize() { 18 | return size; 19 | } 20 | 21 | public boolean isEmpty() { 22 | return size == 0; 23 | } 24 | 25 | public void insert(int value) { 26 | if (size == capacity) { 27 | throw new IllegalStateException("Heap is full. Cannot insert more elements."); 28 | } 29 | 30 | heap[size] = value; 31 | heapifyUp(size); 32 | size++; 33 | } 34 | 35 | public int removeMax() { 36 | if (isEmpty()) { 37 | throw new IllegalStateException("Heap is empty. Cannot remove element."); 38 | } 39 | 40 | int max = heap[0]; 41 | heap[0] = heap[size - 1]; 42 | size--; 43 | heapifyDown(0); 44 | 45 | return max; 46 | } 47 | 48 | private void heapifyUp(int index) { 49 | int parentIndex = (index - 1) / 2; 50 | 51 | while (index > 0 && heap[index] > heap[parentIndex]) { 52 | swap(index, parentIndex); 53 | index = parentIndex; 54 | parentIndex = (index - 1) / 2; 55 | } 56 | } 57 | 58 | private void heapifyDown(int index) { 59 | int leftChildIndex = 2 * index + 1; 60 | int rightChildIndex = 2 * index + 2; 61 | int largestIndex = index; 62 | 63 | if (leftChildIndex < size && heap[leftChildIndex] > heap[largestIndex]) { 64 | largestIndex = leftChildIndex; 65 | } 66 | 67 | if (rightChildIndex < size && heap[rightChildIndex] > heap[largestIndex]) { 68 | largestIndex = rightChildIndex; 69 | } 70 | 71 | if (largestIndex != index) { 72 | swap(index, largestIndex); 73 | heapifyDown(largestIndex); 74 | } 75 | } 76 | 77 | private void swap(int i, int j) { 78 | int temp = heap[i]; 79 | heap[i] = heap[j]; 80 | heap[j] = temp; 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return Arrays.toString(Arrays.copyOfRange(heap, 0, size)); 86 | } 87 | 88 | public static void main(String[] args) { 89 | MaxHeap maxHeap = new MaxHeap(10); 90 | 91 | maxHeap.insert(5); 92 | maxHeap.insert(8); 93 | maxHeap.insert(3); 94 | maxHeap.insert(12); 95 | maxHeap.insert(2); 96 | maxHeap.insert(10); 97 | 98 | System.out.println("Max Heap: " + maxHeap); 99 | 100 | int max = maxHeap.removeMax(); 101 | System.out.println("Removed max element: " + max); 102 | System.out.println("Max Heap after removal: " + maxHeap); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Day_11/MaxHeap_01.java: -------------------------------------------------------------------------------- 1 | package Day_11; 2 | 3 | 4 | import java.util.*; 5 | 6 | public class MaxHeap_01 { 7 | private int[] heap; 8 | private int size; 9 | private int capacity; 10 | 11 | public MaxHeap_01(int capacity) { 12 | this.capacity = capacity; 13 | this.size = 0; 14 | this.heap = new int[capacity]; 15 | } 16 | 17 | private int getParentIndex(int index) { 18 | return (index - 1) / 2; 19 | } 20 | 21 | private int getLeftChildIndex(int index) { 22 | return 2 * index + 1; 23 | } 24 | 25 | private int getRightChildIndex(int index) { 26 | return 2 * index + 2; 27 | } 28 | 29 | private void swap(int index1, int index2) { 30 | int temp = heap[index1]; 31 | heap[index1] = heap[index2]; 32 | heap[index2] = temp; 33 | } 34 | 35 | private void heapifyUp(int index) { 36 | int parentIndex = getParentIndex(index); 37 | if (parentIndex >= 0 && heap[index] > heap[parentIndex]) { 38 | swap(index, parentIndex); 39 | heapifyUp(parentIndex); 40 | } 41 | } 42 | 43 | private void heapifyDown(int index) { 44 | int leftChildIndex = getLeftChildIndex(index); 45 | int rightChildIndex = getRightChildIndex(index); 46 | int largestIndex = index; 47 | 48 | if (leftChildIndex < size && heap[leftChildIndex] > heap[largestIndex]) 49 | largestIndex = leftChildIndex; 50 | 51 | if (rightChildIndex < size && heap[rightChildIndex] > heap[largestIndex]) 52 | largestIndex = rightChildIndex; 53 | 54 | if (largestIndex != index) { 55 | swap(index, largestIndex); 56 | heapifyDown(largestIndex); 57 | } 58 | } 59 | 60 | public void insert(int value) { 61 | if (size >= capacity) 62 | throw new IllegalStateException("Heap is full"); 63 | 64 | heap[size] = value; 65 | heapifyUp(size); 66 | size++; 67 | } 68 | 69 | public int extractMax() { 70 | if (size == 0) 71 | throw new IllegalStateException("Heap is empty"); 72 | 73 | int maxValue = heap[0]; 74 | heap[0] = heap[size - 1]; 75 | size--; 76 | heapifyDown(0); 77 | return maxValue; 78 | } 79 | 80 | public void printHeap() { 81 | System.out.println(Arrays.toString(Arrays.copyOfRange(heap, 0, size))); 82 | } 83 | 84 | public static void main(String[] args) { 85 | MaxHeap_01 maxHeap = new MaxHeap_01(10); 86 | maxHeap.insert(4); 87 | maxHeap.insert(9); 88 | maxHeap.insert(2); 89 | maxHeap.insert(7); 90 | maxHeap.insert(5); 91 | 92 | System.out.print("Max Heap: "); 93 | maxHeap.printHeap(); 94 | 95 | int maxVal = maxHeap.extractMax(); 96 | System.out.println("Extracted Max Value: " + maxVal); 97 | 98 | System.out.print("Updated Max Heap: "); 99 | maxHeap.printHeap(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Day_11/README.md: -------------------------------------------------------------------------------- 1 | # Heap data structure 2 | 3 | How you can use the Heap data structure in Java to solve a specific problem. Let's consider the problem of finding the k largest elements in an array. 4 | 5 | ```java 6 | import java.util.Arrays; 7 | import java.util.PriorityQueue; 8 | //@p4n.in 9 | //www.codeswithpankaj.com 10 | public class KLargestElements { 11 | public static int[] findKLargest(int[] nums, int k) { 12 | // Create a min heap using PriorityQueue 13 | PriorityQueue minHeap = new PriorityQueue<>(); 14 | 15 | // Insert the first k elements into the min heap 16 | for (int i = 0; i < k; i++) { 17 | minHeap.offer(nums[i]); 18 | } 19 | 20 | // Iterate over the remaining elements 21 | for (int i = k; i < nums.length; i++) { 22 | int currentNum = nums[i]; 23 | 24 | // If the current number is greater than the root of the min heap 25 | // remove the root and insert the current number into the min heap 26 | if (currentNum > minHeap.peek()) { 27 | minHeap.poll(); 28 | minHeap.offer(currentNum); 29 | } 30 | } 31 | 32 | // Extract the k largest elements from the min heap 33 | int[] result = new int[k]; 34 | for (int i = 0; i < k; i++) { 35 | result[i] = minHeap.poll(); 36 | } 37 | 38 | return result; 39 | } 40 | 41 | public static void main(String[] args) { 42 | int[] nums = {5, 3, 8, 2, 9, 1}; 43 | int k = 3; 44 | 45 | int[] kLargest = findKLargest(nums, k); 46 | System.out.println("The " + k + " largest elements are: " + Arrays.toString(kLargest)); 47 | } 48 | } 49 | ``` 50 | 51 | In this example, we use a `PriorityQueue` (which is implemented as a min heap in Java) to solve the problem efficiently. The `findKLargest` method takes an array `nums` and an integer `k` as input and returns an array containing the `k` largest elements from the input array. 52 | 53 | Here's how the algorithm works: 54 | 55 | 1. We create a `PriorityQueue` named `minHeap`, which will serve as our min heap to store the `k` largest elements. 56 | 57 | 2. We iterate over the first `k` elements of the input array and insert them into the `minHeap` using the `offer` method. 58 | 59 | 3. Next, we iterate over the remaining elements of the input array starting from index `k`. For each element, we compare it with the root of the `minHeap`. If the element is larger than the root, we remove the root from the `minHeap` using `poll` and insert the current element into the `minHeap` using `offer`. 60 | 61 | 4. After processing all the elements, the `minHeap` will contain the `k` largest elements from the input array. 62 | 63 | 5. Finally, we extract the `k` largest elements from the `minHeap` and store them in an array named `result`. 64 | 65 | 6. We return the `result` array, which contains the `k` largest elements. 66 | 67 | In the `main` method, we test the `findKLargest` method with a sample input array `nums` and `k` value. We print the `k` largest elements using `Arrays.toString` for demonstration purposes. 68 | 69 | By using the Heap data structure, we can efficiently find the `k` largest elements in the array in `O(n log k)` time complexity, where `n` is the size of the input array. 70 | -------------------------------------------------------------------------------- /Day_12/Graph.java: -------------------------------------------------------------------------------- 1 | package Day_12; 2 | import java.util.*; 3 | 4 | class Graph { 5 | private Map> adjList; 6 | 7 | public Graph() { 8 | adjList = new HashMap<>(); 9 | } 10 | 11 | // Add a vertex to the graph 12 | public void addVertex(int vertex) { 13 | adjList.put(vertex, new ArrayList<>()); 14 | } 15 | 16 | // Add an edge between two vertices 17 | public void addEdge(int fromVertex, int toVertex) { 18 | if (!adjList.containsKey(fromVertex) || !adjList.containsKey(toVertex)) 19 | throw new IllegalArgumentException("Invalid vertices"); 20 | 21 | adjList.get(fromVertex).add(toVertex); 22 | adjList.get(toVertex).add(fromVertex); // For an undirected graph, remove this line for a directed graph 23 | } 24 | 25 | // Get all adjacent vertices of a given vertex 26 | public List getAdjacentVertices(int vertex) { 27 | return adjList.get(vertex); 28 | } 29 | 30 | // Print the graph 31 | public void printGraph() { 32 | for (int vertex : adjList.keySet()) { 33 | List neighbors = adjList.get(vertex); 34 | System.out.print(vertex + " -> "); 35 | for (int neighbor : neighbors) { 36 | System.out.print(neighbor + " "); 37 | } 38 | System.out.println(); 39 | } 40 | } 41 | 42 | public static void main(String[] args) { 43 | Graph graph = new Graph(); 44 | 45 | graph.addVertex(1); 46 | graph.addVertex(2); 47 | graph.addVertex(3); 48 | graph.addVertex(4); 49 | graph.addVertex(5); 50 | 51 | graph.addEdge(1, 2); 52 | graph.addEdge(1, 3); 53 | graph.addEdge(2, 3); 54 | graph.addEdge(3, 4); 55 | graph.addEdge(4, 5); 56 | 57 | graph.printGraph(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Day_12/Graph_Data_Structure.java: -------------------------------------------------------------------------------- 1 | package Day_12; 2 | // @p4n.in 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Stack; 6 | 7 | class Graph { 8 | private int numVertices; 9 | private List> adjacencyList; 10 | 11 | public Graph(int numVertices) { 12 | this.numVertices = numVertices; 13 | adjacencyList = new ArrayList<>(numVertices); 14 | for (int i = 0; i < numVertices; i++) { 15 | adjacencyList.add(new ArrayList<>()); 16 | } 17 | } 18 | 19 | public void addEdge(int source, int destination) { 20 | adjacencyList.get(source).add(destination); 21 | } 22 | 23 | public void DFS(int startVertex) { 24 | boolean[] visited = new boolean[numVertices]; 25 | Stack stack = new Stack<>(); 26 | stack.push(startVertex); 27 | 28 | while (!stack.isEmpty()) { 29 | int currentVertex = stack.pop(); 30 | 31 | if (!visited[currentVertex]) { 32 | System.out.print(currentVertex + " "); 33 | visited[currentVertex] = true; 34 | } 35 | 36 | List neighbors = adjacencyList.get(currentVertex); 37 | for (int neighbor : neighbors) { 38 | if (!visited[neighbor]) { 39 | stack.push(neighbor); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | 46 | public class Graph_Data_Structure{ 47 | public static void main(String[] args) { 48 | int numVertices = 5; 49 | Graph graph = new Graph(numVertices); 50 | 51 | graph.addEdge(0, 1); 52 | graph.addEdge(0, 2); 53 | graph.addEdge(1, 3); 54 | graph.addEdge(1, 4); 55 | graph.addEdge(2, 4); 56 | 57 | System.out.println("Depth-First Search (DFS) traversal:"); 58 | graph.DFS(0); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /Day_12/README.md: -------------------------------------------------------------------------------- 1 | # Graph Data Structure 2 | 3 | In computer science and graph theory, a graph is a data structure that represents a collection of interconnected nodes or vertices. It consists of a set of vertices and a set of edges that connect these vertices. 4 | 5 | There are two common ways to represent a graph: adjacency matrix and adjacency list. In this explanation, I'll focus on the adjacency list representation. 6 | 7 | In Java, you can implement a graph using the adjacency list representation using the following steps: 8 | 9 | 1. Start by creating a Graph class. This class will have instance variables to store the number of vertices and an adjacency list. 10 | 11 | 2. The constructor of the Graph class should take the number of vertices as a parameter. It initializes the adjacency list as an empty list with a size equal to the number of vertices. 12 | 13 | 3. Create a method called addEdge(source, destination) to add an edge between two vertices. This method takes the source and destination vertices as parameters. It adds the destination vertex to the list of neighbors for the source vertex in the adjacency list. 14 | 15 | 5. To implement graph traversal algorithms like Depth-First Search (DFS), you can create a method called DFS(startVertex) in the Graph class. This method performs the Depth-First Search algorithm on the graph starting from the given start vertex. It uses a stack to keep track of the vertices to visit. 16 | 17 | 6. Inside the DFS method, initialize a boolean array called visited with a size equal to the number of vertices. This array is used to keep track of visited vertices during the traversal. 18 | 19 | 7. Create a stack to store the vertices to visit. Push the start vertex onto the stack. 20 | 21 | 8. While the stack is not empty, perform the following steps: 22 | 23 | 1. Pop a vertex from the stack. 24 | 2. If the vertex has not been visited, mark it as visited and process it. 25 | 3. Print or perform any desired operation on the current vertex. 26 | 4. Get the neighbors of the current vertex from the adjacency list and iterate over them. 27 | 5. For each unvisited neighbor, push it onto the stack. 28 | 29 | 10. In the Main class or any other class, create an instance of the Graph class and add edges to it using the addEdge method. 30 | 31 | Finally, call the DFS method on the Graph object with a starting vertex to perform the Depth-First Search traversal. 32 | 33 | That's the general idea behind implementing a graph and performing graph traversal algorithms in Java. You can modify and extend the code according to your specific requirements. 34 | 35 | 36 | Implementing a graph data structure in Java using the adjacency list representation: 37 | 38 | ```java 39 | import java.util.ArrayList; 40 | import java.util.List; 41 | @p4n.in 42 | //codeswithpankaj.com 43 | 44 | class Graph { 45 | private int numVertices; 46 | private List> adjacencyList; 47 | 48 | public Graph(int numVertices) { 49 | this.numVertices = numVertices; 50 | adjacencyList = new ArrayList<>(numVertices); 51 | for (int i = 0; i < numVertices; i++) { 52 | adjacencyList.add(new ArrayList<>()); 53 | } 54 | } 55 | 56 | public void addEdge(int source, int destination) { 57 | adjacencyList.get(source).add(destination); 58 | adjacencyList.get(destination).add(source); // Uncomment for undirected graph 59 | } 60 | 61 | public List getNeighbors(int vertex) { 62 | return adjacencyList.get(vertex); 63 | } 64 | } 65 | ``` 66 | 67 | In this example, we have a `Graph` class that represents the graph data structure using the adjacency list representation. 68 | 69 | The constructor `Graph(int numVertices)` initializes the graph with the specified number of vertices. It creates an empty adjacency list with a size equal to the number of vertices. 70 | 71 | The method `addEdge(int source, int destination)` adds an edge between two vertices. It adds the destination vertex to the adjacency list of the source vertex. If you want to represent an undirected graph, you can uncomment the second line, which adds the source vertex to the adjacency list of the destination vertex as well. 72 | 73 | The method `getNeighbors(int vertex)` returns a list of neighbors for the given vertex. 74 | 75 | You can create an instance of the `Graph` class, add edges using the `addEdge` method, and retrieve neighbors using the `getNeighbors` method. 76 | 77 | Here's an example usage: 78 | 79 | ```java 80 | public class Main { 81 | public static void main(String[] args) { 82 | int numVertices = 5; 83 | Graph graph = new Graph(numVertices); 84 | 85 | graph.addEdge(0, 1); 86 | graph.addEdge(0, 2); 87 | graph.addEdge(1, 3); 88 | graph.addEdge(1, 4); 89 | graph.addEdge(2, 4); 90 | 91 | List neighbors = graph.getNeighbors(1); 92 | System.out.println("Neighbors of vertex 1:"); 93 | for (int neighbor : neighbors) { 94 | System.out.println(neighbor); 95 | } 96 | } 97 | } 98 | ``` 99 | 100 | In this example, we create a graph with 5 vertices and add some edges. Then, we retrieve the neighbors of vertex 1 using the `getNeighbors` method and print them. 101 | 102 | Output: 103 | ``` 104 | Neighbors of vertex 1: 105 | 0 106 | 3 107 | 4 108 | ``` 109 | 110 | The output shows the neighbors of vertex 1 in the graph. 111 | -------------------------------------------------------------------------------- /Day_13/LinearSearchExample.java: -------------------------------------------------------------------------------- 1 | public class LinearSearchExample{ 2 | 3 | public static int linearSearch(int[] arr , int target){ 4 | 5 | for (int i = 0; i < arr.length; i++) { 6 | if(arr[i] == target){ 7 | return i;// retrun the index where the target is found 8 | } 9 | } 10 | return -1; // retrun -1 if the tagert is not found in the array 11 | 12 | } 13 | public static void main(String[] args) { 14 | 15 | int[] arr = {10,20,30,40,50,60}; 16 | 17 | int tagert = 2; 18 | 19 | int index = linearSearch(arr, tagert); 20 | 21 | if(index != -1){ 22 | System.out.println("Target "+tagert+"found at index "+ index); 23 | }else{ 24 | System.out.println(" Target not Found ....in the array "); 25 | } 26 | 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /Day_13/README.md: -------------------------------------------------------------------------------- 1 | # DSA Java - Search techniques 2 | 3 | When it comes to implementing search techniques in Java for Data Structures and Algorithms (DSA), there are several commonly used algorithms. Here are a few popular search techniques: 4 | 5 | 1. Linear Search: 6 | - Linear search is the simplest search algorithm that sequentially checks each element of the data structure until a match is found. 7 | - It is commonly used for unsorted arrays or lists. 8 | - Java implementation: 9 | 10 | ```java 11 | public static int linearSearch(int[] arr, int target) { 12 | for (int i = 0; i < arr.length; i++) { 13 | if (arr[i] == target) { 14 | return i; // Found the target 15 | } 16 | } 17 | return -1; // Target not found 18 | } 19 | ``` 20 | 21 | 2. Binary Search: 22 | - Binary search is a fast search algorithm used on sorted arrays or lists by repeatedly dividing the search interval in half. 23 | - It is based on the principle of "divide and conquer." 24 | - Java implementation: 25 | 26 | ```java 27 | public static int binarySearch(int[] arr, int target) { 28 | int low = 0; 29 | int high = arr.length - 1; 30 | 31 | while (low <= high) { 32 | int mid = (low + high) / 2; 33 | if (arr[mid] == target) { 34 | return mid; // Found the target 35 | } else if (arr[mid] < target) { 36 | low = mid + 1; // Target is in the upper half 37 | } else { 38 | high = mid - 1; // Target is in the lower half 39 | } 40 | } 41 | return -1; // Target not found 42 | } 43 | ``` 44 | 45 | 3. Hashing: 46 | - Hashing is a technique that uses a hash function to map keys to array indices, allowing for efficient retrieval of data. 47 | - It is commonly used for dictionary-like data structures such as hash tables. 48 | - Java implementation using `HashMap`: 49 | 50 | ```java 51 | import java.util.HashMap; 52 | 53 | public class HashMapSearch { 54 | public static void main(String[] args) { 55 | HashMap map = new HashMap<>(); 56 | map.put("apple", 1); 57 | map.put("banana", 2); 58 | map.put("orange", 3); 59 | 60 | int value = map.getOrDefault("banana", -1); 61 | System.out.println(value); // Output: 2 62 | } 63 | } 64 | ``` 65 | 66 | These are just a few search techniques commonly used in DSA with Java. Depending on the problem and the data structure being used, other search algorithms like depth-first search (DFS) or breadth-first search (BFS) may also be applicable. 67 | -------------------------------------------------------------------------------- /Day_13/SearchExample.java: -------------------------------------------------------------------------------- 1 | 2 | //@p4n.in 3 | //codeswithpankaj.com 4 | 5 | public class SearchExample { 6 | public static void main(String[] args) { 7 | int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; 8 | int target = 12; 9 | 10 | int linearSearchIndex = linearSearch(arr, target); 11 | if (linearSearchIndex != -1) { 12 | System.out.println("Linear search: Found at index " + linearSearchIndex); 13 | } else { 14 | System.out.println("Linear search: Not found"); 15 | } 16 | 17 | int binarySearchIndex = binarySearch(arr, target); 18 | if (binarySearchIndex != -1) { 19 | System.out.println("Binary search: Found at index " + binarySearchIndex); 20 | } else { 21 | System.out.println("Binary search: Not found"); 22 | } 23 | } 24 | 25 | public static int linearSearch(int[] arr, int target) { 26 | for (int i = 0; i < arr.length; i++) { 27 | if (arr[i] == target) { 28 | return i; // Found the target 29 | } 30 | } 31 | return -1; // Target not found 32 | } 33 | 34 | public static int binarySearch(int[] arr, int target) { 35 | int low = 0; 36 | int high = arr.length - 1; 37 | 38 | while (low <= high) { 39 | int mid = (low + high) / 2; 40 | if (arr[mid] == target) { 41 | return mid; // Found the target 42 | } else if (arr[mid] < target) { 43 | low = mid + 1; // Target is in the upper half 44 | } else { 45 | high = mid - 1; // Target is in the lower half 46 | } 47 | } 48 | return -1; // Target not found 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Day_14/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package Day_14; 2 | public class BubbleSort { 3 | public static void bubbleSort(int[] arr) { 4 | int n = arr.length; 5 | boolean swapped; 6 | 7 | for (int i = 0; i < n - 1; i++) { 8 | swapped = false; 9 | for (int j = 0; j < n - i - 1; j++) { 10 | if (arr[j] > arr[j + 1]) { 11 | // Swap arr[j] and arr[j+1] 12 | int temp = arr[j]; 13 | arr[j] = arr[j + 1]; 14 | arr[j + 1] = temp; 15 | swapped = true; 16 | } 17 | } 18 | // If no two elements were swapped in the inner loop, the array is already sorted 19 | if (!swapped) { 20 | break; 21 | } 22 | } 23 | } 24 | 25 | public static void main(String[] args) { 26 | int[] arr = {64, 34, 25, 12, 22, 11, 90}; 27 | bubbleSort(arr); 28 | 29 | System.out.println("Sorted array:"); 30 | for (int num : arr) { 31 | System.out.print(num + " "); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Day_14/README.md: -------------------------------------------------------------------------------- 1 | # Implementing sorting techniques in Java 2 | 3 | Implementing sorting techniques in Java for Data Structures and Algorithms (DSA), there are several commonly used algorithms. Here are a few popular sorting techniques: 4 | 5 | 1. Bubble Sort: 6 | - Bubble sort is a simple comparison-based sorting algorithm that repeatedly swaps adjacent elements if they are in the wrong order. 7 | - It has a time complexity of O(n^2) in the worst case. 8 | - Java implementation: 9 | 10 | 11 | ```java 12 | 13 | public static void bubbleSort(int[] arr) { 14 | int n = arr.length; 15 | for (int i = 0; i < n - 1; i++) { 16 | for (int j = 0; j < n - i - 1; j++) { 17 | if (arr[j] > arr[j + 1]) { 18 | // Swap arr[j] and arr[j + 1] 19 | int temp = arr[j]; 20 | arr[j] = arr[j + 1]; 21 | arr[j + 1] = temp; 22 | } 23 | } 24 | } 25 | } 26 | ``` 27 | 28 | 2. Selection Sort: 29 | - Selection sort is an in-place comparison-based sorting algorithm that divides the array into a sorted and an unsorted region. 30 | - It repeatedly selects the minimum (or maximum) element from the unsorted region and swaps it with the leftmost unsorted element. 31 | - It has a time complexity of O(n^2) in the worst case. 32 | - Java implementation: 33 | 34 | 35 | ```java 36 | public static void selectionSort(int[] arr) { 37 | int n = arr.length; 38 | for (int i = 0; i < n - 1; i++) { 39 | int minIndex = i; 40 | for (int j = i + 1; j < n; j++) { 41 | if (arr[j] < arr[minIndex]) { 42 | minIndex = j; 43 | } 44 | } 45 | // Swap arr[i] and arr[minIndex] 46 | int temp = arr[i]; 47 | arr[i] = arr[minIndex]; 48 | arr[minIndex] = temp; 49 | } 50 | } 51 | ``` 52 | 53 | 3. Merge Sort: 54 | - Merge sort is a divide-and-conquer algorithm that recursively divides the array into two halves, sorts them independently, and then merges them. 55 | - It has a time complexity of O(n log n) in all cases. 56 | - Java implementation: 57 | 58 | 59 | ```java 60 | public static void mergeSort(int[] arr) { 61 | if (arr.length <= 1) { 62 | return; 63 | } 64 | 65 | int mid = arr.length / 2; 66 | int[] left = Arrays.copyOfRange(arr, 0, mid); 67 | int[] right = Arrays.copyOfRange(arr, mid, arr.length); 68 | 69 | mergeSort(left); 70 | mergeSort(right); 71 | 72 | merge(left, right, arr); 73 | } 74 | 75 | private static void merge(int[] left, int[] right, int[] arr) { 76 | int i = 0, j = 0, k = 0; 77 | 78 | while (i < left.length && j < right.length) { 79 | if (left[i] <= right[j]) { 80 | arr[k++] = left[i++]; 81 | } else { 82 | arr[k++] = right[j++]; 83 | } 84 | } 85 | 86 | while (i < left.length) { 87 | arr[k++] = left[i++]; 88 | } 89 | 90 | while (j < right.length) { 91 | arr[k++] = right[j++]; 92 | } 93 | } 94 | ``` 95 | 96 | These are just a few sorting techniques commonly used in DSA with Java. Depending on the requirements and the characteristics of the data, other sorting algorithms like insertion sort, quicksort, or heapsort may also be applicable. 97 | -------------------------------------------------------------------------------- /Day_14/SortingExample.java: -------------------------------------------------------------------------------- 1 | package Day_14; 2 | 3 | //@p4n.in 4 | //codeswithpankaj.com 5 | 6 | import java.util.Arrays; 7 | 8 | public class SortingExample { 9 | public static void main(String[] args) { 10 | int[] arr = { 5, 2, 8, 12, 1, 6 }; 11 | 12 | // Bubble Sort 13 | int[] bubbleSorted = bubbleSort(Arrays.copyOf(arr, arr.length)); 14 | System.out.println("Bubble Sort: " + Arrays.toString(bubbleSorted)); 15 | 16 | // Selection Sort 17 | int[] selectionSorted = selectionSort(Arrays.copyOf(arr, arr.length)); 18 | System.out.println("Selection Sort: " + Arrays.toString(selectionSorted)); 19 | 20 | // Merge Sort 21 | int[] mergeSorted = mergeSort(Arrays.copyOf(arr, arr.length)); 22 | System.out.println("Merge Sort: " + Arrays.toString(mergeSorted)); 23 | } 24 | 25 | public static int[] bubbleSort(int[] arr) { 26 | int n = arr.length; 27 | for (int i = 0; i < n - 1; i++) { 28 | for (int j = 0; j < n - i - 1; j++) { 29 | if (arr[j] > arr[j + 1]) { 30 | // Swap arr[j] and arr[j + 1] 31 | int temp = arr[j]; 32 | arr[j] = arr[j + 1]; 33 | arr[j + 1] = temp; 34 | } 35 | } 36 | } 37 | return arr; 38 | } 39 | 40 | public static int[] selectionSort(int[] arr) { 41 | int n = arr.length; 42 | for (int i = 0; i < n - 1; i++) { 43 | int minIndex = i; 44 | for (int j = i + 1; j < n; j++) { 45 | if (arr[j] < arr[minIndex]) { 46 | minIndex = j; 47 | } 48 | } 49 | // Swap arr[i] and arr[minIndex] 50 | int temp = arr[i]; 51 | arr[i] = arr[minIndex]; 52 | arr[minIndex] = temp; 53 | } 54 | return arr; 55 | } 56 | 57 | public static int[] mergeSort(int[] arr) { 58 | if (arr.length <= 1) { 59 | return arr; 60 | } 61 | 62 | int mid = arr.length / 2; 63 | int[] left = Arrays.copyOfRange(arr, 0, mid); 64 | int[] right = Arrays.copyOfRange(arr, mid, arr.length); 65 | 66 | left = mergeSort(left); 67 | right = mergeSort(right); 68 | 69 | return merge(left, right); 70 | } 71 | 72 | private static int[] merge(int[] left, int[] right) { 73 | int i = 0, j = 0, k = 0; 74 | int[] merged = new int[left.length + right.length]; 75 | 76 | while (i < left.length && j < right.length) { 77 | if (left[i] <= right[j]) { 78 | merged[k++] = left[i++]; 79 | } else { 80 | merged[k++] = right[j++]; 81 | } 82 | } 83 | 84 | while (i < left.length) { 85 | merged[k++] = left[i++]; 86 | } 87 | 88 | while (j < right.length) { 89 | merged[k++] = right[j++]; 90 | } 91 | 92 | return merged; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Day_15/BinarySearchRecursion.java: -------------------------------------------------------------------------------- 1 | package Day_15; 2 | 3 | public class BinarySearchRecursion { 4 | public static int binarySearch(int[] arr, int target, int left, int right) { 5 | if (left <= right) { 6 | int mid = left + (right - left) / 2; 7 | 8 | if (arr[mid] == target) { 9 | return mid; // Element found at index mid 10 | } else if (arr[mid] < target) { 11 | return binarySearch(arr, target, mid + 1, right); // Search right half 12 | } else { 13 | return binarySearch(arr, target, left, mid - 1); // Search left half 14 | } 15 | } 16 | return -1; // Element not found 17 | } 18 | 19 | public static void main(String[] args) { 20 | int[] arr = {2, 4, 6, 8, 10, 12, 14, 16}; 21 | int target = 10; 22 | int index = binarySearch(arr, target, 0, arr.length - 1); 23 | 24 | if (index != -1) { 25 | System.out.println("Element " + target + " found at index " + index); 26 | } else { 27 | System.out.println("Element not found in the array."); 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Day_15/README.md: -------------------------------------------------------------------------------- 1 | # DSA Java - Recursion 2 | 3 | Recursion is a programming technique where a function calls itself repeatedly to solve a problem by breaking it down into smaller, simpler subproblems. In the context of Data Structures and Algorithms (DSA), recursion is often used to solve problems that can be divided into smaller instances of the same problem. 4 | 5 | Recursion involves two key components: 6 | 7 | 1. Base Case: It is the condition or scenario for which the function does not make a recursive call and returns a specific value. It acts as a stopping criterion for the recursion and prevents infinite recursion. Without a base case, the recursive function would keep calling itself indefinitely. 8 | 9 | 2. Recursive Case: It is the scenario where the function makes one or more recursive calls to itself, solving a smaller instance of the problem. The function breaks down the original problem into smaller subproblems until it reaches the base case(s). 10 | 11 | The general flow of a recursive function can be summarized as follows: 12 | 13 | 1. Check if the base case is met. If so, return the base case value. 14 | 2. If the base case is not met, divide the original problem into smaller subproblems. 15 | 3. Solve each subproblem by making recursive calls to the function itself. 16 | 4. Combine the solutions of the subproblems to obtain the final result. 17 | 5. Return the result. 18 | 19 | Recursion is especially useful in solving problems that exhibit a recursive structure, such as tree traversals, graph traversal algorithms (e.g., depth-first search), and problems that involve repetitive computations. 20 | 21 | When using recursion, it's important to consider the efficiency of the recursive algorithm. In some cases, recursion may result in redundant computations and inefficient memory usage. Techniques such as memoization (caching previously computed results) or tail recursion optimization can be employed to improve the efficiency of recursive algorithms. 22 | 23 | ## Recursion is a powerful concept in programming and is widely used in Data Structures and Algorithms (DSA) to solve problems by breaking them down into smaller, more manageable subproblems. Here's an example that demonstrates the use of recursion in Java: 24 | 25 | ```java 26 | public class RecursionExample { 27 | public static void main(String[] args) { 28 | int n = 5; 29 | 30 | System.out.println("Factorial of " + n + " is: " + factorial(n)); 31 | 32 | int[] array = { 1, 2, 3, 4, 5 }; 33 | System.out.println("Sum of array elements: " + sumArray(array, array.length - 1)); 34 | 35 | int x = 5; 36 | System.out.println("Fibonacci number at position " + x + " is: " + fibonacci(x)); 37 | } 38 | 39 | public static int factorial(int n) { 40 | if (n == 0 || n == 1) { 41 | return 1; 42 | } 43 | return n * factorial(n - 1); 44 | } 45 | 46 | public static int sumArray(int[] arr, int index) { 47 | if (index < 0) { 48 | return 0; 49 | } 50 | return arr[index] + sumArray(arr, index - 1); 51 | } 52 | 53 | public static int fibonacci(int n) { 54 | if (n <= 1) { 55 | return n; 56 | } 57 | return fibonacci(n - 1) + fibonacci(n - 2); 58 | } 59 | } 60 | ``` 61 | 62 | In this example, we have three recursive methods: `factorial`, `sumArray`, and `fibonacci`. 63 | 64 | - The `factorial` method calculates the factorial of a number `n` by recursively multiplying `n` with the factorial of `n-1`, until the base case (`n = 0` or `n = 1`) is reached. 65 | 66 | - The `sumArray` method calculates the sum of an array of integers by recursively adding the element at the current index with the sum of the remaining elements in the array, until the base case (`index < 0`) is reached. 67 | 68 | - The `fibonacci` method calculates the Fibonacci number at position `n` by recursively summing the two previous Fibonacci numbers, until the base case (`n <= 1`) is reached. 69 | 70 | The `main` method demonstrates the usage of these recursive methods. It calls each method with appropriate arguments and displays the results using `System.out.println`. 71 | 72 | The output of the example will be: 73 | 74 | ``` 75 | Factorial of 5 is: 120 76 | Sum of array elements: 15 77 | Fibonacci number at position 5 is: 5 78 | ``` 79 | 80 | The recursive methods successfully solve their respective problems using recursion. It's important to define the base case(s) to ensure that the recursion terminates and to handle the base case(s) separately to avoid infinite recursion. 81 | -------------------------------------------------------------------------------- /Day_15/RecursionExample1.java: -------------------------------------------------------------------------------- 1 | package Day_15; 2 | // @p4n.in 3 | // codeswithpankaj.com 4 | 5 | public class RecursionExample1 { 6 | public static void main(String[] args) { 7 | int[] array = { 1, 2, 3, 4, 5 }; 8 | int sum = calculateSum(array, array.length - 1); 9 | System.out.println("Sum of array elements: " + sum); 10 | } 11 | 12 | public static int calculateSum(int[] arr, int index) { 13 | if (index < 0) { 14 | return 0; // Base case: Reached the end of the array, return 0 15 | } 16 | return arr[index] + calculateSum(arr, index - 1); // Recursive case: Add current element with the sum of remaining elements 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Day_15/RecursionExample2.java: -------------------------------------------------------------------------------- 1 | package Day_15; 2 | 3 | //@p4n.in 4 | // codeswithpankaj.com 5 | 6 | public class RecursionExample2 { 7 | public static void main(String[] args) { 8 | int n = 5; 9 | int factorial = calculateFactorial(n); 10 | System.out.println("Factorial of " + n + " is: " + factorial); 11 | } 12 | 13 | public static int calculateFactorial(int n) { 14 | if (n == 0 || n == 1) { 15 | return 1; // Base case: factorial of 0 or 1 is 1 16 | } 17 | return n * calculateFactorial(n - 1); // Recursive case: factorial(n) = n * factorial(n-1) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Data Structures JAVA 2 | This tutorial will give you great understanding on Data Structures concepts 3 | 4 | provide a brief explanation of some common data structures used in computer science and software development using Java. 5 | 6 | Certainly! I'll provide a brief explanation of some common data structures used in computer science and software development using Java. 7 | 8 | 1. Arrays: 9 | - Arrays are a fundamental data structure that store elements of the same type in contiguous memory locations. 10 | - In Java, arrays have a fixed size and can be accessed using index-based notation. 11 | - Example: 12 | ``` 13 | int[] numbers = {1, 2, 3, 4, 5}; 14 | ``` 15 | 2. Linked Lists: 16 | - Linked lists consist of nodes where each node contains data and a reference to the next node in the list. 17 | - Linked lists can be singly linked (with a reference to the next node) or doubly linked (with references to both the next and previous nodes). 18 | - Linked lists are dynamic in size and allow efficient insertion and deletion of elements. 19 | - Example: See the earlier examples of singly linked list and doubly linked list. 20 | 21 | 3. Stacks: 22 | - Stacks follow the Last-In-First-Out (LIFO) principle, where the last element inserted is the first one to be removed. 23 | - Elements are added and removed from one end called the top of the stack. 24 | - Stack operations include push (add an element to the top), pop (remove the top element), and peek (view the top element without removing it). 25 | - Example: See the earlier example of implementing a stack. 26 | 27 | 4. Queues: 28 | - Queues follow the First-In-First-Out (FIFO) principle, where the first element inserted is the first one to be removed. 29 | - Elements are added to one end called the rear, and removed from the other end called the front. 30 | - Queue operations include enqueue (add an element to the rear), dequeue (remove the front element), and peek (view the front element without removing it). 31 | - Example: See the earlier example of implementing a queue. 32 | 33 | 5. Trees: 34 | - Trees are hierarchical data structures composed of nodes connected by edges. 35 | - Each node can have child nodes, forming a parent-child relationship. 36 | - Trees have a root node at the top, and each node can have zero or more child nodes. 37 | - Special types of trees include binary trees (each node has at most two child nodes) and binary search trees (values are stored in a specific order for efficient searching). 38 | - Example: 39 | - Java's `java.util.TreeSet` and `java.util.TreeMap` implement tree-based data structures. 40 | 41 | 6. Graphs: 42 | - Graphs consist of vertices (nodes) and edges (connections) between the vertices. 43 | - Vertices can be connected in various ways, such as directed or undirected edges. 44 | - Graphs can be used to represent complex relationships between elements. 45 | - Example: Java's `java.util.HashMap` and `java.util.HashSet` can be used to represent graphs. 46 | 47 | 7. Hash Tables: 48 | - Hash tables, also known as hash maps, are data structures that store key-value pairs. 49 | - The key is used to compute a hash code, which is used to index the value in an underlying array. 50 | - Hash tables provide fast access and retrieval of values based on keys. 51 | - Example: Java's `java.util.HashMap` and `java.util.LinkedHashMap` are implementations of hash tables. 52 | 53 | 54 | 55 | explanations of some common algorithms used in computer science and software development, along with examples of their implementation in Java: 56 | 57 | 1. Sorting Algorithms: 58 | - Bubble Sort: Repeatedly compares adjacent elements and swaps them if they are in the wrong order. The largest (or smallest) element "bubbles" to the end (or beginning) of the array. 59 | - Selection Sort: Selects the smallest (or largest) element and swaps it with the current position. The sorted portion of the array gradually grows. 60 | - Insertion Sort: Iteratively inserts each element into its correct position in the sorted portion of the array. 61 | - Merge Sort: Divides the array into two halves, sorts each half recursively, and then merges the sorted halves. 62 | - Quick Sort: Chooses a pivot element, partitions the array around the pivot, and recursively sorts the sub-arrays on either side of the pivot. 63 | - Example: See the implementation of sorting algorithms in Java for various examples. 64 | 65 | 2. Searching Algorithms: 66 | - Linear Search: Iteratively checks each element in the array until a match is found or the end is reached. 67 | - Binary Search: Efficiently searches a sorted array by repeatedly dividing the search space in half. 68 | - Example: See the implementation of searching algorithms in Java for various examples. 69 | 70 | 3. Graph Algorithms: 71 | - Depth-First Search (DFS): Traverses a graph by exploring as far as possible along each branch before backtracking. 72 | - Breadth-First Search (BFS): Traverses a graph by exploring all the neighbors of a node before moving to the next level. 73 | - Dijkstra's Algorithm: Finds the shortest path between two nodes in a weighted graph. 74 | - Kruskal's Algorithm: Finds the minimum spanning tree of a connected, weighted graph. 75 | - Example: See the implementation of graph algorithms in Java for various examples. 76 | 77 | 4. Dynamic Programming: 78 | - Dynamic programming is a technique used to solve complex problems by breaking them down into smaller, overlapping subproblems. 79 | - It involves storing the solutions to subproblems in a table or array and reusing those solutions to avoid redundant computations. 80 | - Dynamic programming is often used to solve optimization problems and problems with overlapping substructures. 81 | - Example: Dynamic programming can be applied to solve problems like the Fibonacci sequence, the knapsack problem, and finding the longest common subsequence. 82 | 83 | 5. Backtracking: 84 | - Backtracking is a general algorithmic technique that involves systematically exploring all possible solutions to a problem. 85 | - It incrementally builds a solution and abandons it as soon as it determines that it cannot be extended to a valid solution. 86 | - Backtracking is often used to solve combinatorial problems like permutations, subsets, and Sudoku puzzles. 87 | - Example: Backtracking can be applied to solve problems like the N-Queens problem, Sudoku solving, and generating all possible combinations. 88 | 89 | 90 | Certainly! Here's an example that demonstrates the implementation of a common algorithm in Java: 91 | 92 | ```java 93 | import java.util.Arrays; 94 | //p4n.in 95 | // codeswithpankaj.com 96 | 97 | public class AlgorithmsExample { 98 | 99 | // Example of a sorting algorithm: Bubble Sort 100 | public static void bubbleSort(int[] arr) { 101 | int n = arr.length; 102 | for (int i = 0; i < n - 1; i++) { 103 | for (int j = 0; j < n - i - 1; j++) { 104 | if (arr[j] > arr[j + 1]) { 105 | int temp = arr[j]; 106 | arr[j] = arr[j + 1]; 107 | arr[j + 1] = temp; 108 | } 109 | } 110 | } 111 | } 112 | 113 | public static void main(String[] args) { 114 | int[] numbers = {5, 2, 8, 12, 1, 6}; 115 | System.out.println("Original array: " + Arrays.toString(numbers)); 116 | 117 | // Sorting the array using Bubble Sort 118 | bubbleSort(numbers); 119 | System.out.println("Sorted array: " + Arrays.toString(numbers)); 120 | } 121 | } 122 | ``` 123 | 124 | In this example, we demonstrate the implementation of the Bubble Sort algorithm, which is a simple sorting algorithm. The algorithm repeatedly compares adjacent elements and swaps them if they are in the wrong order. This process is repeated until the array is sorted. 125 | 126 | In the `bubbleSort` method, we use nested loops to iterate over the array and compare adjacent elements. If an element is greater than the next element, we swap them. This process is repeated until the largest element "bubbles" to the end of the array. After each pass, the largest element is guaranteed to be in its correct position. The outer loop is used to control the number of passes required to sort the array. 127 | 128 | In the `main` method, we create an array of numbers and print the original array. Then, we call the `bubbleSort` method to sort the array using the Bubble Sort algorithm. Finally, we print the sorted array. 129 | 130 | When you run this example, you will see the original array followed by the sorted array: 131 | 132 | ``` 133 | Original array: [5, 2, 8, 12, 1, 6] 134 | Sorted array: [1, 2, 5, 6, 8, 12] 135 | ``` 136 | 137 | This example demonstrates the implementation of a sorting algorithm, but you can similarly implement other algorithms based on your requirements, such as searching algorithms, graph algorithms, dynamic programming, and more. 138 | 139 | 140 | 141 | --------------------------------------------------------------------------------