├── Data Structures ├── Arrays │ ├── README.md │ ├── Topkfrequentelements.md │ ├── 3Sum.md │ ├── Intro_to_Arrays.md │ ├── Implementation_of_queue_using_array.md │ ├── Subarray_vs_Subsequence.md │ ├── TwoSumII.md │ └── queue.md ├── Hashingtechnique.md ├── Linked List │ ├── Implementation_of_queue_using_linkedlist.md │ └── Insertion in Linked List.md ├── Stacks │ └── README.md ├── BinarySearch │ └── Peak_Element_in_MountainArray.md ├── LinkedList.md └── BinarySearchTrees │ └── SearchInsertDelete.md ├── Algorithms ├── Searching Algorithms │ ├── README.md │ ├── BFS.md │ ├── Linear_Search.md │ ├── Binary_Search.md │ └── ternary_Search.md ├── Sorting Algorithms │ ├── README.md │ ├── ShellSort.md │ ├── RadixSort.md │ ├── Insertion_Sort.md │ ├── Heap_Sort.md │ ├── Bubble_Sort.md │ ├── Merge_Sort.md │ ├── Selection_sort.md │ ├── Insertion_Sort_Java.md │ └── Quick sort.md ├── Dynammic programming │ ├── LCS-1.png │ ├── LCS-2.png │ └── Longest Common Subsequence.md ├── Asymptotic Notations │ ├── big-omega.md │ ├── Big-Oh.md │ ├── Introduction.md │ └── Big-theta.md ├── Tree │ ├── Inorder_Traversal.md │ ├── Invert_Binary_Tree.md │ └── Prim's_Algorithm.md ├── Floyd_Warshall │ └── Floyd_Warshall.md ├── Sieve of Eratosthenes │ └── Sieve of Eratosthenes.md ├── Recursive algorithm │ └── Akra_Bazzi.md └── Segmented Sieve │ └── Segmented Sieve.md ├── .github ├── ISSUE_TEMPLATE │ ├── script-addition.md │ └── improve-a-doc.md └── PULL_REQUEST_TEMPLATE.md ├── LICENSE ├── README.md └── CODE_OF_CONDUCT.md /Data Structures/Arrays/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Algorithms/Searching Algorithms/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Algorithms/Sorting Algorithms/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Algorithms/Dynammic programming/LCS-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackClubRAIT/Wizard-Of-Docs/HEAD/Algorithms/Dynammic programming/LCS-1.png -------------------------------------------------------------------------------- /Algorithms/Dynammic programming/LCS-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackClubRAIT/Wizard-Of-Docs/HEAD/Algorithms/Dynammic programming/LCS-2.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/script-addition.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Script Addition 3 | about: Add a DSA doc. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Description 11 | Describe more about the issue. 12 | 13 | ### Programming language 14 | - [ ] C 15 | - [ ] C++ 16 | - [ ] Java 17 | - [ ] Python 18 | 19 | #### Are you contributing under any open-source program ? 20 | 21 | 22 |
1 Data 5 | 2 Pointer(reference) to the next node.6 | ● A linked list is a linear data structure, in which the elements are not stored at 7 | contiguous memory locations.\ 8 | ● The first node of a linked list is known as head.\ 9 | ● The last node of a linked list is known as tail.\ 10 | ● The last node has a reference to null. 11 | 12 | ## Linked list class 13 | ``` 14 | class Node { 15 | public : 16 | int data; // to store the data stored 17 | Node *next; // to store the address of next pointer 18 | Node(int data) { 19 | this -> data = data; 20 | next = NULL; 21 | } 22 | ``` 23 | Note: The first node in the linked list is known as Head pointer and the last node is 24 | referenced as Tail pointer. We must never lose the address of the head pointer as it 25 | references the starting address of the linked list and is, if lost, would lead to losing of the 26 | list. 27 | 28 | ## Printing of the linked list 29 | To print the linked list, we will start traversing the list from the beginning of the list(head) 30 | until we reach the NULL pointer which will always be the tail pointer. Follow the code 31 | below: 32 | ``` 33 | void print(Node *head) { 34 | Node *tmp = head; 35 | while(tmp != NULL) { 36 | cout << tmp->data << “ “; 37 | tmp = tmp->next; 38 | } 39 | cout << endl; 40 | } 41 | ``` 42 | 43 | ## Types Of LinkedList 44 | There are generally three types of linked list:\ 45 | ● Singly: Each node contains only one link which points to the subsequent node in the 46 | list.\ 47 | ● Doubly: It’s a two-way linked list as each node points not only to the next pointer 48 | but also to the previous pointer.\ 49 | ● Circular: There is no tail node i.e., the next field is never NULL and the next field for 50 | the last node points to the head node. 51 | 52 | ## Taking Input in a list 53 | ``` 54 | Node* takeInput() { 55 | int data; 56 | cin >> data; 57 | Node *head = NULL; 58 | Node *tail = NULL; 59 | while(data != -1) { // -1 is used for terminating 60 | Node *newNode = new Node(data); 61 | if(head == NULL) { 62 | head = newNode; 63 | tail = newNode; 64 | } 65 | else { 66 | tail -> next = newNode; 67 | tail = tail -> next; 68 | // OR 69 | // tail = newNode; 70 | } 71 | cin >> data; 72 | } 73 | return head; 74 | } 75 | ``` 76 | To take input in the user, we need to keep few things in the mind:\ 77 | ● Always use the first pointer as the head pointer.\ 78 | ● When initialising the new pointer the next pointer should always be referenced to 79 | NULL.\ 80 | ● The current node’s next pointer should always point to the next node to connect the 81 | linked list. 82 | 83 | ## Operations on Linked Lists 84 | 85 | ### Insertion 86 | There are 3 cases:\ 87 | ● Case 1: Insert node at the last\ 88 | This can be directly done by normal insertion as discussed above while we took input.\ 89 | 90 | ● Case 2: Insert node at the beginning\ 91 | ○ First-of-all store the head pointer in some other pointer.\ 92 | ○ Now, mark the new pointer as the head and store the previous head to the\ 93 | next pointer of the current head.\ 94 | ○ Update the new head.\ 95 | 96 | ● Case 3: Insert node anywhere in the middle\ 97 | ○ For this case, we always need to store the address of the previous pointer as 98 | well as the current pointer of the location at which new pointer is to be 99 | inserted.\ 100 | ○ Now let the new inserted pointer be curr. Point the previous pointer’s next to 101 | curr and curr’s next to the original pointer at the given location.\ 102 | ○ This way the new pointer will be inserted easily. 103 | 104 | ``` 105 | Node* insertNode(Node *head, int i, int data) { 106 | Node *newNode = new Node(data); 107 | int count = 0; 108 | Node *temp = head; 109 | if(i == 0) { //Case 2 110 | newNode -> next = head; 111 | head = newNode; 112 | return head; 113 | } 114 | while(temp != NULL && count < i - 1) { //Case 3 115 | temp = temp -> next; 116 | count++; 117 | } 118 | if(temp != NULL) { 119 | Node *a = temp -> next; 120 | temp -> next = newNode; 121 | newNode -> next = a; 122 | } 123 | return head; //Returns the new head pointer after insertion 124 | } 125 | ``` 126 | 127 | ## Deletion of node 128 | There are 2 cases:\ 129 | ● Case 1: Deletion of the head pointer\ 130 | In order to delete the head node, we can directly remove it from the linked list by 131 | pointing the head to the next.\ 132 | ● Case 2: Deletion of any node in the list\ 133 | In order to delete the node from the middle/last, we would need the previous 134 | pointer as well as the next pointer to the node to be deleted. Now directly point the 135 | previous pointer to the current node’s next pointer. 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /Algorithms/Sieve of Eratosthenes/Sieve of Eratosthenes.md: -------------------------------------------------------------------------------- 1 | # Sieve of Eratosthenes Algorithm 2 | 3 | A Prime Number has a unique property which states that the number can only be divisible by itself or 1. 4 | 5 | ## What does it do? 6 | For a given upper limit, this algorithm computes all the prime numbers upto the given limit by using the precomputed prime numbers repeatedly. 7 | 8 | The traditional algorithm for checking prime property would iterate over all the composites multiple times for each number for checking its properties. 9 | Whereas this algorithm only has to iterate over all numbers only once while crossing out the composites and marking out the primes. 10 | Once all the primes are marked, they are collected inside a list/vector and are used as required. 11 | Hence the time complexity for the traditional algorithm increases with increase in range as well as size of numbers whereas Sieve of Eratosthenes only takes O(N). 12 | 13 | Sieve of Eratosthenes algorithm is the most efficient for collecting multiple primes for a huge range of numbers of big magnitudes. 14 | 15 | 16 | ## Steps 17 | **Step 1)** A list/vector is created where all the primes would be stored. 18 | 19 | **Step 2)** All the numbers upto the given range is initially marked as Prime (true) [except for 0 and 1]. 20 | 21 | **Step 3)** As the primes are marked true, all the multiples of those primes are marked as composites (false). If a number is already marked false, their multiples are skipped. 22 | 23 | **Step 4)** All the numbers which were multiples are marked false and only those numbers remain marked as prime (true) which are not a multiple of any other number, hence it is a prime number. 24 | 25 | **Step 5)** The marked primes are then collected in the list/vector for their required use. 26 | 27 | 28 | ## Code in C++ 29 | ```cpp 30 | #include
68 |
69 |
70 | ### Case 2 : When str1[i] != str2[j]
71 | When we can move to only right left
72 |
73 |
74 | ```java
75 | public class App {
76 |
77 | public static void main(String[] args) {
78 | System.out.println(longestCommonSubsequence("abc", "cab"));
79 | }
80 |
81 | public static int longestCommonSubsequence(String text1, String text2) {
82 |
83 | int rows = text1.length();
84 | int columns = text2.length();
85 |
86 | if(rows == 0 || columns == 0)
87 | return 0;
88 |
89 | int[][] dpTable = new int[rows+1][columns+1];
90 | for(int i = 1; i <= rows; i++) {
91 | for(int j = 1; j <= columns; j++) {
92 | if(text1.charAt(i-1) == text2.charAt(j-1)) {
93 | dpTable[i][j] = dpTable[i-1][j-1] + 1;
94 | } else {
95 | dpTable[i][j] = Math.max(dpTable[i-1][j], dpTable[i][j-1]);
96 | }
97 | }
98 | }
99 |
100 | System.out.println(subSequence(text1, text2, dpTable));
101 | return dpTable[rows][columns];
102 | }
103 |
104 | public static StringBuilder subSequence(String text1, String text2, int[][] dpTable) {
105 | String subsequence = "";
106 | int row = text1.length();
107 | int column = text2.length();
108 | while(row > 0 && column > 0 && dpTable[row][column] != 0) {
109 | if(dpTable[row][column] == dpTable[row - 1][column]) {
110 | row = row - 1;
111 | } else if(dpTable[row][column] == dpTable[row][column-1]) {
112 | column = column -1;
113 | } else {
114 | subsequence += text1.charAt(row-1);
115 | row = row - 1;
116 | column = column - 1;
117 | }
118 | }
119 | StringBuilder sb = new StringBuilder(subsequence);
120 | return sb.reverse();
121 | }
122 |
123 | }
124 | ```
125 | **Note the order of checks in the `subSequence()` method 💥 , for constructing the subsequence.**
126 |
--------------------------------------------------------------------------------
/Algorithms/Tree/Prim's_Algorithm.md:
--------------------------------------------------------------------------------
1 | # Prim's Algorithm
2 |
3 | - Prim’s algorithm is used to find the Minimum Spanning Tree(MST) of a connected or undirected graph. Spanning Tree of a graph is a subgraph that is also a tree and includes all the vertices. Minimum Spanning Tree is the spanning tree with a minimum edge weight sum.
4 |
5 | ## Algorithm
6 | - Step 1: Keep a track of all the vertices that have been visited and added to the spanning tree.
7 |
8 | - Step 2: Initially the spanning tree is empty.
9 |
10 | - Step 3: Choose a random vertex, and add it to the spanning tree. This becomes the root node.
11 |
12 | - Step 4: Add a new vertex, say x, such that x is not in the already built spanning tree. x is connected to the built spanning tree using minimum weight edge. (Thus, x can be adjacent to any of the nodes that have already been added in the spanning tree).
13 | Adding x to the spanning tree should not form cycles.
14 | - Step 5: Repeat the Step 4, till all the vertices of the graph are added to the spanning tree.
15 |
16 | - Step 6: Print the total cost of the spanning tree.
17 |
18 |
19 | ## Code (In C++)
20 |
21 | #includeAlgorithm: The rule is, if the given value (to be searched) is greater than the current node’s value, we continue the search in only the right subtree of the current node. And if the given value is lesser, the search goes on only in the left subtree. Since we are using recursion here, the recursive calls foe the left and the right subtree are referred to as the traversal here.12 | 13 | ### Code for SEARCHING in a BST:- 14 | 15 | ``` 16 | bool searchInTree(node *root, int val) 17 | { 18 | bool a = false, b = false; 19 | if (!root) 20 | return false; 21 | if (root->val == val) 22 | return true; 23 | else if (val > root->val) 24 | a = searchInTree(root->right, val); 25 | else 26 | b = searchInTree(root->left, val); 27 | return a || b; //if it finds the given value in either left or right subtree, TRUE will be returned, otherwise FALSE 28 | } 29 | ``` 30 | 31 | ### Time Complexity:- 32 | For searching an element, we have to traverse all elements. Therefore, searching in binary search tree has worst case time complexity of O(n). In general, time complexity is O(h) where h is height of BST. 33 | 34 | ## INSERTING a node with given value in BST:- 35 | Insertion in BST takes place quite similar to the search algorithm, the only difference being that whenever any of the nodes while traversal is found to be NULL, the given value is inserted there. 36 | 37 |
ALGORITHM: Similar to binary search, if the given value to be inserted is greater than the value of the current node, we traverse in its right subtree, and if given value is lesser than the current node value, we traverse in the left subtree. Our aim is to find an empty branch where we can insert the given value node.38 | 39 | ### Code for INSERTING in a BST:- 40 | 41 | ``` 42 | node *insert(node *root, int val) 43 | { 44 | if (!root) //whenever the current node passed to tbe recursive function is NULL, we know that there's a vacancy here 45 | return new node(val); // creating a new node with the given value and returning that 46 | if (val > root->val) 47 | root->right = insert(root->right, val); 48 | else 49 | root->left = insert(root->left, val); 50 | return root; 51 | } 52 | 53 | ``` 54 | 55 | ### Time Complexity:- 56 | In order to insert an element as left child, we have to traverse all elements. Therefore, insertion in binary tree has worst case complexity of O(n). 57 | 58 | ## DELETION of a node with given value in BST:- 59 | The deletion algorithm in a BST is comparatively easy as compared to that in a Binary Tree. We just have to delete the current node if its value is equal to the given value, and put its right node in its place if it exists, otherwise the left node. 60 | 61 |
ALGORITHM: Let's take an example of the BST, suppose we want to delete the node with value x. We will traverse to that node and see if its right node exists and is not NULL. If it exists, we create a new node with the right node’s value and put it at the current node’s place. If the right node doesn’t exist,we connect the left node in place of the current node.62 | 63 | ### Code for Deleting a node in a BST:- 64 | 65 | ``` 66 | struct node* deleteNode(struct node* root, int key){ 67 | if (root == NULL) return root; //base case of recursion 68 | if (key < root->key) 69 | root->left = deleteNode(root->left, key); //traversing in the left subtree 70 | else if (key > root->key) 71 | root->right = deleteNode(root->right, key); //traversing in the right subtree 72 | else{ 73 | if (root->left == NULL){ //if only right node present 74 | struct node *temp = root->right; 75 | free(root); 76 | return temp; 77 | } 78 | else if (root->right == NULL){ //if only left node present 79 | struct node *temp = root->left; 80 | free(root); 81 | return temp; 82 | } 83 | struct node* temp = minValueNode(root->right); //if both left and right nodes are NULL, none present 84 | root->key = temp->key; 85 | root->right = deleteNode(root->right, temp->key); 86 | } 87 | return root; 88 | } 89 | 90 | ``` 91 | ### Time Complexity:- 92 | For deletion of element, we have to traverse all elements to find that element(assuming we do breadth first traversal). Therefore, deletion in binary tree has worst case complexity of O(n). 93 | 94 | ## Note: 95 | So, now you know why using a BST is a really time efficient data structure. Its basic operations such as insertion, deletion and search take O(log N) time complexity to be processed. -------------------------------------------------------------------------------- /Algorithms/Sorting Algorithms/Quick sort.md: -------------------------------------------------------------------------------- 1 | # ⭐ QUICK SORT 2 | 3 | Quicksort is an in-place sorting algorithm.Quicksort is a divide-and-conquer algorithm. 4 | It works by selecting a 'pivot' element from the array and partitioning the other elements into two sub-arrays, 5 | according to whether they are less than or greater than the pivot. For this reason, 6 | it is sometimes called partition-exchange sort.The sub-arrays are then sorted recursively. 7 | This can be done in-place, requiring small additional amounts of memory to perform the sorting. 8 | #### Example: 9 | 10 | ##### Input: `[9, 0, 1, 12, 3], 0, 4` 11 | ###### input1: `array` 12 | ###### input0: `start index` 13 | ###### input1: `end index` 14 | 15 | ##### Partition phase: 16 | `[9, 0, 1, 12, 3]`