├── .codespellrc ├── .github └── workflows │ └── code-format.yml ├── .gitignore ├── Algorithms ├── Searching-Algorithms │ ├── Binary-Search │ │ ├── Easy │ │ │ ├── 01-binary-search.md │ │ │ ├── 02-lower&upper-bound.md │ │ │ ├── 03-search-insert-position.md │ │ │ ├── 04-floor&ceil-in-array.md │ │ │ ├── 05-first-and-last-ocurrence.md │ │ │ ├── 06-number-of-occurrence.md │ │ │ ├── 07-search-in-rotated-sorted-unique-array.md │ │ │ ├── 08-search-in-rotated-sorted-duplicate-array.md │ │ │ ├── 09-minimum-in-sorted-rotated.md │ │ │ ├── 10-single-in-sorted-rotated.md │ │ │ └── 11-find-peak-in-array.md │ │ └── Medium │ │ │ └── koko-eating-bananas.md │ └── linear-search.md ├── Sliding-Window │ ├── 01-intro.md │ ├── 02-problem-1.md │ └── 03-problem-2.md ├── Sorting-Algorithms │ ├── bubble-sort.md │ └── selection-sort.md └── time-complexity.md ├── CPP ├── 01-intro.md ├── 02-c-vs-cpp.md ├── 03-basics.md ├── 04-loops.md ├── 05-bitwise-operators.md ├── 06-operators.md ├── 07-functions.md ├── 08-lambda-function.md ├── 09-data-types.md ├── 10-static-typing.md ├── 11-dynamic-typing.md ├── 12-pointers-references.md ├── 13-memory-model.md ├── 14-raw-ptr.md ├── 15-memory-leakage.md ├── 16-unique-ptr.md ├── 17-shared-ptr.md ├── 18-structuring-codebase.md ├── 19-scope.md ├── 20-namespace.md ├── 20.1-dont-use-namesapce-std.md ├── 21-code-splitting.md ├── 22-forward-declaration.md ├── 23-structs-classes.md ├── 24-OOP.md ├── 25-OOP-example.md ├── 26-multiple-inheritance.md ├── 26.1-diamond-inheritance.md ├── 27-static-polymorphism.md ├── 28-dynamic-polymorphism.md ├── 28.1-virtual-methods.md ├── 28.2-virtual-tables.md ├── 29-exception-handling.md ├── 29.1-try-catch-throw.md ├── 30-exit-codes.md ├── 31-access-violations.md ├── 32-type-casting.md ├── 33-standard-template-library.md ├── 34-templates.md └── 35-name-mangling.md ├── Data-Structures ├── Hash-Maps │ ├── 01-maps-intro.md │ ├── 02-map-methods.md │ ├── 03-number-of-occurrences.md │ ├── 04-max-occurrence.md │ └── 05-python-maps.md ├── Linear-Data-Structures │ ├── 02-strings.md │ ├── 03-vectors.md │ ├── 04-stacks.md │ ├── 05-queues.md │ ├── Array │ │ ├── 01-arrays.md │ │ └── 02-second-largest.md │ └── Linked-List │ │ ├── Basics │ │ ├── 01-linked-list.md │ │ ├── 02-node-creation.md │ │ ├── 03-traversal.md │ │ └── 04-implementation.cpp │ │ ├── Doubly-Linked-List │ │ ├── 00-DLL-basics.md │ │ ├── 01-arr2DLL.md │ │ ├── 02-delete-head-tail.md │ │ ├── 03-delete-kth-node.md │ │ ├── 04-insert-head-tail.md │ │ └── 05-reverseDLL.md │ │ ├── Singly-Linked-List │ │ ├── 01-array2LL.md │ │ ├── 02-delete-head-tail.md │ │ ├── 03-delete-kth-node.md │ │ ├── 04-insert-head-tail.md │ │ ├── 05-insert-at-kth-pos.md │ │ ├── 06-addTwoLL.md │ │ ├── 07-segEvenOddNodes.md │ │ ├── 08-sort-0s-1s-2s.md │ │ ├── 09-delete-nth-node-from-back.md │ │ ├── 10-reverseLL.md │ │ └── 11-check-palindrome.md │ │ ├── reverseLinkedList.md │ │ └── temp2.cpp ├── Trees │ ├── 01-intro.md │ ├── 02-basics.md │ ├── 03-travsersals.md │ ├── 04-in-order-recur.md │ ├── 05-pre-order-recur.md │ ├── 06-post-order-recur.md │ ├── 07-level-order.md │ ├── 08-in-order-iterative.md │ ├── 09-pre-order-iterative.md │ ├── 10-post-order-twoStack.md │ ├── 11-post-order-oneStack.md │ ├── 12.heap.md │ └── problems │ │ ├── check-for-balanced-bt.cpp │ │ ├── count-leaves.cpp │ │ ├── depth-of-bt.cpp │ │ ├── diameter-of-bt.cpp │ │ ├── sum-of-left-leaves.cpp │ │ └── symmetric-bt.cpp └── stl-reference.md ├── Database └── normalization.md ├── Go ├── Basics │ ├── 00-intro.md │ ├── 01-helloGo.md │ ├── 02-packages.md │ ├── 03-basics.md │ ├── 04-errors.md │ ├── 05-structs.md │ ├── 06-interfaces.md │ ├── 07-arrays-slices.md │ ├── 08-maps(theGoObjects).md │ ├── 09-higher-order-functions.md │ ├── 10-pointers.md │ └── 11-json.md ├── Concurrency │ ├── 1-concurrecy.md │ ├── 2-deadlocks.md │ ├── 3-buffered-channels.md │ └── 4-generics.md ├── codes │ └── temp.go └── wise-words.md ├── JavaScript ├── 01-intro.md ├── 02-basics.md ├── 03-operators.md ├── 04-variables.md ├── 05-array-methods.md └── Asynchronous JS │ ├── async-await.md │ ├── async-queue.js │ ├── callBack.md │ ├── multiHandlers.md │ ├── promiChain.md │ ├── promise-1.md │ ├── promise-2.md │ ├── sync-vs-async.md │ └── then-catch.md ├── LICENSE ├── OOP ├── OOP-intro.md ├── abstraction.md ├── classes-objects-intro.md ├── encapsulation.md ├── inheritence.md └── polymorphism.md ├── README.md └── TypeScript ├── Learn-What-Matters ├── 01-typescript-basics.md ├── 02-the-tsconfig.md ├── 03-functions.md ├── 04-arrays.md ├── 05-custom-types.md ├── 06-generics.md ├── 07-union-types.md └── 08-interfaces.md └── TypeScript-For-React ├── 01-typed-props.md ├── 01-useState.md ├── 02-componentProps.md ├── 02-dataFromAPI.md ├── 03-eventListners.md └── 03-typing-children.md /.codespellrc: -------------------------------------------------------------------------------- 1 | [codespell] 2 | ignore-words-list = "and" 3 | count = 4 | quiet-level = 3 5 | -------------------------------------------------------------------------------- /.github/workflows/code-format.yml: -------------------------------------------------------------------------------- 1 | name: Format Code 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | push: 7 | 8 | jobs: 9 | format: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | 16 | - name: Format Markdown 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | - run: npm install --global prettier 21 | - run: prettier --write '**/*.md' 22 | 23 | - name: Commit and Push Changes 24 | if: github.repository == 'Rishabh672003/Programming-Notes' 25 | uses: actions-js/push@v1.4 26 | with: 27 | github_token: ${{ secrets.GITHUB_TOKEN }} 28 | message: 'Formatted the code' 29 | force: true 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Example-Code/*.out 2 | 3 | Go/codes/go.mod -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/03-search-insert-position.md: -------------------------------------------------------------------------------- 1 | ## Search Insert Position 2 | 3 | You're given a sorted array `arr` of distinct values and a target value `m`. Search for the index of the target value in array. 4 | 5 | --- 6 | 7 | **Note :** 8 | 9 | - If the value is present in the array, return its index. 10 | 11 | - If the value is absent, determine the index where it would be inserted in the array while **maintaining the sorted order.** 12 | 13 | - Consider 0-based indexing only. 14 | 15 | --- 16 | 17 | **Example :** 18 | 19 | ``` 20 | int arr[5] = {1, 2, 3, 5, 7}; 21 | m = 6; 22 | 23 | Output : 3 24 | 25 | Explanation : In the given array, the target 6 is not available so we can insert m = 6 at index 3 to maintain sorted order. 26 | ``` 27 | 28 | --- 29 | 30 | **Implementation :** 31 | 32 | ```cpp 33 | #include 34 | using namespace std; 35 | 36 | int searchInsert(vector& arr, int m) { 37 | int n = arr.size(); 38 | int low = 0, high = n - 1; 39 | int ans = n; 40 | while (low <= high) { 41 | int mid = low + (high - low) / 2; 42 | if (arr[mid] >= m) { 43 | ans = mid; 44 | high = mid - 1; 45 | } else { 46 | low = mid + 1; 47 | } 48 | } 49 | return ans; 50 | } 51 | 52 | int main() { 53 | vector arr = {1, 3, 5, 6, 8, 9}; 54 | int m = 7; 55 | cout << searchInsert(arr, m) << endl; 56 | return 0; 57 | } 58 | ``` 59 | 60 | ``` 61 | Output : 4 62 | 63 | Explanation : 7 isn't present in the array so 4 will be the index where 7 would be inserted so as to maintain sorted order. 64 | ``` 65 | 66 | --- 67 | 68 | **Refer :** 69 | [Lower Bound](./02-lower&upper-bound.md), [Binary Search](./01-binary-search.md). 70 | 71 | --- 72 | 73 | **Solve it on :** 74 | 75 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/algorithm-to-find-best-insert-position-in-sorted-array_839813?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf) & 76 | [LeetCode](). 77 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/04-floor&ceil-in-array.md: -------------------------------------------------------------------------------- 1 | ## Floor and Ceil in array. 2 | 3 | **Floor : _Largest_ element in array which is <= x.** 4 | 5 | **Ceil : _Smallest_ element in array which is >= x.** 6 | 7 | --- 8 | 9 | **Example :** 10 | 11 | ``` 12 | int arr[5] = {10, 20, 30, 40, 50}; 13 | int x = 25 14 | 15 | here, floor --> 20 and ceil --> 30 16 | 17 | Explanation : 18 | floor : 10 <= 25, 20 <= 25 but 20 > 10, so 20. 19 | ceil : 30 >= 25, 40 >= 25, 50 >= 25 but 40 > 30 < 50, so 30. 20 | ``` 21 | 22 | **Note :** If the element exists in the array then the **element itself** is floor and ceil. 23 | 24 | --- 25 | 26 | **Implementation :** 27 | 28 | ```cpp 29 | int findFloor(vector& arr, int x){ 30 | int n = arr.size(); 31 | int low = 0, high = n - 1; 32 | int ans = -1; 33 | while (low <= high){ 34 | int mid = low + (high - low) / 2; 35 | if (arr[mid] <= x){ 36 | ans = arr[mid]; // maybe an answer 37 | low = mid + 1; 38 | // eleminate the left search space as we want to find the 'largest' element. 39 | } else { 40 | high = mid - 1; 41 | } 42 | } 43 | return ans; 44 | } 45 | 46 | int findCeil(vector& arr, int x){ 47 | int n = arr.size(); 48 | int low = 0, high = n - 1; 49 | int ans = -1; 50 | while (low <= high){ 51 | int mid = low + (high - low) / 2; 52 | if (arr[mid] >= x){ 53 | ans = arr[mid]; // maybe an answer 54 | high = mid - 1; 55 | // eleminate the right search space as we want to find the 'smallest' element. 56 | } else { 57 | low = mid + 1; 58 | } 59 | } 60 | return ans; 61 | } 62 | 63 | int main() { 64 | vector arr = {1, 3, 5, 6, 8, 9}; 65 | int x = 7; 66 | int floor = findFloor(arr, x); 67 | int ceil = findCeil(arr, x); 68 | cout << "The floor of " << x << " is " << floor << endl; 69 | cout << "The ceil of " << x << " is " << ceil << endl; 70 | return 0; 71 | } 72 | 73 | ``` 74 | 75 | ``` 76 | output : 77 | The floor of 7 is 6 78 | The ceil of 7 is 7 79 | ``` 80 | 81 | --- 82 | 83 | **Refer :** 84 | [Lower Bound](./02-lower&upper-bound.md), [Binary Search](./01-binary-search.md). 85 | 86 | --- 87 | 88 | **Solve it on :** 89 | 90 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/ceiling-in-a-sorted-array_1825401?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf) 91 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/05-first-and-last-ocurrence.md: -------------------------------------------------------------------------------- 1 | ## First and Last occurrence of an element. 2 | 3 | ### First occurrence --> Lower Bound. 4 | 5 | ### Last occurrence --> Upper bound - 1. 6 | 7 | --- 8 | 9 | **Implementation :** 10 | 11 | ```cpp 12 | int lowerBound(vector &arr, int n, int x){ 13 | int low = 0, high = n - 1; 14 | int ans = n; 15 | while (low <= high){ 16 | int mid = low + (high - low) / 2; 17 | if (arr[mid] >= x){ 18 | ans = mid; 19 | high = mid - 1; 20 | } else { 21 | low = mid + 1; 22 | } 23 | } 24 | return ans; 25 | } 26 | 27 | int upperBound(vector &arr, int n, int x){ 28 | int low = 0, high = n - 1; 29 | int ans = n; 30 | while (low <= high){ 31 | int mid = low + (high - low) / 2; 32 | // maybe answer 33 | if (arr[mid] > x){ 34 | ans = mid; 35 | // look for more small index in left 36 | high = mid - 1; 37 | } else { 38 | low = mid + 1; // look for right 39 | } 40 | } 41 | return ans; 42 | } 43 | 44 | pair firstAndLastPosition(vector& arr, int n, int k) 45 | { 46 | int lb = lowerBound(arr, n, k); 47 | if (lb == n || arr[lb] != k) return {-1, -1}; 48 | return {lb, upperBound(arr, n, k) - 1}; 49 | } 50 | 51 | int main() { 52 | vector arr = {1, 3, 5, 5, 5, 5, 7, 8, 9}; 53 | int k = 5; 54 | pair result = firstAndLastPosition(arr, arr.size(), k); 55 | cout << "The first and last position of " << k << " in the array are " << result.first << " and " << result.second << endl; 56 | return 0; 57 | } 58 | ``` 59 | 60 | ``` 61 | Output : 62 | The first and last position of 5 in the array are 2 and 5 63 | ``` 64 | 65 | --- 66 | 67 | **Solve it on :** 68 | 69 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/first-and-last-position-of-an-element-in-sorted-array_1082549?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf) & 70 | [LeetCode](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/). 71 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/06-number-of-occurrence.md: -------------------------------------------------------------------------------- 1 | ## Number of Occurrence of element in an array. 2 | 3 | ### Number of occurrence = last occurrence - first occurrence + 1 4 | 5 | --- 6 | 7 | **Implementation :** 8 | 9 | ```cpp 10 | #include 11 | using namespace std; 12 | 13 | int lowerBound(vector& arr, int n, int x) { 14 | int low = 0, high = n - 1; 15 | int ans = n; 16 | while (low <= high) { 17 | int mid = low + (high - low) / 2; 18 | if (arr[mid] >= x) { 19 | ans = mid; 20 | high = mid - 1; 21 | } else { 22 | low = mid + 1; 23 | } 24 | } 25 | return ans; 26 | } 27 | 28 | int upperBound(vector& arr, int n, int x) { 29 | int low = 0, high = n - 1; 30 | int ans = n; 31 | while (low <= high) { 32 | int mid = low + (high - low) / 2; 33 | if (arr[mid] > x) { 34 | ans = mid; 35 | high = mid - 1; 36 | } else { 37 | low = mid + 1; 38 | } 39 | } 40 | return ans; 41 | } 42 | 43 | pair firstAndLastPosition(vector& arr, int n, int k) { 44 | int lb = lowerBound(arr, n, k); 45 | if (lb == n || arr[lb] != k) return {-1, -1}; 46 | return {lb, upperBound(arr, n, k) - 1}; 47 | } 48 | 49 | int count(vector& arr, int n, int x) { 50 | pair ans = firstAndLastPosition(arr, n, x); 51 | if (ans.first == -1) return 0; 52 | return ans.second - ans.first + 1; 53 | } 54 | 55 | int main() { 56 | vector arr = {1, 3, 5, 5, 5, 5, 7, 8, 9}; 57 | int x = 5; 58 | int count = count(arr, arr.size(), x); 59 | cout << "The number of occurrences of " << x << " in the array is " << count << endl; 60 | return 0; 61 | } 62 | ``` 63 | 64 | ``` 65 | Output : 66 | The number of occurrences of 5 in the array is 4 67 | ``` 68 | 69 | --- 70 | 71 | **Solve it on :** 72 | 73 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/occurrence-of-x-in-a-sorted-array_630456?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf). 74 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/09-minimum-in-sorted-rotated.md: -------------------------------------------------------------------------------- 1 | ## Find Minimum in Rotated Sorted Array 2 | 3 | Given the sorted rotated array **arr** of **unique** elements, return the **minimum** element of this array. 4 | You must write an algorithm that runs in **O(log n)** time. 5 | 6 | ```cpp 7 | int findMin(vector& arr) 8 | { 9 | int low = 0, high = arr.size() - 1; 10 | int ans = INT_MAX; 11 | while (low <= high) { 12 | int mid = low + (high - low) / 2; 13 | 14 | if (arr[low] <= arr[high]) { 15 | ans = min(ans, arr[low]); 16 | break; 17 | } 18 | 19 | if (arr[low] <= arr[mid]){ 20 | ans = min(ans, arr[low]); 21 | low = mid + 1; 22 | } else { 23 | high = mid - 1; 24 | ans = min(ans, arr[mid]); 25 | } 26 | } 27 | return ans; 28 | } 29 | ``` 30 | 31 | --- 32 | 33 | **Solve it on :** 34 | 35 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/rotated-array_1093219?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf) & 36 | [LeetCode](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/). 37 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/10-single-in-sorted-rotated.md: -------------------------------------------------------------------------------- 1 | ## Single Element in a Sorted Array 2 | 3 | **Problem Statement :** 4 | You are given a sorted array consisting of only integers where every element appears exactly twice, except for one element which appears exactly once. 5 | 6 | Return the single element that appears only once. 7 | Your solution must run in **O(log n)** time and **O(1)** space. 8 | 9 | --- 10 | 11 | **Example :** 12 | 13 | ``` 14 | Input: arr[9] = [1,1,2,3,3,4,4,8,8]; 15 | Output: 2 16 | ``` 17 | 18 | --- 19 | 20 | ### Implementation : 21 | 22 | ```cpp 23 | class Solution { 24 | public: 25 | int singleNonDuplicate(vector& arr) { 26 | int n = arr.size(); 27 | 28 | if (n == 1) return arr[0]; // if only 1 element in array 29 | 30 | // trimming down array size to avoid extra comparisons. 31 | if (arr[0] != arr[1]) return arr[0]; 32 | if (arr[n-1] != arr[n-2]) return arr[n-1]; 33 | int low = 1, high = n - 2; 34 | 35 | while (low <= high){ 36 | int mid = low + (high - low) / 2; 37 | 38 | // search for mid to be a single 39 | if (arr[mid] != arr[mid - 1] && arr[mid] != arr[mid + 1]) return arr[mid]; 40 | 41 | /* if one of th half is sorted, our answer is in the opposite half. if we are on left half and it is sorted, eleminate it */ 42 | if ((mid % 2 == 1 && arr[mid] == arr[mid - 1]) 43 | || (mid % 2 == 0 && arr[mid] == arr[mid + 1])) { 44 | low = mid + 1; 45 | } 46 | 47 | // else right half is sorted, eleminate it. 48 | else { 49 | high = mid - 1; 50 | } 51 | 52 | } 53 | return -1; 54 | } 55 | }; 56 | ``` 57 | 58 | --- 59 | 60 | **Solve it on :** 61 | 62 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/unique-element-in-sorted-array_1112654?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf) & 63 | [LeetCode](https://leetcode.com/problems/single-element-in-a-sorted-array/). 64 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/Binary-Search/Easy/11-find-peak-in-array.md: -------------------------------------------------------------------------------- 1 | ## Find Peak Element 2 | 3 | **Problem Statement :** 4 | A peak element is an element that is **strictly** greater than its neighbors. 5 | 6 | Given an integer array nums, find a peak element, and return its index. _If the array contains multiple peaks, return the index to any of the peaks._ 7 | 8 | You may imagine that `nums[-1] = nums[n] = -∞`. In other words, an element is always considered to be **strictly** greater than a neighbor that is outside the array. 9 | 10 | You must write an algorithm that runs in **O(log n)** time. 11 | 12 | --- 13 | 14 | **Example :** 15 | 16 | ``` 17 | Input: nums = [1,2,3,1] 18 | Output: 2 19 | Explanation: 3 is a peak element and your function should return the index number 2. 20 | ``` 21 | 22 | --- 23 | 24 | ### Implementation : 25 | 26 | ```cpp 27 | int findPeakElement(vector &arr) { 28 | int n = arr.size(); 29 | 30 | // trimming search space by checking corners 31 | if (n == 0) return 0; 32 | if (arr[0] > arr[1]) return 0; 33 | if (arr[n - 1] > arr[n - 2]) return n - 1; 34 | int low = 1, high = n - 2; 35 | 36 | while (low <= high) { 37 | int mid = low + (high - low) / 2; 38 | 39 | // if my mid is a peak 40 | if (arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1]) return mid; 41 | 42 | // if mid is on an increasing curve 43 | else if (arr[mid] > arr[mid - 1]) low = mid + 1; 44 | 45 | // if mid is on an deccreasing curve 46 | else high = mid - 1; 47 | } 48 | return -1; 49 | } 50 | ``` 51 | 52 | --- 53 | 54 | [Coding Ninjas](https://www.codingninjas.com/studio/problems/find-peak-element_1081482?utm_source=striver&utm_medium=website&utm_campaign=a_zcoursetuf) & 55 | [LeetCode](https://leetcode.com/problems/single-element-in-a-sorted-array/). 56 | -------------------------------------------------------------------------------- /Algorithms/Searching-Algorithms/linear-search.md: -------------------------------------------------------------------------------- 1 | # Linear Search 2 | 3 | _Searching Elements in Contigious Linear Data Structure._ 4 | 5 | **Time Complexity:** 6 | 7 | 1. Best Case: O(1) --> Element found at 1st comparison. 8 | 2. Average / Worst Case: O(n) --> for n comparisons. (where n is the size of array) 9 | 10 | # Implementation 11 | 12 | ```cpp 13 | #include 14 | using namespace std; 15 | 16 | int linearSearch(int arr[], int n, int x) 17 | { 18 | // loop through each element in the array 19 | for (int i = 0; i < n; i++) 20 | { 21 | // if the current element matches the search value, return the index 22 | if (arr[i] == x) 23 | { 24 | return i; 25 | } 26 | } 27 | // if the search value is not found in the array, return -1 28 | return -1; 29 | } 30 | 31 | int main() 32 | { 33 | int arr[] = {10, 20, 30, 40, 50}; 34 | int n = sizeof(arr) / sizeof(arr[0]); 35 | int x = 30; 36 | 37 | int index = linearSearch(arr, n, x); 38 | if (index == -1) 39 | { 40 | cout << "Element not found" << endl; 41 | } 42 | else 43 | { 44 | cout << "Element found at index " << index << endl; 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | ``` 51 | -------------------------------------------------------------------------------- /Algorithms/Sliding-Window/01-intro.md: -------------------------------------------------------------------------------- 1 | ## Introduction to Sliding Window Algorithm. 2 | 3 | - The sliding window algorithm is a technique for solving problems that involve a sequence of elements, such as an **array** or a **string**. 4 | 5 | - The sliding window can be termed as a **sub-array** or a **sub-string** which moves over the sequence, and some operation is performed on the elements within the window. 6 | 7 | - The algorithm works by maintaining a window of fixed or variable size over the sequence. 8 | 9 | --- 10 | 11 | ## Why we need this algorithm ? 12 | 13 | Suppose you've a problem where your are provided an integer array, 14 | 15 | ```cpp 16 | int arr[7] = {2, 3, 5, 2, 9, 7, 1}; 17 | ``` 18 | 19 | and an integer let's say '3' which denotes the size of subarray. Find the maximum sum of subarrays. 20 | 21 | **A subarray is a subset of an array. But it must be continuous in nature.** 22 | 23 | ``` 24 | The array 2 3 5 2 9 7 1 can have the following size 3 subarrays with their sum : 25 | 26 | 2 3 5 sum = 10 27 | 3 5 2 sum = 10 28 | 5 2 9 sum = 16 29 | 2 9 7 sum = 18 --> Maximum sum 30 | 9 7 1 sum = 17 31 | ``` 32 | 33 | To solve this problem, we might think about the Brute Force Approach, where we consider 2 pointers `i` and `j`, we use 2 nested `for` loops where `i` iterates from 0 to size and `j` iterates from `i` to `j < i + 3` and stores the sum for each sub-array and at the end returns the max of all individual sums. 34 | 35 | But then we will be performing a **repetitive task** of adding 2 same numbers for each iteration which we've **already performed** in previous iteration. 36 | 37 | **Here's what I mean :** 38 | 39 | ``` 40 | 2 + 3 + 5 41 | 3 + 5 + 2 we repeat 3 + 5 42 | 5 + 2 + 9 we repeat 5 + 2 43 | 2 + 9 + 7 we repeat 2 + 9 44 | 9 + 7 + 1 we repeat 9 + 7 45 | ``` 46 | 47 | Whenever you find such repetitions in any program, there's a need of **Optimization**. 48 | 49 | To overcome this repetitions, what we can do is to remove the previous value, once it gets added up and then add the upcoming value and so on. 50 | 51 | This is something what a Sliding Window does. Whenever it moves ahead it leaves behind the previous value and includes the upcoming value. 52 | 53 | **See Below Example :** 54 | 55 | ![sliding-window](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/7ebe8306-58c5-4b9b-9f35-ca6941612780) 56 | 57 | --- 58 | -------------------------------------------------------------------------------- /Algorithms/Sorting-Algorithms/bubble-sort.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort 2 | 3 | **Bubble sort is a simple sorting algorithm that repeatedly steps through a list of elements to be sorted, compares each pair of adjacent elements and swaps them if they are in the wrong order. The pass through the list is repeated until the list is sorted.** 4 | 5 | ### Working 6 | 7 | Here is an example of how bubble sort works on a list of numbers: 8 | 9 | 1. Compare the first two elements. If the first element is greater than the second element, swap them. 10 | 2. Move to the next pair of elements (second and third) and repeat step 1. 11 | 3. Continue to compare and swap adjacent elements until the end of the list is reached. 12 | 4. Repeat steps 1-3 until no more swaps are needed. 13 | 14 | ### Implementation in C++ 15 | 16 | ```cpp 17 | #include 18 | using namespace std; 19 | 20 | void bubbleSort(int arr[], int n) { 21 | int i, j; 22 | for (i = 0; i < n; i++) { 23 | for (j = 0; j < n; j++) { 24 | if (arr[j] > arr[j + 1]) { 25 | swap(arr[j], arr[j + 1]); 26 | } 27 | } 28 | } 29 | } 30 | 31 | int main() { 32 | int arr[] = {64, 25, 12, 22, 11}; 33 | int n = sizeof(arr) / sizeof(arr[0]); 34 | bubbleSort(arr, n); 35 | cout << "Sorted array: "; 36 | for (int i = 0; i < n; i++) 37 | cout << arr[i] << " "; 38 | return 0; 39 | } 40 | 41 | ``` 42 | 43 | we define a function called bubbleSort that takes an array of integers and the size of the array as its arguments. The function then uses nested loops to compare adjacent elements in the array and swap them if they are in the wrong order. This process is repeated until the entire array is sorted. 44 | 45 | ### Time and Space Complexity of Bubble Sort 46 | 47 | The time complexity of bubble sort is O(n^2), where n is the number of elements in the array. This means that the time taken by the algorithm to sort an array grows quadratically with the size of the input data. Specifically, in the worst case scenario where the array is already sorted in reverse order, the algorithm will take n\*(n-1)/2 comparisons and swaps to sort the array. In the average case, it will take about the same number of comparisons and swaps. 48 | 49 | The space complexity of bubble sort is O(1), which means that the amount of memory required by the algorithm remains constant regardless of the size of the input data. This is because bubble sort only requires a few variables to keep track of the current state of the algorithm, such as the indices of the elements being compared, and a temporary variable used for swapping elements. 50 | -------------------------------------------------------------------------------- /CPP/01-intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to C++ 2 | 3 | C++ is a general-purpose programming language created by Bjarne Stroustrup as an 4 | extension of the C programming language. It was first introduced in 1985 and 5 | provides object-oriented features like classes and inheritance. C++ is widely 6 | used in various applications like game development, system programming, embedded 7 | systems, and high-performance computing. 8 | 9 | C++ is a statically-typed language, meaning that the type of a variable is 10 | determined during compilation, and has an extensive library called the C++ 11 | Standard Library, which provides a rich set of functions, algorithms, and data 12 | structures for various tasks. 13 | 14 | C++ builds upon the features of C, and thus, most C programs can be compiled and 15 | run with a C++ compiler. 16 | 17 | ## Code Example 18 | 19 | Here's a simple example of a C++ program that demonstrates some essential features of the language: 20 | 21 | ```cpp 22 | #include 23 | 24 | // A simple function to add two numbers 25 | int add(int a, int b) { return a + b; } 26 | 27 | class Calculator { 28 | public: 29 | // A member function to multiply two numbers 30 | int multiply(int a, int b) { return a * b; } 31 | }; 32 | 33 | int main() { 34 | int x = 5; 35 | int y = 3; 36 | 37 | // Using the standalone function 'add' 38 | int sum = add(x, y); 39 | std::cout << "Sum: " << sum << std::endl; 40 | 41 | // Using a class and member function 42 | Calculator calc; 43 | int product = calc.multiply(x, y); 44 | std::cout << "Product: " << product << std::endl; 45 | 46 | return 0; 47 | } 48 | ``` 49 | 50 | --- 51 | 52 | ![meme](https://img.devrant.com/devrant/rant/r_77251_3xSNn.jpg) 53 | -------------------------------------------------------------------------------- /CPP/02-c-vs-cpp.md: -------------------------------------------------------------------------------- 1 | # C vs C++ 2 | 3 | C and C++ are two popular programming languages with some similarities, but they also have key differences. C++ is an extension of the C programming language, with added features such as object-oriented programming, classes, and exception handling. Although both languages are used for similar tasks, they have their own syntax and semantics, which makes them distinct from each other. 4 | 5 | ## Syntax and Semantics 6 | 7 | ### C 8 | 9 | - C is a procedural programming language. 10 | - Focuses on functions and structured programming. 11 | - Does not support objects or classes. 12 | - Memory management is manual, using functions like `malloc` and `free`. 13 | 14 | ```c 15 | #include 16 | 17 | void printHello() { 18 | printf("Hello, World!\n"); 19 | } 20 | 21 | int main() { 22 | printHello(); 23 | return 0; 24 | } 25 | ``` 26 | 27 | ### C++ 28 | 29 | - C++ is both procedural and object-oriented. 30 | - Supports both functions and classes. 31 | - Incorporates different programming paradigms. 32 | - Memory management can be manual (like C) or rely on constructors/destructors and smart pointers. 33 | 34 | ```cpp 35 | #include 36 | 37 | class HelloWorld { 38 | public: 39 | void printHello() { std::cout << "Hello, World!" << std::endl; } 40 | }; 41 | 42 | int main() { 43 | HelloWorld obj; 44 | obj.printHello(); 45 | return 0; 46 | } 47 | ``` 48 | 49 | ## Code Reusability and Modularity 50 | 51 | ### C 52 | 53 | - Code reusability is achieved through functions and modular programming. 54 | - High cohesion and low coupling are achieved via structured design. 55 | - Function libraries can be created and included through headers. 56 | 57 | ### C++ 58 | 59 | - Offers better code reusability with classes, inheritance, and polymorphism. 60 | - Code modularity is enhanced through namespaces and well-designed object-oriented hierarchy. 61 | 62 | ## Error Handling 63 | 64 | ### C 65 | 66 | - Error handling in C is done primarily through return codes. 67 | - Lacks support for exceptions or any built-in error handling mechanism. 68 | 69 | ### C++ 70 | 71 | - Offers exception handling, which can be used to handle errors that may occur during program execution. 72 | - Enables catching and handling exceptions with `try`, `catch`, and `throw` keywords, providing more control over error handling. 73 | 74 | ## Conclusion 75 | 76 | ![c-vs-c++](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/88a43133-fbf9-454d-9291-5eada1cc4ddf) 77 | 78 | Both C and C++ are powerful languages with unique features and capabilities. While C is simpler and focuses on procedural programming, C++ offers the versatility of using different programming paradigms and improved code organization. Understanding the differences between these two languages can help you decide which one is more suitable for your specific needs and programming style. 79 | -------------------------------------------------------------------------------- /CPP/04-loops.md: -------------------------------------------------------------------------------- 1 | # Loops in C++ 2 | 3 | Loops are an essential concept in programming that allow you to execute a block of code repeatedly until a specific condition is met. In C++, there are three main types of loops: `for`, `while`, and `do-while`. 4 | 5 | ## For Loop 6 | 7 | A `for` loop is used when you know the number of times you want to traverse through a block of code. It consists of an initialization statement, a condition, and an increment/decrement operation. 8 | 9 | Here's the syntax for a `for` loop: 10 | 11 | ```cpp 12 | for (initialization; condition; increment / decrement) { 13 | // block of code to execute 14 | } 15 | ``` 16 | 17 | For example: 18 | 19 | ```cpp 20 | #include 21 | using namespace std; 22 | 23 | int main() { 24 | for (int i = 0; i < 5; i++) { 25 | cout << "Iteration: " << i << endl; 26 | } 27 | return 0; 28 | } 29 | ``` 30 | 31 | ## While Loop 32 | 33 | A `while` loop runs as long as a specified condition is `true`. The loop checks for the condition before entering the body of the loop. 34 | 35 | Here's the syntax for a `while` loop: 36 | 37 | ```cpp 38 | while (condition) { 39 | // block of code to execute 40 | } 41 | ``` 42 | 43 | For example: 44 | 45 | ```cpp 46 | #include 47 | using namespace std; 48 | 49 | int main() { 50 | int i = 0; 51 | while (i < 5) { 52 | cout << "Iteration: " << i << endl; 53 | i++; 54 | } 55 | return 0; 56 | } 57 | ``` 58 | 59 | ## Do-While Loop 60 | 61 | A `do-while` loop is similar to a `while` loop, with the key difference being that the loop body is executed at least once, even when the condition is `false`. 62 | 63 | Here's the syntax for a `do-while` loop: 64 | 65 | ```cpp 66 | do { 67 | // block of code to execute 68 | } while (condition); 69 | ``` 70 | 71 | For example: 72 | 73 | ```cpp 74 | #include 75 | using namespace std; 76 | 77 | int main() { 78 | int i = 0; 79 | do { 80 | cout << "Iteration: " << i << endl; 81 | i++; 82 | } while (i < 5); 83 | return 0; 84 | } 85 | ``` 86 | 87 | ## While vs Do-While Loop 88 | 89 | ![while-vs-do-while](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/3b283fbf-014d-43d3-ada6-fa8c0477a39c) 90 | 91 | ## Summary 92 | 93 | In summary, loops are an integral part of C++ programming that allow you to execute a block of code multiple times. The three types of loops in C++ are `for`, `while`, and `do-while`. Each type has its own specific use case and can be chosen depending on the desired behavior. 94 | 95 | - [C++ For Loop](https://www.w3schools.com/cpp/cpp_for_loop.asp) 96 | -------------------------------------------------------------------------------- /CPP/08-lambda-function.md: -------------------------------------------------------------------------------- 1 | # Lambda Functions in C++ 2 | 3 | A lambda function, or simply "lambda", is an anonymous (unnamed) function that is defined in place, within your source code, and with a concise syntax. Lambda functions were introduced in C++11 and have since become a widely used feature, especially in combination with the Standard Library algorithms. 4 | 5 | ## Syntax 6 | 7 | Here is a basic syntax of a lambda function in C++: 8 | 9 | ```cpp 10 | [capture-list](parameters) -> return_type { 11 | // function body 12 | }; 13 | ``` 14 | 15 | - **capture-list**: A list of variables from the surrounding scope that the lambda function can access. 16 | - **parameters**: The list of input parameters, just like in a regular function. Optional. 17 | - **return_type**: The type of the value that the lambda function will return. This part is optional, and the compiler can deduce it in many cases. 18 | - **function body**: The code that defines the operation of the lambda function. 19 | 20 | ## Usage Examples 21 | 22 | Here are a few examples to demonstrate the use of lambda functions in C++: 23 | 24 | - Lambda function with no capture, parameters, or return type. 25 | 26 | ```cpp 27 | auto printHello = []() { 28 | std::cout << "Hello, World!" << std::endl; 29 | }; 30 | printHello(); // Output: Hello, World! 31 | ``` 32 | 33 | - Lambda function with parameters. 34 | 35 | ```cpp 36 | auto add = [](int a, int b) { 37 | return a + b; 38 | }; 39 | int result = add(3, 4); // result = 7 40 | ``` 41 | 42 | - Lambda function with capture-by-value. 43 | 44 | ```cpp 45 | int multiplier = 3; 46 | auto times = [multiplier](int a) { 47 | return a * multiplier; 48 | }; 49 | int result = times(5); // result = 15 50 | ``` 51 | 52 | - Lambda function with capture-by-reference. 53 | 54 | ```cpp 55 | int expiresInDays = 45; 56 | auto updateDays = [&expiresInDays](int newDays) { 57 | expiresInDays = newDays; 58 | }; 59 | updateDays(30); // expiresInDays = 30 60 | ``` 61 | 62 | Note that, when using the capture by reference, any change made to the captured variable _inside_ the lambda function will affect its value in the surrounding scope. 63 | 64 | - [Lambdas in C++](https://youtu.be/MH8mLFqj-n8) 65 | - [Lambda Expressions](https://en.cppreference.com/w/cpp/language/lambda) 66 | -------------------------------------------------------------------------------- /CPP/10-static-typing.md: -------------------------------------------------------------------------------- 1 | # Static Typing 2 | 3 | In C++, static typing means that the data type of a variable is determined at compile time, before the program is executed. This means that a variable can be used only with data of a specific type, and the compiler ensures that the operations performed with the variable are compatible with its type. 4 | 5 | C++ is a statically typed language, which means that it uses static typing to determine data types and perform type checking during compile time. This helps with ensuring type safety and can prevent certain types of errors from occurring during the execution of the program. 6 | 7 | Here's a simple code example to demonstrate static typing in C++: 8 | 9 | ```cpp 10 | #include 11 | #include 12 | 13 | int main() { 14 | int num = 42; // 'num' is statically typed as an integer 15 | 16 | std::string and = "The answer to everything in the Universe"; 17 | num = and; // This assignment would cause a compile-time error as the types 18 | // don't match 19 | 20 | std::cout << "The value of num is: " << num << std::endl; 21 | std::cout << "The value of pi is: " << pi << std::endl; 22 | 23 | return 0; 24 | } 25 | ``` 26 | 27 | In the code above, the variable `num` is statically typed as an `int`, and `pi` is statically typed as a `string`. If you attempt to assign the value of `and` to `num`, you'll get a compile-time error. This is because the static typing system ensures that variables are only used with compatible data types. 28 | -------------------------------------------------------------------------------- /CPP/11-dynamic-typing.md: -------------------------------------------------------------------------------- 1 | # Dynamic Typing in C++ 2 | 3 | C++ is known as a statically-typed language, which means the data types of its variables are determined at compile time. However, C++ also provides concepts to have certain level of _dynamic typing_, which means determining the data types of variables at runtime. 4 | 5 | Here is a brief overview of two ways to achieve dynamic typing in C++: 6 | 7 | ## `void*` Pointers 8 | 9 | A `void*` pointer is a generic pointer that can point to objects of any data type. They can be used to store a reference to any type of object without knowing the specific type of the object. 10 | 11 | Example: 12 | 13 | ```cpp 14 | #include 15 | 16 | int main() { 17 | int x = 42; 18 | float y = 3.14f; 19 | std::string z = "Hello, world!"; 20 | 21 | void* void_ptr; 22 | 23 | void_ptr = &x; 24 | std::cout << "int value: " << *(static_cast(void_ptr)) << std::endl; 25 | 26 | void_ptr = &y; 27 | std::cout << "float value: " << *(static_cast(void_ptr)) 28 | << std::endl; 29 | 30 | void_ptr = &z; 31 | std::cout << "string value: " << *(static_cast(void_ptr)) 32 | << std::endl; 33 | 34 | return 0; 35 | } 36 | ``` 37 | 38 | ## `std::any` (C++17) 39 | 40 | C++17 introduced the `std::any` class which represents a generalized type-safe container for single values of any type. 41 | 42 | Example: 43 | 44 | ```cpp 45 | #include 46 | #include 47 | 48 | int main() { 49 | std::any any_value; 50 | 51 | any_value = 42; 52 | std::cout << "int value: " << std::any_cast(any_value) << std::endl; 53 | 54 | any_value = 3.14; 55 | std::cout << "double value: " << std::any_cast(any_value) 56 | << std::endl; 57 | 58 | any_value = std::string("Hello, world!"); 59 | std::cout << "string value: " << std::any_cast(any_value) 60 | << std::endl; 61 | 62 | return 0; 63 | } 64 | ``` 65 | 66 | Keep in mind that both `void*` pointers and `std::any` have performance implications due to the additional type checking and casting that take place during runtime. They should be used carefully and only when absolutely necessary. 67 | -------------------------------------------------------------------------------- /CPP/13-memory-model.md: -------------------------------------------------------------------------------- 1 | # Memory Model in C++ 2 | 3 | The memory model in C++ defines how the program stores and accesses data in computer memory. It consists of different segments, such as the Stack, Heap, Data and Code segments. Each of these segments is used to store different types of data and has specific characteristics. 4 | 5 | ## Stack Memory 6 | 7 | Stack memory is used for automatic storage duration variables, such as local variables and function call data. Stack memory is managed by the compiler, and it's allocation and deallocation are done automatically. The stack memory is also a LIFO (Last In First Out) data structure, meaning that the most recent data allocated is the first to be deallocated. 8 | 9 | ```cpp 10 | void functionExample() { 11 | int x = 10; // x is stored in the stack memory 12 | } 13 | ``` 14 | 15 | ## Heap Memory 16 | 17 | Heap memory is used for dynamic storage duration variables, such as objects created using the `new` keyword. The programmer has control over the allocation and deallocation of heap memory using `new` and `delete` operators. Heap memory is a larger pool of memory than the stack, but has a slower access time. 18 | 19 | ```cpp 20 | void functionExample() { 21 | int* p = new int; // dynamically allocated int in heap memory 22 | *p = 10; 23 | // more code 24 | delete p; // deallocate memory 25 | } 26 | ``` 27 | 28 | ## Data Segment 29 | 30 | The Data segment is composed of two parts: the initialized data segment and the uninitialized data segment. The initialized data segment stores global, static, and constant variables with initial values, whereas the uninitialized segment stores uninitialized global and static variables. 31 | 32 | ```cpp 33 | // Initialized data segment 34 | int globalVar = 10; // global variables 35 | static int staticVar = 10; // static local variables 36 | const int constVar = 10; // constant variables with value 37 | 38 | // Uninitialized data segment 39 | int globalVar; // uninitialized global variables 40 | ``` 41 | 42 | ## Code Segment 43 | 44 | The Code segment (also known as the Text segment) stores the executable code (machine code) of the program. It's usually located in a read-only area of memory to prevent accidental modification. 45 | 46 | ```cpp 47 | void functionExample() { 48 | // The machine code for this function is stored in the code segment. 49 | } 50 | ``` 51 | 52 | In summary, understanding the memory model in C++ helps to optimize the usage of memory resources and improves overall program performance. 53 | -------------------------------------------------------------------------------- /CPP/14-raw-ptr.md: -------------------------------------------------------------------------------- 1 | # Raw Pointers and `new` and `delete` operators 2 | 3 | Raw pointers in C++ are low-level constructs that directly hold a memory address. They can be used for manually allocating memory, creating dynamic arrays, and passing values efficiently, among other things. 4 | 5 | ## `new` Operator 6 | 7 | The `new` operator is used to allocate memory on the heap. The memory allocated using `new` remains available until you explicitly deallocate it using the corresponding `delete` operator. 8 | 9 | Here's an example of using the `new` operator: 10 | 11 | ```cpp 12 | int* ptr = new int; // Dynamically allocates an int on the heap 13 | *ptr = 42; // Assigns the value 42 to the allocated int 14 | ``` 15 | 16 | ## `delete` Operator 17 | 18 | The `delete` operator is used to deallocate memory that has been allocated using `new`. After memory is deallocated, it's available to be reallocated for other purposes. Failing to properly deallocate memory can lead to memory leaks. 19 | 20 | Here's an example of using the `delete` operator: 21 | 22 | ```cpp 23 | int* ptr = new int; // Dynamically allocates an int on the heap 24 | *ptr = 42; // Assigns the value 42 to the allocated int 25 | 26 | delete ptr; // Deallocates the memory assigned to ptr 27 | ``` 28 | 29 | ## `new[]` and `delete[]` Operators 30 | 31 | The `new[]` and `delete[]` operators are used for allocating and deallocating memory for an array of objects. The syntax for `new[]` and `delete[]` is very similar to that of `new` and `delete`. 32 | 33 | Here's an example of using the `new[]` and `delete[]` operators: 34 | 35 | ```cpp 36 | int n = 10; 37 | int* arr = 38 | new int[n]; // Dynamically allocates an array of 10 integers on the heap 39 | 40 | // Set some values in the array 41 | for (int i = 0; i < n; i++) { 42 | arr[i] = i; 43 | } 44 | 45 | delete[] arr; // Deallocates the memory assigned to the array 46 | ``` 47 | 48 | In summary, raw pointers, and `new` and `delete` operators allow manual memory management in C++, providing control over allocation and deallocation. Make sure to always deallocate memory allocated with `new` or `new[]`, to avoid memory leaks in your programs. 49 | -------------------------------------------------------------------------------- /CPP/15-memory-leakage.md: -------------------------------------------------------------------------------- 1 | # Memory Leakage 2 | 3 | Memory leakage occurs when a program allocates memory in the heap but does not release the memory back to the operating system when it is no longer needed. Over time, this leads to exhaustion of available memory, resulting in low system performance or crashes. 4 | 5 | In C++, when you use raw pointers, you need to manage the memory allocation and deallocation manually. In many cases, you will use the `new` keyword to allocate memory for an object in the heap and use `delete` keyword to deallocate that memory when it's no longer needed. Forgetting to do this can cause memory leaks. 6 | 7 | Here's an example: 8 | 9 | ```cpp 10 | void create_memory_leak() { 11 | int* ptr = new int[100]; // Allocating memory in the heap for an array of integers 12 | // Some code... 13 | // Code to deallocate the memory is missing: delete[] ptr; 14 | } // ptr goes out of scope, memory block allocated is not deallocated, causing a memory leak. 15 | ``` 16 | 17 | To avoid memory leaks, you should always ensure that memory is deallocated before a pointer goes out of scope or is reassigned. Some ways to achieve this include using the C++ smart pointers (`std::unique_ptr`, `std::shared_ptr`), RAII (Resource Acquisition Is Initialization) techniques, and containers from the C++ standard library that manage memory allocation internally (e.g., `std::vector`, `std::string`). 18 | 19 | For example, this code will not have a memory leak: 20 | 21 | ```cpp 22 | #include 23 | 24 | void no_memory_leak() { 25 | std::shared_ptr ptr = std::make_shared(100); // Allocating memory in the heap for an array of integers using shared_ptr 26 | // Some code... 27 | } // shared_ptr goes out of scope and it will automatically deallocate the memory block assigned to it. 28 | ``` 29 | -------------------------------------------------------------------------------- /CPP/16-unique-ptr.md: -------------------------------------------------------------------------------- 1 | # Unique Pointer (`unique_ptr`) 2 | 3 | `std::unique_ptr` is a smart pointer provided by the C++ Standard Library. It is a template class that is used for managing single objects or arrays. 4 | 5 | `unique_ptr` works on the concept of _exclusive ownership_ - meaning only one `unique_ptr` is allowed to own an object at a time. This ownership can be transferred or moved, but it cannot be shared or copied. 6 | 7 | This concept helps to prevent issues like dangling pointers, reduce memory leaks, and eliminates the need for manual memory management. When the `unique_ptr` goes out of scope, it automatically deletes the object it owns. 8 | 9 | Let's take a look at some basic examples of using `unique_ptr`: 10 | 11 | ## Creating a unique_ptr 12 | 13 | ```cpp 14 | #include 15 | #include 16 | 17 | int main() { 18 | std::unique_ptr p1(new int(5)); // Initialize with pointer to a new integer 19 | std::unique_ptr p2 = std::make_unique(10); // Preferred method (C++14 onwards) 20 | 21 | std::cout << *p1 << ", " << *p2 << std::endl; 22 | return 0; 23 | } 24 | ``` 25 | 26 | ## Transferring Ownership 27 | 28 | ```cpp 29 | #include 30 | #include 31 | 32 | int main() { 33 | std::unique_ptr p1(new int(5)); 34 | 35 | std::unique_ptr p2 = std::move(p1); // Ownership is transferred from p1 to p2 36 | 37 | if (p1) { 38 | std::cout << "p1 owns the object" << std::endl; 39 | } else if (p2) { 40 | std::cout << "p2 owns the object" << std::endl; 41 | } 42 | 43 | return 0; 44 | } 45 | ``` 46 | 47 | ## Using unique_ptr with Custom Deleters 48 | 49 | ```cpp 50 | #include 51 | #include 52 | 53 | struct MyDeleter { 54 | void operator()(int* ptr) { 55 | std::cout << "Custom Deleter: Deleting pointer" << std::endl; 56 | delete ptr; 57 | } 58 | }; 59 | 60 | int main() { 61 | std::unique_ptr p1(new int(5), MyDeleter()); 62 | return 0; // Custom Deleter will be called when p1 goes out of scope 63 | } 64 | ``` 65 | 66 | Remember that since unique_ptr has exclusive ownership, you cannot use it when you need shared access to an object. For such cases, you can use `std::shared_ptr`. 67 | -------------------------------------------------------------------------------- /CPP/17-shared-ptr.md: -------------------------------------------------------------------------------- 1 | # Shared Pointer 2 | 3 | A `shared_ptr` is a type of smart pointer in C++ that allows multiple pointers to share ownership of a dynamically allocated object. The object will be automatically deallocated only when the last `shared_ptr` that points to it is destroyed. 4 | 5 | When using a `shared_ptr`, the reference counter is automatically incremented every time a new pointer is created, and decremented when each pointer goes out of scope. Once the reference counter reaches zero, the system will clean up the memory. 6 | 7 | ## Code Example 8 | 9 | Here's an example of how to use `shared_ptr`: 10 | 11 | ```cpp 12 | #include 13 | #include 14 | 15 | class MyClass { 16 | public: 17 | MyClass() { std::cout << "Constructor is called." << std::endl; } 18 | ~MyClass() { std::cout << "Destructor is called." << std::endl; } 19 | }; 20 | 21 | int main() { 22 | // create a shared pointer to manage the MyClass object 23 | std::shared_ptr ptr1(new MyClass()); 24 | 25 | { 26 | // create another shared pointer and initialize it with the previously created pointer 27 | std::shared_ptr ptr2 = ptr1; 28 | 29 | std::cout << "Inside the inner scope." << std::endl; 30 | // both pointers share the same object, and the reference counter has been increased to 2 31 | } 32 | 33 | std::cout << "Outside the inner scope." << std::endl; 34 | // leaving the inner scope will destroy ptr2, and the reference counter is decremented to 1 35 | 36 | // the main function returns, ptr1 goes out of scope, and the reference counter becomes 0 37 | // this causes the MyClass object to be deleted and the destructor is called 38 | } 39 | ``` 40 | 41 | Output: 42 | 43 | ``` 44 | Constructor is called. 45 | Inside the inner scope. 46 | Outside the inner scope. 47 | Destructor is called. 48 | ``` 49 | 50 | In this example, `ptr1` and `ptr2` share ownership of the same object. The object is only destroyed when both pointers go out of scope and the reference counter becomes zero. 51 | -------------------------------------------------------------------------------- /CPP/18-structuring-codebase.md: -------------------------------------------------------------------------------- 1 | # Structuring Codebase 2 | 3 | Structuring codebase is an essential part of software development that deals with organizing and modularizing your code to make it more maintainable, efficient, and easier to understand. A well-structured codebase enhances collaboration, simplifies adding new features, and makes debugging faster. In C++, there are various techniques to help you structure your codebase effectively. 4 | 5 | ## Namespaces 6 | 7 | Namespaces are one of the tools in C++ to organize your code by providing a named scope for different identifiers you create, like functions, classes, and variables. They help avoid name clashes and make your code more modular. 8 | 9 | ```cpp 10 | namespace MyNamespace { 11 | int aFunction() { 12 | // function implementation 13 | } 14 | } // namespace MyNamespace 15 | // to use the function 16 | MyNamespace::aFunction(); 17 | ``` 18 | 19 | ## Include Guards 20 | 21 | Include guards are a tool for preventing multiple inclusions of a header file in your project. They consist of preprocessor directives that conditionally include the header file only once, even if it's included in multiple places. 22 | 23 | ```cpp 24 | #ifndef MY_HEADER_FILE_H 25 | #define MY_HEADER_FILE_H 26 | 27 | // Your code here 28 | 29 | #endif // MY_HEADER_FILE_H 30 | ``` 31 | 32 | ## Header and Source Files 33 | 34 | Separating your implementation and declarations into header (_.h) and source (_.cpp) files is a key aspect of structuring your codebase in C++. Header files usually contain class and function declarations, while source files contain their definitions. 35 | 36 | // MyClass.h 37 | 38 | ```cpp 39 | #ifndef MY_CLASS_H 40 | #define MY_CLASS_H 41 | 42 | class MyClass { 43 | public: 44 | MyClass(); 45 | int myMethod(); 46 | }; 47 | 48 | #endif // MY_CLASS_H 49 | ``` 50 | 51 | // MyClass.cpp 52 | 53 | ```cpp 54 | #include "MyClass.h" 55 | 56 | MyClass::MyClass() { 57 | // constructor implementation 58 | } 59 | 60 | int MyClass::myMethod() { 61 | // method implementation 62 | } 63 | ``` 64 | 65 | ## Code Formatting 66 | 67 | Consistent code formatting and indentation play a crucial role in structuring your codebase, making it easier to read and understand for both you and other developers. A style guide such as the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) can help you maintain consistent formatting throughout your project. 68 | -------------------------------------------------------------------------------- /CPP/19-scope.md: -------------------------------------------------------------------------------- 1 | # Scope in C++ 2 | 3 | **Scope** refers to the visibility and accessibility of variables, functions, classes, and other identifiers in a C++ program. It determines the lifetime and extent of these identifiers. In C++, there are four types of scope: 4 | 5 | - **Global scope:** Identifiers declared outside any function or class have a global scope. They can be accessed from any part of the program (unless hidden by a local identifier with the same name). The lifetime of a global identifier is the entire duration of the program. 6 | 7 | ```cpp 8 | #include 9 | 10 | int globalVar; // This is a global variable 11 | 12 | int main() { 13 | std::cout << "Global variable: " << globalVar << std::endl; 14 | } 15 | ``` 16 | 17 | - **Local scope:** Identifiers declared within a function or a block have a local scope. They can be accessed only within the function or the block they were declared in. Their lifetime is limited to the duration of the function/block execution. 18 | 19 | ```cpp 20 | #include 21 | 22 | void localExample() { 23 | int localVar; // This is a local variable 24 | localVar = 5; 25 | std::cout << "Local variable: " << localVar << std::endl; 26 | } 27 | 28 | int main() { 29 | localExample(); 30 | // std::cout << localVar << std::endl; //error: ‘localVar’ was not declared in this scope 31 | } 32 | ``` 33 | 34 | - **Namespace scope:** A namespace is a named scope that groups related identifiers together. Identifiers declared within a namespace have the namespace scope. They can be accessed using the namespace name and the scope resolution operator `::`. 35 | 36 | ```cpp 37 | #include 38 | 39 | namespace MyNamespace { 40 | int namespaceVar = 42; 41 | } 42 | 43 | int main() { 44 | std::cout << "Namespace variable: " << MyNamespace::namespaceVar << std::endl; 45 | } 46 | ``` 47 | 48 | - **Class scope:** Identifiers declared within a class have a class scope. They can be accessed using the class name and the scope resolution operator `::` or, for non-static members, an object of the class and the dot `.` or arrow `->` operator. 49 | 50 | ```cpp 51 | #include 52 | 53 | class MyClass { 54 | public: 55 | static int staticMember; 56 | int nonStaticMember; 57 | 58 | MyClass(int value) : nonStaticMember(value) {} 59 | }; 60 | 61 | int MyClass::staticMember = 7; 62 | 63 | int main() { 64 | MyClass obj(10); 65 | std::cout << "Static member: " << MyClass::staticMember << std::endl; 66 | std::cout << "Non-static member: " << obj.nonStaticMember << std::endl; 67 | } 68 | ``` 69 | 70 | Understanding various types of scope in C++ is essential for effective code structuring and management of resources in a codebase. 71 | -------------------------------------------------------------------------------- /CPP/20-namespace.md: -------------------------------------------------------------------------------- 1 | # Namespaces in C++ 2 | 3 | In C++, a namespace is a named scope or container that is used to organize and enclose a collection of code elements, such as variables, functions, classes, and other namespaces. They are mainly used to divide and manage the code base, giving developers control over name collisions and the specialization of code. 4 | 5 | ## Syntax 6 | 7 | Here's the syntax for declaring a namespace: 8 | 9 | ```cpp 10 | namespace identifier { 11 | // code elements 12 | } 13 | ``` 14 | 15 | ## Using Namespaces 16 | 17 | To access elements within a namespace, you can use the scope resolution operator `::`. Here are some examples: 18 | 19 | ### Declaring and accessing a namespace 20 | 21 | ```cpp 22 | #include 23 | 24 | namespace animals { 25 | std::string dog = "Bobby"; 26 | std::string cat = "Lilly"; 27 | } 28 | 29 | int main() { 30 | std::cout << "Dog's name: " << animals::dog << std::endl; 31 | std::cout << "Cat's name: " << animals::cat << std::endl; 32 | 33 | return 0; 34 | } 35 | ``` 36 | 37 | ### Nesting namespaces 38 | 39 | Namespaces can be nested within other namespaces: 40 | 41 | ```cpp 42 | #include 43 | 44 | namespace outer { 45 | int x = 10; 46 | 47 | namespace inner { 48 | int y = 20; 49 | } 50 | } 51 | 52 | int main() { 53 | std::cout << "Outer x: " << outer::x << std::endl; 54 | std::cout << "Inner y: " << outer::inner::y << std::endl; 55 | 56 | return 0; 57 | } 58 | ``` 59 | 60 | ## `using` Keyword 61 | 62 | You can use the `using` keyword to import namespaced elements into the current scope. However, this might lead to name conflicts if multiple namespaces have elements with the same name. 63 | 64 | ### Using a single element from a namespace 65 | 66 | ```cpp 67 | #include 68 | 69 | namespace animals { 70 | std::string dog = "Bobby"; 71 | std::string cat = "Lilly"; 72 | } 73 | 74 | int main() { 75 | using animals::dog; 76 | 77 | std::cout << "Dog's name: " << dog << std::endl; 78 | 79 | return 0;we do be grindin 80 | } 81 | ``` 82 | 83 | ### Using the entire namespace 84 | 85 | ```cpp 86 | #include 87 | 88 | namespace animals { 89 | std::string dog = "Bobby"; 90 | std::string cat = "Lilly"; 91 | } 92 | 93 | int main() { 94 | using namespace animals; 95 | 96 | std::cout << "Dog's name: " << dog << std::endl; 97 | std::cout << "Cat's name: " << cat << std::endl; 98 | 99 | return 0; 100 | } 101 | ``` 102 | 103 | In conclusion, namespaces are a useful mechanism in C++ to organize code, avoid naming conflicts, and manage the visibility of code elements. 104 | -------------------------------------------------------------------------------- /CPP/21-code-splitting.md: -------------------------------------------------------------------------------- 1 | # Code Splitting 2 | 3 | Code splitting refers to the process of breaking down a large code base into smaller, more manageable files or modules. This helps improve the organization, maintainability, and readability of the code. In C++, code splitting is generally achieved through the use of separate compilation, header files, and source files. 4 | 5 | ### Header Files (.h or .hpp) 6 | 7 | Header files, usually with the `.h` or `.hpp` extension, are responsible for declaring classes, functions, and variables that are needed by multiple source files. They act as an interface between different parts of the code, making it easier to manage dependencies and reduce the chances of duplicated code. 8 | 9 | Example of a header file: 10 | 11 | ```cpp 12 | // example.h 13 | #ifndef EXAMPLE_H 14 | #define EXAMPLE_H 15 | 16 | class Example { 17 | public: 18 | void printMessage(); 19 | }; 20 | 21 | #endif 22 | ``` 23 | 24 | ### Source Files (.cpp) 25 | 26 | Source files, with the `.cpp` extension, are responsible for implementing the actual functionality defined in the corresponding header files. They include the header files as needed and provide the function and class method definitions. 27 | 28 | Example of a source file: 29 | 30 | ```cpp 31 | // example.cpp 32 | #include "example.h" 33 | #include 34 | 35 | void Example::printMessage() { 36 | std::cout << "Hello, code splitting!" << std::endl; 37 | } 38 | ``` 39 | 40 | ### Separate Compilation 41 | 42 | C++ allows for separate compilation, which means that each source file can be compiled independently into an object file. These object files can then be linked together to form the final executable. This provides faster build times when making changes to a single source file since only that file needs to be recompiled, and the other object files can be reused. 43 | 44 | Example of separate compilation and linking: 45 | 46 | ```sh 47 | # Compile each source file into an object file 48 | g++ -c main.cpp -o main.o 49 | g++ -c example.cpp -o example.o 50 | 51 | # Link object files together to create the executable 52 | g++ main.o example.o -o my_program 53 | ``` 54 | 55 | By following the code splitting technique, you can better organize your C++ codebase, making it more manageable and maintainable. 56 | -------------------------------------------------------------------------------- /CPP/22-forward-declaration.md: -------------------------------------------------------------------------------- 1 | # Forward Declaration 2 | 3 | Forward declaration is a way of declaring a symbol (class, function, or variable) before defining it in the code. It helps the compiler understand the type, size, and existence of the symbol. This declaration is particularly useful when we have cyclic dependencies or to reduce compilation time by avoiding unnecessary header inclusions in the source file. 4 | 5 | ## Class Forward Declaration 6 | 7 | To use a class type before it is defined, you can declare the class without defining its members, like this: 8 | 9 | ```cpp 10 | class ClassA; // forward declaration 11 | ``` 12 | 13 | You can then use pointers or references to the class in your code before defining the class itself: 14 | 15 | ```cpp 16 | void do_something (ClassA& obj); 17 | 18 | class ClassB { 19 | public: 20 | void another_function(ClassA& obj); 21 | }; 22 | ``` 23 | 24 | However, if you try to make an object of `ClassA` or call its member functions without defining the class, you will get a compilation error. 25 | 26 | ## Function Forward Declaration 27 | 28 | Functions must be declared before using them, and a forward declaration can be used to declare a function without defining it: 29 | 30 | ```cpp 31 | int add(int a, int b); // forward declaration 32 | 33 | int main() { 34 | int result = add(2, 3); 35 | return 0; 36 | } 37 | 38 | int add(int a, int b) { 39 | return a + b; 40 | } 41 | ``` 42 | 43 | ## Enum and Typedef Forward Declaration 44 | 45 | For `enum` and `typedef`, it is not possible to forward declare because they don't have separate declaration and definition stages. 46 | 47 | Keep in mind that forward declarations should be used cautiously, as they can make the code more difficult to understand. 48 | -------------------------------------------------------------------------------- /CPP/23-structs-classes.md: -------------------------------------------------------------------------------- 1 | # Structures and Classes in C++ 2 | 3 | Structures and classes are user-defined data types in C++ that allow for the grouping of variables of different data types under a single name. They make it easier to manage and organize complex data by creating objects that have particular attributes and behaviors. The main difference between a structure and a class is their default access specifier: members of a structure are public by default, while members of a class are private. 4 | 5 | ## Structures 6 | 7 | A structure is defined using the `struct` keyword, followed by the structure's name and a set of curly braces `{}` enclosing the members (variables and/or functions) of the structure. The members can be of different data types. To create an object of the structure's type, use the structure name followed by the object name. 8 | 9 | Here's an example of defining a structure and creating an object: 10 | 11 | ```cpp 12 | struct Employee { 13 | int id; 14 | std::string name; 15 | float salary; 16 | }; 17 | 18 | Employee e1; // create an object of the 'Employee' structure 19 | ``` 20 | 21 | You can access the members of a structure using the dot operator `.`: 22 | 23 | ```cpp 24 | e1.id = 1; 25 | e1.name = "John Doe"; 26 | e1.salary = 40000; 27 | ``` 28 | 29 | ## Classes 30 | 31 | A class is defined using the `class` keyword, followed by the class's name and a set of curly braces `{}` enclosing the members (variables and/or functions) of the class. Like structures, class members can be of different data types. You can create objects of a class using the class name followed by the object name. 32 | 33 | Here's an example of a class definition and object creation: 34 | 35 | ```cpp 36 | class Student { 37 | int roll_no; 38 | std::string name; 39 | float marks; 40 | 41 | public: 42 | void set_data(int r, std::string n, float m) { 43 | roll_no = r; 44 | name = n; 45 | marks = m; 46 | } 47 | 48 | void display() { 49 | std::cout << "Roll no: " << roll_no 50 | << "\nName: " << name 51 | << "\nMarks: " << marks << std::endl; 52 | } 53 | }; 54 | 55 | Student s1; // create an object of the 'Student' class 56 | ``` 57 | 58 | Since the data members of a class are private by default, we cannot access them directly using the dot operator from outside the class. Instead, we use public member functions to set or get their values: 59 | 60 | ```cpp 61 | s1.set_data(1, "Alice", 95.0); 62 | s1.display(); 63 | ``` 64 | 65 | That's a brief summary of structures and classes in C++. Remember that while they may seem similar, classes provide more control over data encapsulation and can be used to implement more advanced features like inheritance and polymorphism. 66 | -------------------------------------------------------------------------------- /CPP/25-OOP-example.md: -------------------------------------------------------------------------------- 1 | # A sample program 2 | 3 | A damn simple program to demonstrate concepts of OOP. 4 | 5 | ## Program 6 | 7 | ```cpp 8 | #include 9 | #include 10 | #include 11 | 12 | using std::cout; 13 | 14 | class Doctor { 15 | private: 16 | std::string name; 17 | int age; 18 | int id_no; 19 | 20 | public: 21 | Doctor(std::string name, int age, int id_no) 22 | : name(name), age(age), id_no(id_no) {} 23 | 24 | std::string getName() const { return name; } 25 | void setName(const std::string &name) { this->name = name; } 26 | int getAge() const { return age; } 27 | void setAge(int age) { this->age = age; } 28 | int getIdNo() const { return id_no; } 29 | void setIdNo(int id_no) { this->id_no = id_no; } 30 | 31 | virtual void get_name() { 32 | cout << "Name of Doctor is " << name << std::endl; 33 | } 34 | 35 | virtual void task() { cout << "Treat patients" << std::endl; } 36 | 37 | Doctor(){}; 38 | }; 39 | 40 | class surgeon : public Doctor { 41 | public: 42 | surgeon(std::string name): Doctor(name,0,0){}; 43 | void task() override { cout << "Do surgery" << std::endl; } 44 | }; 45 | 46 | class vet : public Doctor { 47 | private: 48 | int no_of_animals; 49 | 50 | public: 51 | vet(std::string name, int no_of_animals) 52 | : Doctor(name, 0, 0), no_of_animals(no_of_animals) {} 53 | 54 | void task() override { cout << "Operates on animals" << std::endl; } 55 | 56 | void no_animals() const { 57 | cout << "No of Animals: " << no_of_animals << std::endl; 58 | } 59 | }; 60 | 61 | int main() { 62 | std::unique_ptr rishabh = 63 | std::make_unique("Rishabh", 20, 100); 64 | rishabh->get_name(); 65 | rishabh->task(); 66 | 67 | std::unique_ptr amit = std::make_unique("Amit"); 68 | amit->get_name(); 69 | amit->task(); 70 | 71 | std::unique_ptr sumit = std::make_unique("Sumit", 1231); 72 | sumit->get_name(); 73 | sumit->no_animals(); 74 | sumit->task(); 75 | 76 | return 0; 77 | } 78 | ``` 79 | -------------------------------------------------------------------------------- /CPP/26-multiple-inheritance.md: -------------------------------------------------------------------------------- 1 | # Multiple Inheritance 2 | 3 | Multiple inheritance is a feature in C++ where a class can inherit characteristics (data members and member functions) from more than one parent class. The concept is similar to single inheritance (where a class inherits from a single base class), but in multiple inheritance, a class can have multiple base classes. 4 | 5 | When a class inherits multiple base classes, it becomes a mixture of their properties and behaviors, and can override or extend them as needed. 6 | 7 | ## Syntax 8 | 9 | Here is the syntax to declare a class with multiple inheritance: 10 | 11 | ```cpp 12 | class DerivedClass : access-specifier BaseClass1, access-specifier BaseClass2, ... 13 | { 14 | // class body 15 | }; 16 | ``` 17 | 18 | The `DerivedClass` will inherit members from both `BaseClass1` and `BaseClass2`. The `access-specifier` (like `public`, `protected`, or `private`) determines the accessibility of the inherited members. 19 | 20 | ## Example 21 | 22 | Here is an example of multiple inheritance in action: 23 | 24 | ```cpp 25 | #include 26 | 27 | // Base class 1 28 | class Animal { 29 | public: 30 | void eat(){ 31 | std::cout << "I can eat!" << std::endl; 32 | } 33 | }; 34 | 35 | // Base class 2 36 | class Mammal { 37 | public: 38 | void breath(){ 39 | std::cout << "I can breathe!" << std::endl; 40 | } 41 | }; 42 | 43 | // Derived class inheriting from both Animal and Mammal 44 | class Dog : public Animal, public Mammal { 45 | public: 46 | void bark(){ 47 | std::cout << "I can bark! Woof woof!" << std::endl; 48 | } 49 | }; 50 | 51 | int main(){ 52 | Dog myDog; 53 | 54 | // Calling members from both base classes 55 | myDog.eat(); 56 | myDog.breath(); 57 | 58 | // Calling a member from the derived class 59 | myDog.bark(); 60 | 61 | return 0; 62 | } 63 | ``` 64 | 65 | ## Note 66 | 67 | In some cases, multiple inheritance can lead to complications such as ambiguity and the "diamond problem". Ensure that you use multiple inheritance judiciously and maintain well-structured and modular classes to prevent issues. 68 | 69 | For more information on C++ multiple inheritance and related topics, refer to C++ documentation or a comprehensive C++ programming guide. 70 | -------------------------------------------------------------------------------- /CPP/26.1-diamond-inheritance.md: -------------------------------------------------------------------------------- 1 | # Diamond Inheritance 2 | 3 | Diamond inheritance is a specific scenario in multiple inheritance where a class is derived from two or more classes, which in turn, are derived from a common base class. It creates an ambiguity that arises from duplicating the common base class, which leads to an ambiguous behavior while calling the duplicate members. 4 | 5 | To resolve this ambiguity, you can use virtual inheritance. A virtual base class is a class that is shared by multiple classes using `virtual` keyword in C++. This ensures that only one copy of the base class is inherited in the final derived class, and thus, resolves the diamond inheritance problem. 6 | 7 | _Example:_ 8 | 9 | ```cpp 10 | #include 11 | using namespace std; 12 | 13 | class Base { 14 | public: 15 | void print() { 16 | cout << "Base class" << endl; 17 | } 18 | }; 19 | 20 | class Derived1 : virtual public Base { 21 | public: 22 | void derived1Print() { 23 | cout << "Derived1 class" << endl; 24 | } 25 | }; 26 | 27 | class Derived2 : virtual public Base { 28 | public: 29 | void derived2Print() { 30 | cout << "Derived2 class" << endl; 31 | } 32 | }; 33 | 34 | class Derived3 : public Derived1, public Derived2 { 35 | public: 36 | void derived3Print() { 37 | cout << "Derived3 class" << endl; 38 | } 39 | }; 40 | 41 | int main() 42 | { 43 | Derived3 d3; 44 | d3.print(); // Now, there is no ambiguity in calling the base class function 45 | d3.derived1Print(); 46 | d3.derived2Print(); 47 | d3.derived3Print(); 48 | 49 | return 0; 50 | } 51 | ``` 52 | 53 | In the code above, `Derived1` and `Derived2` are derived from the `Base` class using virtual inheritance. So, when we create an object of `Derived3` and call the `print()` function from the `Base` class, there is no ambiguity, and the code executes without any issues. 54 | -------------------------------------------------------------------------------- /CPP/27-static-polymorphism.md: -------------------------------------------------------------------------------- 1 | # Static Polymorphism 2 | 3 | Static polymorphism, also known as compile-time polymorphism, is a type of polymorphism that resolves the types and method calls at compile time rather than at runtime. This is commonly achieved through the use of function overloading and templates in C++. 4 | 5 | ## Function Overloading 6 | 7 | Function overloading is a way to create multiple functions with the same name but different parameter lists. The compiler determines the correct function to call based on the types and number of arguments used when the function is called. 8 | 9 | Example: 10 | 11 | ```cpp 12 | #include 13 | 14 | void print(int i) { 15 | std::cout << "Printing int: " << i << std::endtreel; 16 | } 17 | 18 | void print(double d) { 19 | std::cout << "Printing double: " << d << std::endl; 20 | } 21 | 22 | void print(const char* s) { 23 | std::cout << "Printing string: " << s << std::endl; 24 | } 25 | 26 | int main() { 27 | print(5); // Calls print(int i) 28 | print(3.14); // Calls print(double d) 29 | print("Hello"); // Calls print(const char* s) 30 | 31 | return 0; 32 | } 33 | ``` 34 | 35 | ## Templates 36 | 37 | Templates are a powerful feature in C++ that allows you to create generic functions or classes. The actual code for specific types is generated at compile time, which avoids the overhead of runtime polymorphism. The use of templates is the main technique to achieve static polymorphism in C++. 38 | 39 | Example: 40 | 41 | ```cpp 42 | #include 43 | 44 | // Template function to print any type 45 | template 46 | void print(const T& value) { 47 | std::cout << "Printing value: " << value << std::endl; 48 | } 49 | 50 | int main() { 51 | print(42); // int 52 | print(3.14159); // double 53 | print("Hello"); // const char* 54 | 55 | return 0; 56 | } 57 | ``` 58 | 59 | In conclusion, static polymorphism achieves polymorphic behavior during compile time using function overloading and templates, instead of relying on runtime information like dynamic polymorphism does. This can result in more efficient code since method calls are resolved at compile time. 60 | -------------------------------------------------------------------------------- /CPP/28-dynamic-polymorphism.md: -------------------------------------------------------------------------------- 1 | # Dynamic Polymorphism 2 | 3 | Dynamic polymorphism is a programming concept in object-oriented languages like C++ where a derived class can override or redefine methods of its base class. This means that a single method call can have different implementations based on the type of object it is called on. 4 | 5 | Dynamic polymorphism is achieved through **virtual functions**, which are member functions of a base class marked with the `virtual` keyword. When you specify a virtual function in a base class, it can be overridden in any derived class to provide a different implementation. 6 | 7 | ## Example 8 | 9 | Here's an example in C++ demonstrating dynamic polymorphism. 10 | 11 | ```cpp 12 | #include 13 | 14 | // Base class 15 | class Shape { 16 | public: 17 | virtual void draw() { std::cout << "Drawing a shape" << std::endl; } 18 | }; 19 | 20 | // Derived class 1 21 | class Circle : public Shape { 22 | public: 23 | void draw() override { std::cout << "Drawing a circle" << std::endl; } 24 | }; 25 | 26 | // Derived class 2 27 | class Rectangle : public Shape { 28 | public: 29 | void draw() override { std::cout << "Drawing a rectangle" << std::endl; } 30 | }; 31 | 32 | int main() { 33 | Shape* shape; 34 | Circle circle; 35 | Rectangle rectangle; 36 | 37 | // Storing the address of circle 38 | shape = &circle; 39 | 40 | // Call circle draw function 41 | shape->draw(); 42 | 43 | // Storing the address of rectangle 44 | shape = &rectangle; 45 | 46 | // Call rectangle draw function 47 | shape->draw(); 48 | 49 | return 0; 50 | } 51 | ``` 52 | 53 | This code defines a base class `Shape` with a virtual function `draw`. Two derived classes `Circle` and `Rectangle` both override the `draw` function to provide their own implementations. Then in the `main` function, a pointer of type `Shape` is used to call the respective `draw` functions of `Circle` and `Rectangle` objects. The output of this program will be: 54 | 55 | ``` 56 | Drawing a circle 57 | Drawing a rectangle 58 | ``` 59 | 60 | As you can see, using dynamic polymorphism, we can determine at runtime which `draw` method should be called based on the type of object being used. 61 | 62 | ## **Never use `malloc` in C++** 63 | 64 | In this code calling of `f()` with the _a2_ object will cause a segmentation fault as _a2_ is instantiated using `malloc` 65 | So don't use `malloc` use `new` keyword instead in C++ 66 | 67 | ```cpp 68 | class A { 69 | public: 70 | int x = 3; 71 | virtual void f() { std::cout << "abc"; } 72 | }; 73 | 74 | A* a1 = new A; 75 | A* a2 = (A*)malloc(sizeof(A)); 76 | 77 | std::cout << a1->x; // print "3" 78 | std::cout << a2->x; // undefined value!! 79 | a1->f(); // print "abc" 80 | a2->f(); // segmentation fault 81 | ``` 82 | -------------------------------------------------------------------------------- /CPP/28.1-virtual-methods.md: -------------------------------------------------------------------------------- 1 | # Virtual Methods 2 | 3 | Virtual methods are a key aspect of dynamic polymorphism in C++. They allow subclass methods to override the methods of their base class, so the appropriate method is called depending on the actual type of an object at runtime. 4 | 5 | To declare a method as virtual, simply use the `virtual` keyword in the method's declaration in the base class. This tells the compiler that the method should be treated as a virtual method, allowing it to be overridden by derived classes. 6 | 7 | ## Code Example 8 | 9 | Here's an example demonstrating virtual methods: 10 | 11 | ```cpp 12 | #include 13 | 14 | // Base class 15 | class Shape { 16 | public: 17 | virtual double area() const { 18 | return 0; 19 | } 20 | }; 21 | 22 | // Derived class 23 | class Circle : public Shape { 24 | public: 25 | Circle(double r) : radius(r) {} 26 | 27 | // Override the base class method 28 | double area() const override { 29 | return 3.14 * radius * radius; 30 | } 31 | 32 | private: 33 | double radius; 34 | }; 35 | 36 | // Derived class 37 | class Rectangle : public Shape { 38 | public: 39 | Rectangle(double w, double h) : width(w), height(h) {} 40 | 41 | // Override the base class method 42 | double area() const override { 43 | return width * height; 44 | } 45 | 46 | private: 47 | double width; 48 | double height; 49 | }; 50 | 51 | int main() { 52 | Circle c(5); 53 | Rectangle r(4, 6); 54 | 55 | Shape* shape = &c; 56 | std::cout << "Circle's area: " << shape->area() << std::endl; 57 | 58 | shape = &r; 59 | std::cout << "Rectangle's area: " << shape->area() << std::endl; 60 | 61 | return 0; 62 | } 63 | ``` 64 | 65 | In this example, we define a base class `Shape` that has a virtual method `area`. This method is then overridden by the derived classes `Circle` and `Rectangle`. By using a virtual method and a base class pointer to the derived objects, we can invoke the appropriate `area` method based on the actual object type at runtime. 66 | -------------------------------------------------------------------------------- /CPP/28.2-virtual-tables.md: -------------------------------------------------------------------------------- 1 | # Virtual Tables 2 | 3 | Virtual Tables (or Vtable) are a mechanism used by C++ compilers to support dynamic polymorphism. In dynamic polymorphism, the appropriate function is called at runtime, depending on the actual object type. 4 | 5 | When a class contains a virtual function, the compiler creates a virtual table for that class. This table contains function pointers to the virtual functions defined in the class. Each object of that class has a pointer to its virtual table (_vptr_, virtual pointer), which is automatically initialized by the compiler during object construction. 6 | 7 | ## Example 8 | 9 | Let's consider the following example: 10 | 11 | ```cpp 12 | class Base { 13 | public: 14 | virtual void function1() { std::cout << "Base::function1" << std::endl; } 15 | 16 | virtual void function2() { std::cout << "Base::function2" << std::endl; } 17 | }; 18 | 19 | class Derived : public Base { 20 | public: 21 | void function1() override { 22 | std::cout << "Derived::function1" << std::endl; 23 | } 24 | 25 | void function3() { std::cout << "Derived::function3" << std::endl; } 26 | }; 27 | 28 | int main() { 29 | Base* obj = new Derived(); // create a Derived object and assign a pointer 30 | // of type Base* 31 | obj->function1(); // calls Derived::function1, due to dynamic polymorphism 32 | obj->function2(); // calls Base::function2 33 | 34 | delete obj; 35 | return 0; 36 | } 37 | ``` 38 | 39 | In this example, when a `Derived` object is created, the compiler generates a Vtable for `Derived` class, containing pointers to its virtual functions: 40 | 41 | - `Derived::function1` (overridden from `Base`) 42 | - `Base::function2` (inherits from Base) 43 | 44 | The `_vptr_` pointer in the `Derived` object points to this Vtable. When the `function1` is called on the `Base` pointer pointing to the `Derived` object, the function pointer in the Vtable is used to call the correct function (in this case, `Derived::function1`). Similarly, the call to `function2` calls `Base::function2`, since it's the function pointer stored in the Vtable for `Derived` class. 45 | 46 | Note that `function3` is not part of the Vtable, as it is not a virtual function. 47 | 48 | ## Diagram explanation 49 | 50 | ![image](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/dfc6208d-810e-4f51-9997-5473c1fb7f3f) 51 | -------------------------------------------------------------------------------- /CPP/29.1-try-catch-throw.md: -------------------------------------------------------------------------------- 1 | # Exception handling in C++ 2 | 3 | C++ exception handling is a mechanism that allows you to handle errors that occur during the execution of a program. It is built on three keywords: try, catch, and throw. 4 | 5 | - The `try` keyword is used to define a block of code that can throw an exception. 6 | - The `catch` keyword is used to define a block of code that is executed when a particular exception is thrown. 7 | - The `throw` keyword is used to throw an exception. 8 | 9 | The following is an example of a simple try-catch block: 10 | 11 | ```c++ 12 | int main() { 13 | try { 14 | // This code might throw an exception. 15 | throw(something can be of any type) 16 | } catch (int e) { 17 | // This code is executed if an exception of type int is thrown. 18 | std::cout << "An integer exception was thrown: " << e << std::endl; 19 | } catch (std::string e) { 20 | // This code is executed if an exception of type std::string is thrown. 21 | std::cout << "A string exception was thrown: " << e << std::endl; 22 | } 23 | } 24 | ``` 25 | 26 | In this example, the `try` block contains the code that might throw an exception. The `catch` blocks are executed if a particular type of exception is thrown. In this case, there are two catch blocks: one for exceptions of type `int` and one for exceptions of type `std::string`. 27 | 28 | If an exception is thrown in the `try` block, the first `catch` block that matches the type of the exception is executed. If no `catch` block matches the type of the exception, the program terminates abnormally. 29 | 30 | You can also have multiple catch blocks for the same type of exception. In this case, the catch blocks are executed in the order in which they appear in the code. 31 | 32 | The `throw` keyword is used to throw an exception. The syntax for the `throw` keyword is: 33 | 34 | ```c++ 35 | throw expression; 36 | ``` 37 | 38 | The `expression` can be any value. When the `throw` keyword is executed, the `expression` is passed to the first `catch` block that matches its type. 39 | 40 | Here is an example of a `throw` statement: 41 | 42 | ```c++ 43 | throw 10; 44 | ``` 45 | 46 | This statement throws an exception of type `int` with the value of 10. 47 | 48 | The `try`, `catch`, and `throw` keywords can be used to handle a wide variety of errors. For example, you can use them to handle errors that occur when opening files, reading from files, or writing to files. You can also use them to handle errors that occur when dividing by zero, accessing invalid memory, or calling a function that does not exist. 49 | -------------------------------------------------------------------------------- /CPP/30-exit-codes.md: -------------------------------------------------------------------------------- 1 | # Exit codes 2 | 3 | In C++, the `exit` function is used to terminate the execution of a program. The value supplied as an argument to `exit` is returned to the operating system as the program's exit code. By convention, a return code of zero means that the program completed successfully. 4 | 5 | Here are some of the commonly used exit codes in C++: 6 | 7 | - `EXIT_SUCCESS`: 0, indicates successful termination of the program. 8 | - `EXIT_FAILURE`: 1, indicates abnormal termination of the program. 9 | - `SIGINT`: 2, indicates that the program was terminated by a user interrupt (Ctrl+C). 10 | - `SIGSEGV`: 11, indicates that the program attempted to access a memory location that is not accessible. 11 | - `SIGABRT`: 6, indicates that the program was aborted by a call to the `abort` function. 12 | - `SIGKILL`: 9, indicates that the program was killed by the operating system. 13 | 14 | You can also use user-defined exit codes. However, it is important to avoid using the following exit codes, as they have special meanings: 15 | 16 | - 1, 2, 126-165, and 255 17 | 18 | The `exit` function is defined in the `` header file. 19 | 20 | Here is an example of how to use the `exit` function: 21 | 22 | ```c++ 23 | #include 24 | 25 | int main() { 26 | if (some_error_occurred) { 27 | exit(1); // Terminate the program with an exit code of 1 28 | } 29 | 30 | // Do something else 31 | 32 | return 0; // Terminate the program with an exit code of 0 33 | } 34 | ``` 35 | 36 | ## Example: Using return in `main` 37 | 38 | ```cpp 39 | #include 40 | 41 | int main() { 42 | // Some code here... 43 | 44 | if (/*some error condition*/) { 45 | std::cout << "An error occurred." << std::endl; 46 | return 1; 47 | } 48 | 49 | // More code here... 50 | 51 | if (/*another error condition*/) { 52 | std::cout << "Another error occurred." << std::endl; 53 | return 2; 54 | } 55 | 56 | return 0; // Successful execution 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /CPP/31-access-violations.md: -------------------------------------------------------------------------------- 1 | ## Access Violation in C++ 2 | 3 | An access violation in C++ is an error that occurs when a program tries to access a memory address that it does not have permission to access. This can happen for a variety of reasons, such as: 4 | 5 | - Trying to access a memory address that is outside of the allocated memory space for the program. 6 | - Trying to access a memory address that is already in use by another program or process. 7 | - Trying to access a memory address that has been marked as invalid. 8 | 9 | ### Code Examples 10 | 11 | Here are some code examples of access violations: 12 | 13 | #### Trying to access a memory address that is outside of the allocated memory space for the program: 14 | 15 | ```c++ 16 | int* p = new int[10]; // Allocate memory for an array of 10 integers. 17 | *p = 10; // This is fine. 18 | p[10] = 20; // This will cause an access violation because p is pointing to an address outside of the allocated memory space. 19 | ``` 20 | 21 | #### Trying to access a memory address that is already in use by another program or process: 22 | 23 | ```c++ 24 | int* q = (int*)malloc(sizeof(int)); // Allocate memory for an integer on the heap. 25 | *q = 10; // This is fine. 26 | p = q; // This is also fine. 27 | *p = 20; // This will cause an access violation because p is now pointing to the same memory address as q, which is still in use by another program or process. 28 | ``` 29 | 30 | #### Trying to access a memory address that has been marked as invalid: 31 | 32 | ```c++ 33 | int* r = new int; // Allocate memory for an integer. 34 | delete r; // This marks the memory address pointed to by r as invalid. 35 | *r = 20; // This will cause an access violation because the memory address pointed to by r is no longer valid. 36 | ``` 37 | 38 | ## How to Avoid Access Violations 39 | 40 | To avoid access violations, it is important to be careful about how you access memory in C++. Here are a few tips: 41 | 42 | - Always use the `new` keyword to allocate memory for your program. This will help to prevent you from accidentally accessing memory that is outside of your allocated space. 43 | - Use the `delete` keyword to free up memory when you are finished with it. This will help to prevent memory leaks, which can also lead to access violations. 44 | - Be careful about using pointers. Pointers can be used to access memory addresses directly, which can make it easier to accidentally cause an access violation. 45 | - Use the `assert()` macro to check for errors in your code. This can help to catch access violations early on, before they cause a crash. 46 | 47 | ## How to Debug Access Violations 48 | 49 | If you do encounter an access violation, there are a few things you can do to debug the problem: 50 | 51 | - Use a debugger to step through your code and see where the access violation is occurring. 52 | - Check the values of your variables to see if they are pointing to invalid memory addresses. 53 | - Use the `valgrind` tool to scan your code for memory errors. 54 | 55 | By following these tips, you can help to prevent access violations in your C++ code. 56 | -------------------------------------------------------------------------------- /CPP/34-templates.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | Templates in C++ are a powerful feature that allows you to write generic code. This means you can write a function or a 4 | class that can work with different data types, without having to write separate versions of the function or class for 5 | each data type. 6 | 7 | **Function Templates** 8 | 9 | Function templates are functions that can work with different data types. Here's an example of a function template that 10 | prints out the value of an object of any type: 11 | 12 | ```cpp 13 | template void print(T value) { std::cout << value << std::endl; } 14 | 15 | print(1); 16 | print("Hello"); 17 | print(5.3); 18 | ``` 19 | 20 | In the above code, `T` is a placeholder for any data type. When you call the `print` function, you can pass an object of 21 | any type for which operator `<<` is overloaded, and the `print` function will print out the value of the object. 22 | 23 | **Class Templates** 24 | 25 | Class templates are classes that can work with different data types. Here's an example of a class template that holds an object of any type: 26 | 27 | ```cpp 28 | template class Box { 29 | T value; 30 | 31 | public: 32 | Box(T value) : value(value) {} 33 | void print() { std::cout << value << std::endl; } 34 | }; 35 | ``` 36 | 37 | In the above code, `T` is a placeholder for any data type. When you create an object of the `Box` class, you can specify 38 | the type of the object, and the `Box` class will hold an object of that type. 39 | 40 | **Template Specialization** 41 | 42 | Template specialization is a way to provide a different implementation of a function or a class for a specific data 43 | type. Here's an example of a function template and a specialized version of the function for the `int` data type: 44 | 45 | ```cpp 46 | // Function template 47 | template T add(T a, T b) { return a + b; } 48 | 49 | // Specialized version for int 50 | template <> int add(int a, int b) { return a + b; } 51 | ``` 52 | 53 | In the above code, the `add` function template can add two objects of any type. The specialized version of the `add` 54 | function for the `int` data type adds two `int` objects. 55 | 56 | **Class Template Specialization** 57 | 58 | Similarly, you can provide a different implementation of a class for a specific data type. Here's an example of a class 59 | template and a specialized version of the class for the `int` data type: 60 | 61 | ```cpp 62 | // Class template 63 | template class Box { 64 | T value; 65 | 66 | public: 67 | Box(T value) : value(value) {} 68 | void print() { std::cout << value << std::endl; } 69 | }; 70 | 71 | // Specialized version for int 72 | template <> class Box { 73 | int value; 74 | 75 | public: 76 | Box(int value) : value(value) {} 77 | void print() { 78 | std::cout << "This is an integer box. Value: " << value << std::endl; 79 | } 80 | }; 81 | ``` 82 | 83 | In the above code, the `Box` class template can hold an object of any type. The specialized version of the `Box` class 84 | for the `int` data type holds an `int` object and prints a different message when the `print` method is called. 85 | -------------------------------------------------------------------------------- /CPP/35-name-mangling.md: -------------------------------------------------------------------------------- 1 | # Name Mangling 2 | 3 | Name mangling in C++ is a technique used to resolve conflicts between identifiers that have the same name but belong to 4 | different scopes or have different types. This process transforms function names into unique identifiers that can be 5 | distinguished by the linker during the linking phase of compilation. 6 | 7 | However, it's important to note that name mangling is platform-specific. The C++ ABI (Application Binary Interface) of 8 | the platform you are running on defines the name mangling. There are two common C++ ABIs, which are the Itanium ABI and 9 | Microsoft's ABI. Depending on the platform and the compiler being used, different name mangling schemes may be applied . 10 | 11 | The C++ standard does not define a specific naming convention for mangled names, so different compilers may implement 12 | name mangling differently. However, mangled names typically start with \_Z followed by the mangled name of the function 13 | or variable, including namespace, classes, and name, with a length and the identifier 1. 14 | 15 | Here's an example of name mangling in action: 16 | 17 | ```cpp 18 | namespace MyNamespace { 19 | class MyClass { 20 | public: 21 | void myMethod(int param); 22 | }; 23 | } // namespace MyNamespace 24 | ``` 25 | 26 | The mangled name of `myMethod` might look something like `_ZN11MyNamespace7MyClass9myMethodEi`, which includes the 27 | namespace (`MyNamespace`), the class (`MyClass`), the method name (`myMethod`), and the parameter type (`int`). 28 | 29 | To understand the mangled names, you can use a tool like `c++filt`. `c++filt` is a command-line utility that comes with 30 | the GNU Binutils package and is used to demangle C++ symbols. By piping the output of `nm` (another command-line utility 31 | that lists symbols from object files) through `c++filt`, you can see the demangled names of the symbols. 32 | 33 | Here's how you might use `c++filt`: 34 | 35 | ```bash 36 | nm myprogram.o | c++filt 37 | ``` 38 | 39 | This command will print out the names of all symbols in `myprogram.o`, with the mangled names replaced by their 40 | demangled equivalents. 41 | 42 | Output: 43 | 44 | ``` 45 | 0000000000003df0 d _DYNAMIC 46 | 0000000000003fe8 d _GLOBAL_OFFSET_TABLE_ 47 | 0000000000002000 R _IO_stdin_used 48 | w _ITM_deregisterTMCloneTable 49 | w _ITM_registerTMCloneTable 50 | 0000000000002004 r __GNU_EH_FRAME_HDR 51 | 0000000000004010 D __TMC_END__ 52 | 0000000000004010 B __bss_start 53 | w __cxa_finalize@GLIBC_2.2.5 54 | 0000000000004000 D __data_start 55 | 0000000000004008 D __dso_handle 56 | w __gmon_start__ 57 | U __libc_start_main@GLIBC_2.34 58 | 0000000000004010 D _edata 59 | 0000000000004018 B _end 60 | 000000000000112c T _fini 61 | 0000000000001000 T _init 62 | 0000000000001020 T _start 63 | 0000000000004000 W data_start 64 | 0000000000001119 T main 65 | ``` 66 | -------------------------------------------------------------------------------- /Data-Structures/Hash-Maps/01-maps-intro.md: -------------------------------------------------------------------------------- 1 | ## What is a Map ? 2 | 3 | A map data structure, also known as an associative array or dictionary, is a fundamental concept in computer science. 4 | 5 | It's used to store and manage a collection of **key-value pairs**, where each key is a unique identifier and each value 6 | is associated with that key. 7 | 8 | This allows for efficient and fast retrieval of values based on their corresponding keys. 9 | 10 | ## Why Map ? 11 | 12 | The map data structure is particularly useful when you want to: 13 | 14 | 1. **Retrieve Data Efficiently:** With a map, you can quickly look up a value using its associated key, making searching 15 | for specific information a lot faster compared to searching through an entire list. 16 | 17 | 2. **Maintain Relationships:** Maps are great for maintaining relationships between different pieces of data. For 18 | instance, you can use a map to associate a person's name with their contact information. 19 | 20 | 3. **Count Occurrences:** Maps are excellent for counting the occurrences of elements in a collection. For example, you 21 | could count the frequency of each word in a text. 22 | 23 | 4. **Implementing Algorithms:** Many algorithms and problem-solving techniques involve maps to store intermediate 24 | results or to track progress efficiently. 25 | 26 | 5. **Implementing Hash Tables:** Under the hood, a common way to implement maps is using hash tables, which are 27 | fundamental in computer science. 28 | 29 | ## Initialization 30 | 31 | In C++, the map data structure is called a `std::map.` 32 | 33 | It's part of the C++ Standard Template Library (STL) and provides a way to store key-value pairs in a sorted order based 34 | on the keys. 35 | 36 | The keys in a `std::map` are unique, which means that each key can only appear once in the map. 37 | 38 | ```cpp 39 | #include // include standard map library 40 | ``` 41 | 42 | --- 43 | 44 | ```cpp 45 | // declaring a map in STL 46 | std::map name_of_map; 47 | ``` 48 | 49 | --- 50 | 51 | ```cpp 52 | // example : 53 | std::map mp; 54 | ``` 55 | 56 | --- 57 | 58 | ```cpp 59 | // Adding a key-value pair in a map 60 | 61 | #include 62 | using namespace std; 63 | 64 | int main() { 65 | 66 | map scores; 67 | 68 | // adding value to a key :- 69 | // here, "Amit" is the key and 99 is the value. 70 | scores["Amit"] = 99; 71 | 72 | cout << "Amit's Score: " << scores["Amit"] << endl; 73 | 74 | return 0; 75 | } 76 | 77 | // output: 99 78 | 79 | /* 80 | Note that scores["Amit"] = 99; 81 | is similar to what we do to initialise 82 | an array element by arr[index] = some_value; 83 | In case of a map, the index value can be of any data type. 84 | In above example the key was a string, hence it was quoted inside a "...". 85 | */ 86 | ``` 87 | -------------------------------------------------------------------------------- /Data-Structures/Hash-Maps/02-map-methods.md: -------------------------------------------------------------------------------- 1 | ## STL Map Methods 2 | 3 | 1. **Insertion:** 4 | 5 | `mapName[key] = value` - Inserts a key-value pair into the map. 6 | 7 | `insert({key, value})` - Inserts a key-value pair into the map. 8 | 9 | 2. Access: 10 | 11 | `mapName[key]` - Accesses the value associated with the given key. 12 | 13 | `at(key)` - Accesses the value associated with the given key (throws an exception if the key is not present). 14 | 15 | 3. **Search:** 16 | 17 | `find(key)` - Searches for a key in the map and returns an iterator pointing to it. 18 | 19 | `count(key)` - Returns the number of occurrences of a key (0 or 1 in a map). 20 | 21 | 4. **Deletion:** 22 | 23 | `erase(key)` - Removes the element with the given key from the map. 24 | 25 | `clear()` - Removes all elements from the map. 26 | 27 | 5. **Size and Empty Check:** 28 | 29 | `size()` - Returns the number of elements in the map. 30 | 31 | `empty()` - Checks if the map is empty. 32 | 33 | 6. **Iterators:** 34 | 35 | `begin()` - Returns an iterator pointing to the first element. 36 | 37 | `end()` - Returns an iterator pointing just beyond the last element. 38 | You can use iterators to traverse through the map's elements. 39 | 40 | 7. **Range-based Loop:** 41 | 42 | You can use a range-based loop to iterate through the map's elements easily. 43 | 44 | 8. **Value Modification:** 45 | 46 | You can modify the value associated with a key directly using the key as an index. 47 | 48 | 9. **Bounds:** 49 | 50 | `lower_bound(key)` - Returns an iterator to the first element with a key not less than the given key. 51 | 52 | `upper_bound(key)` - Returns an iterator to the first element with a key greater than the given key. 53 | 54 | 10. **Key Comparison:** 55 | 56 | `key_comp()` - Returns a function that compares keys. 57 | 58 | `value_comp()` - Returns a function that compares values. 59 | 60 | 11. **Swapping:** 61 | 62 | `swap(map2)` - Swaps the contents of two maps. 63 | -------------------------------------------------------------------------------- /Data-Structures/Hash-Maps/03-number-of-occurrences.md: -------------------------------------------------------------------------------- 1 | ## Find Number of Occurrence : Integers 2 | 3 | ```cpp 4 | #include 5 | using namespace std; 6 | int main() { 7 | int n; cin >> n; 8 | int arr[n]; 9 | for(int i = 0; i < n; i++){ 10 | cin >> arr[i]; 11 | } 12 | 13 | // precompute 14 | int hash[n] = {0}; 15 | for(int i = 0; i < n; i++){ 16 | // go to the index of hash array and do a +1 17 | hash[arr[i]]++; 18 | } 19 | 20 | //fetch 21 | int num; cin >> num; 22 | 23 | cout << hash[num] << endl; 24 | 25 | return 0; 26 | } 27 | ``` 28 | 29 | ``` 30 | output : 31 | 5 --> size of array 32 | 1 1 2 2 3 --> array elements 33 | 2 --> target element 34 | 2 --> number of it's occurrence 35 | ``` 36 | 37 | --- 38 | 39 | ### A short explanation : 40 | 41 | - We create an array `arr` of size `n`, and take input of the elements. 42 | 43 | - The Precomputation is done by creating an hash array with size `n`. 44 | 45 | - **Example** : if `arr[i] = 1`, then `hash[1]` will be incremented by 1 and so on. 46 | 47 | --- 48 | 49 | ## Find Number of Occurrence : Characters (LowerCase) 50 | 51 | ```cpp 52 | #include 53 | using namespace std; 54 | int main(){ 55 | string s; cin >> s; 56 | 57 | // precompute 58 | int hash[26] = {0}; 59 | for (int i = 0; i < s.size(); i++){ 60 | hash[s[i] - 'a']++; 61 | } 62 | 63 | // fetch 64 | char c; cin >> c; 65 | 66 | cout << hash[c - 'a'] << endl; 67 | 68 | return 0; 69 | } 70 | ``` 71 | 72 | --- 73 | 74 | ### A short explanation : 75 | 76 | - We create an string `s`, and take it's input. 77 | 78 | - The Precomputation begins by creating an hash array with size 26. (index 0 to 25) 79 | 80 | - Then we keep incrementing the count of every `s[i] - 'a'` in hash array. 81 | 82 | - As we know that `s[i]` is a character and **ASCII** value of a is 97, hence we subtract the current character with 'a' to get an integer **ASCII** value equivalent to it's positon in hash array. 83 | 84 | - **Example** : if s`[i] = 'c'`, then `'c' - 'a' = 99 - 97 = 2`, which then refers it's index (position) in hash array. (0 based indexing). 85 | 86 | - While printing output, `hash[c - 'a']` refers to the index value which comes after subtracting character `c - 'a'`. 87 | 88 | - **Example** : If `c = 'd'`, then `hash['d' - 'a'] == hash[100 - 97] == hash[3]`, which is the place where count of `'d'` is stored. 89 | 90 | --- 91 | 92 | ### Tags : 93 | 94 | `#hashing` `#find-occurrence` 95 | -------------------------------------------------------------------------------- /Data-Structures/Hash-Maps/04-max-occurrence.md: -------------------------------------------------------------------------------- 1 | ## Find the maximum Occurring number. 2 | 3 | ```cpp 4 | #include 5 | using namespace std; 6 | 7 | int main() { 8 | int n; cin >> n; 9 | int arr[n]; 10 | for(int i = 0; i < n; i++){ 11 | cin >> arr[i]; 12 | } 13 | 14 | // create an unordered_map to store the frequencies of the elements 15 | unordered_map mp; 16 | for(int i = 0; i < n; i++){ 17 | mp[arr[i]]++; 18 | } 19 | 20 | // find the maximum value in the map 21 | int max_val = -1; 22 | int max_key = -1; 23 | 24 | for(auto it = mp.begin(); it != mp.end(); it++){ 25 | if(it->second > max_val){ 26 | max_val = it->second; 27 | max_key = it->first; 28 | } 29 | } 30 | 31 | // print the maximum occurring number 32 | cout << max_key << " -> " << max_val << endl; 33 | 34 | return 0; 35 | } 36 | ``` 37 | 38 | ``` 39 | Output: 40 | 41 | 5 --> size of array 42 | 1 1 1 2 3 --> array elements 43 | 1 -> 3 --> most occurred value -> how many times it occurred. 44 | ``` 45 | 46 | --- 47 | 48 | ### Explanation : 49 | 50 | - In this code, the mp `unordered_map` is used to store the frequencies of the elements in the `arr` array. 51 | 52 | - The `max_val` variable is used to store the maximum value in the map and the `max_key` variable is used to store the key corresponding to the maximum value. 53 | 54 | - The for loop iterates over the `mp` map and finds the maximum value. 55 | 56 | - `it->first` is the key, `it->second` is the value of that particular iterator value. 57 | 58 | - The maximum occurring number and it's occurrence is then printed. 59 | -------------------------------------------------------------------------------- /Data-Structures/Hash-Maps/05-python-maps.md: -------------------------------------------------------------------------------- 1 | # Hash-Maps/Dictionary in Python 2 | 3 | Dictionaries are ordered maps in python 4 | 5 | ```py 6 | a = {} 7 | a["rishabh"] = 12 8 | a["amit"] += 1 # this will raise a key 9 | 10 | # two ways to avoid this 11 | 12 | # 1. Use get() method with a default value 13 | b["amit"] += b.get("amit", 0) + 1 # if "amit" doesnt exist in the hashmap, b.get() will return the default value 0 in 14 | # this case 15 | 16 | # 2. we can use a defaultdict, which will put default values for types if they dont exist in 17 | # dictionary 18 | 19 | from collections import defatuldict 20 | b = defaultdict(int) # int will be the type of the value 21 | b["amit"] += 1 # will initialize b["amit"] as 0 and then increment it 22 | b["amit"] # output will be 1 23 | 24 | # For looping around the hashmap use the items() method or keys()/values() for specifically keys or values 25 | 26 | c = { 27 | "rishabh" : 12, 28 | "amit": 13, 29 | } 30 | 31 | for i, j in c.items(): 32 | print(f"{i}, {j}") # output: rishabh, 12 33 | # amit, 13 34 | for i in c.keys(): pass # will just give keys 35 | for i in c.values(): pass # will just give values 36 | 37 | c.pop("rishabh") # will remove 'rishabh' key value pair from the map 38 | 39 | ``` 40 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Array/02-second-largest.md: -------------------------------------------------------------------------------- 1 | ## Find Second largest element in the array 2 | 3 | Approach : 4 | 5 | 1. Brute : Sort --> Traverse from n - 2 --> if (a[i] != largest) ==> secondLargest == a[i] 6 | 7 | Time Complexity : O(N Log N) + 1 ==> [Sort] 8 | 9 | Code : 10 | 11 | ```cpp 12 | int secondLargest(vector& arr, int n) { 13 | sort(arr.begin(), arr.end()); // O(N Log N) 14 | int secondLargest = arr[arr.size() - 2]; 15 | return secondLargest; 16 | } 17 | ``` 18 | 19 | 2. Better : Traverse for Largest --> set SecondLargest = -1 --> Traverse again --> if (arr[i] > SecondLargest and arr[i] != largest) ==> secondLargest == a[i] 20 | 21 | Time Complexity : O(2N) ==> [Two Traversals] 22 | 23 | Code : 24 | 25 | ```cpp 26 | int secondLargest(vector& arr, int n) { 27 | int largest = arr[0]; 28 | int secondLargest = -1; 29 | for (int i = 0; i < n; i++) { // O(N) 30 | if (arr[i] > largest) { 31 | largest = arr[i]; 32 | } 33 | } 34 | for (int i = 0; i < n; i++) { // O(N) 35 | if (arr[i] > secondLargest && arr[i] != largest) { 36 | secondLargest = arr[i]; 37 | } 38 | } 39 | return secondLargest; 40 | } 41 | ``` 42 | 43 | 3. Optimal : set FirstElement to Largest, set SecondLargest = -1 --> Traverse from 0 to n --> if found an a[i] > Largest ==> SecondLargest == Largest and Largest == arr[i] --> else if found an a[i] < largest but a[i] > SecondLargest ==> SecondLargest == a[i] 44 | 45 | Time Complexity : O(N) ==> [Single Traversal] 46 | 47 | Code : 48 | 49 | ```cpp 50 | int secondLargest(vector& arr, int n) { 51 | int largest = arr[0]; 52 | int secondLargest = -1; 53 | for (int i = 0; i < n; i++) { // O(N) 54 | if (arr[i] > largest) { 55 | secondLargest = largest; 56 | largest = arr[i]; 57 | } else if (arr[i] < largest && arr[i] > secondLargest) { 58 | secondLargest = arr[i]; 59 | } 60 | } 61 | return secondLargest; 62 | } 63 | ``` 64 | 65 | --- 66 | 67 | ### Bonus : Find Second Smallest 68 | 69 | ```cpp 70 | int secondLargest(vector& arr, int n) { 71 | int smallest = arr[0]; 72 | int secondSmallest = INT_MAX; 73 | for (int i = 0; i < n; i++) { 74 | if (arr[i] < smallest) { 75 | secondSmallest = smallest; 76 | smallest = arr[i]; 77 | } else if (arr[i] != smallest && arr[i] < secondSmallest) { 78 | secondSmallest = arr[i]; 79 | } 80 | } 81 | return secondSmallest; 82 | } 83 | ``` 84 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Basics/01-linked-list.md: -------------------------------------------------------------------------------- 1 | # Linked Lists. 2 | 3 | 4 | 5 | **Table of content :** 6 | 7 | - [Why do we need Linked list ?](#why-do-we-need-linked-list) 8 | - [What is a Linked List ?](#what-is-a-linked-list) 9 | - [Structure of a Linked List](#structure-of-a-linked-list) 10 | - [Linked List Terminologies](#linked-list-terminologies) 11 | - [A depiction of a Linked list in heap memory](#a-depiction-of-a-linked-list-in-heap-memory) 12 | 13 | 14 | --- 15 | 16 | ### Why do we need Linked list ? 17 | 18 | We need a data structure which is dynamic in nature, means it should not have a fixed size. The size could be changed during the run-time. 19 | 20 | An **array** with size 10 will be allocated a fixed 10 sized in memory and hence it cannot span or contract during the run-time. 21 | 22 | A **vector** can span double to its size if extra elements are meant to be added, but it ultimately wastes the remaining allocated memory. 23 | 24 | Hence we need an optimal data structure which can grow or shrink on run time with no memory waste. 25 | 26 | --- 27 | 28 | ### What is a Linked List ? 29 | 30 | A Linked list is a **Linear** but **Non-contiguous** Data Structure. Unlike arrays, hey are **Dynamic** in nature. 31 | 32 | Linked list elements are randomly placed in the heap memory and hence **cannot be indexed**. 33 | 34 | --- 35 | 36 | ### Structure of a Linked List 37 | 38 | **If Linked list elements are non-contiguous, then how do they form a linear collection?** 39 | 40 | This is only possible because, in a Linked list, each member element is linked to the other with a reference to its memory location, means each linked list element stores its **data** and also a pointer to point the **memory address** of its next element. 41 | 42 | **But there's no Primitive or Collective data type which can hold two things at a time!** 43 | 44 | So we need to create a **Self Defined data type (a struct or a class)**, which can hold two values, the data (of any type) and a pointer to point a memory address at the same time. 45 | 46 | Let's call this self defined data type a **NODE**. Now each node will have two halves, the first half will store data, the other half will store a pointer. A single node may look like a capsule with two halves: 47 | 48 | ``` 49 | [ Data | Pointer* ] 50 | ``` 51 | 52 | --- 53 | 54 | ### Linked List Terminologies 55 | 56 | 1. **Head node** : The first node of Linked list is the head node and acts as a starting point for most of the operations. 57 | 2. **Tail node** : The last node of Linked list which points to the NULL Pointer 0x0. 58 | 59 | --- 60 | 61 | ### A depiction of a Linked list in heap memory : 62 | 63 | ![Linked-List-1](https://github.com/amitsuthar69/assets/blob/main/linked-lists/linked-list-1.png?raw=true) 64 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Basics/02-node-creation.md: -------------------------------------------------------------------------------- 1 | ## Creating a Node in Linked List 2 | 3 | The self defined data type to create a node could be a struct or a class. 4 | 5 | ### C++ Implementation : 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | class Node { 12 | public: 13 | // node members 14 | int data; // data 15 | Node* next; // pointer 16 | 17 | // constructor 18 | Node(int val) { 19 | data = val; 20 | next = nullptr; 21 | } 22 | }; 23 | 24 | int main() { 25 | vector arr = {2, 3, 4, 6, 3}; 26 | const Node* n1 = new Node(arr[1]); // creating a new node 27 | cout << n1->data << endl; // print 3 28 | cout << n1->next << endl; // prints Null address 29 | delete n1 30 | return 0; 31 | } 32 | ``` 33 | 34 | The line `Node *n1 = new Node(arr[1]);` of code is allocating memory for a new object of the class named `Node` on the heap and assigning the address of the object to a pointer variable named `next`. 35 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Basics/03-traversal.md: -------------------------------------------------------------------------------- 1 | ## Traversing in a Linked List 2 | 3 | ### Algorithm : 4 | 5 | 1. Create a temporary node (temp) which points to head node. 6 | 2. Unless the temp points to a NULL node, do the following things repeatedly : 7 | - print current temp node's data. 8 | - move the temp node ahead by assigning the temp node to its next node. 9 | 10 | ```cpp 11 | class Solution { 12 | public: 13 | void display(Node* head) { 14 | Node* temp = head; 15 | while (temp != NULL) { 16 | std::cout << temp->data << " "; 17 | temp = temp->next; 18 | } 19 | } 20 | }; 21 | ``` 22 | 23 | --- 24 | 25 | ### Depiction of traversal 26 | 27 | ![linked-list-1](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/98f79c73-5949-4bd7-8001-7201c0f46e44) 28 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Basics/04-implementation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::cout, std::endl; 4 | 5 | class Node { 6 | public: 7 | int data; 8 | Node* next; 9 | 10 | Node(int data) { 11 | this->data = data; 12 | this->next = NULL; 13 | } 14 | }; 15 | 16 | void insertAtHead(Node*& head, int data) { 17 | Node* temp = new Node(data); 18 | temp->next = head; 19 | head = temp; 20 | } 21 | 22 | void insertAtTail(Node*& tail, int data) { 23 | Node* temp = new Node(data); 24 | tail->next = temp; 25 | tail = temp; 26 | } 27 | 28 | void insertAtPosition(Node*& head, Node*& tail, int pos, int data) { 29 | Node* temp = head; 30 | int cnt = 1; 31 | 32 | // if inserting at first pos 33 | if (pos == 1) { 34 | insertAtHead(head, data); 35 | return; 36 | } 37 | 38 | // if inserting at last pos 39 | if (temp->next == NULL) { 40 | insertAtTail(tail, data); 41 | return; 42 | } 43 | 44 | while (cnt < pos - 1) { 45 | temp = temp->next; 46 | cnt++; 47 | } 48 | 49 | Node* nodeToInsert = new Node(data); 50 | nodeToInsert->next = temp->next; 51 | temp->next = nodeToInsert; 52 | } 53 | 54 | void printLinkedList(Node*& head) { 55 | Node* temp = head; 56 | while (temp != NULL) { 57 | cout << temp->data << " "; 58 | temp = temp->next; 59 | } 60 | cout << endl; 61 | } 62 | 63 | int main() { 64 | Node* node1 = new Node(10); 65 | 66 | // create head and tail pointer. 67 | Node* head = node1; 68 | Node* tail = node1; 69 | 70 | cout << "Initial List : "; 71 | printLinkedList(head); 72 | 73 | insertAtHead(head, 12); 74 | 75 | cout << "List after insertion at head : "; 76 | printLinkedList(head); 77 | 78 | insertAtTail(tail, 13); 79 | 80 | cout << "List after insertion at tail : "; 81 | printLinkedList(head); 82 | 83 | insertAtPosition(head, tail, 3, 14); 84 | 85 | cout << "List after insertion at 3rd position : "; 86 | printLinkedList(head); 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Doubly-Linked-List/00-DLL-basics.md: -------------------------------------------------------------------------------- 1 | ## Doubly Linked List 2 | 3 | Unlike a singly linked list, where each node only has a pointer to the next node, A doubly linked list (DLL) has two pointers: 4 | 5 | - Next pointer: Points to the next node in the list. 6 | - Previous pointer: Points to the previous node in the list. 7 | 8 | This additional Previous pointer allows traversing the list in both directions (forward and backward). 9 | 10 | Advantages of DLL over singly linked list: 11 | 12 | - Bidirectional traversal: Traversing the list in both directions is possible. 13 | - Efficient deletion: Removing a node is faster as the previous node's pointer can be updated directly. 14 | - Insertion before a node: Inserting a new node before a specific node is easier. 15 | 16 | --- 17 | 18 | ### DLL Node Creation 19 | 20 | ```cpp 21 | class Node { 22 | public: 23 | int data; 24 | Node* next; 25 | Node* back; 26 | 27 | Node(int val, Node* next1, Node* back1){ 28 | data = val; 29 | next = next1; 30 | back = back1; 31 | } 32 | 33 | Node(int val){ 34 | data = val; 35 | next = nullptr; 36 | back = nullptr; 37 | } 38 | }; 39 | ``` 40 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Doubly-Linked-List/01-arr2DLL.md: -------------------------------------------------------------------------------- 1 | ## Convert array to DLL 2 | 3 | ### Algorithm 4 | 5 | 1. Create a `head` node and assign it to arrays's first element. 6 | 2. Create a `prev` pointer to keep a track of just previous node. Initially, prev will point to head. 7 | 3. Start iteration form 1 to array size, during each iteration do these : 8 | - Create a `temp` node and assign it the `i`th value of array. The `temp`'s next will point to `null` where as the `temp`'s back will point to `prev` node. 9 | - For now the scenario is, the temp's back is connected to previous node, but still te prev node is disconnected to the temp node. So connect the prev node to temp node by pointing it to temp. 10 | - Now as we've a brand new node, bring the prev node ahead (to the temp node.) 11 | 4. Return the `head` node in the end. 12 | 13 | --- 14 | 15 | ### Implementation 16 | 17 | ```cpp 18 | Node* arr2DLL(vector &arr){ 19 | Node* head = new Node(arr[0]); 20 | Node* prev = head; 21 | for (int i = 1; i < arr.size(); i++){ 22 | Node* temp = new Node(arr[i], nullptr, prev); 23 | prev->next = temp; 24 | prev = temp; 25 | } 26 | return head; 27 | } 28 | ``` 29 | 30 | --- 31 | 32 | ### Depiction 33 | 34 | ![arr2DLL](https://github.com/amitsuthar69/assets/blob/main/linked-lists/arr2Dll.png?raw=true) 35 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Doubly-Linked-List/02-delete-head-tail.md: -------------------------------------------------------------------------------- 1 | ## Delete head and tail of a DLL 2 | 3 | ### Algorithm : 4 | 5 | **Delete Head :** 6 | 7 | 1. If DLL is empty or is a singleton, return NULL. 8 | 2. Else, make a `prev` pointer and point to head to keep a trck of head. 9 | 3. Move the current head pointer to the next node. 10 | 4. Point new head's back to NULL and prev's next to NULL to disconnect the first node. 11 | 5. Free up the memory by deleting the prev node. 12 | 6. Return new head. 13 | 14 | **Delete tail :** 15 | 16 | 1. If DLL is empty or is a singleton, return NULL. 17 | 2. Else, create a temporary tail pointer and point it to head. 18 | 3. Start traversing the DLL unless we reach the actual tail node. 19 | 4. Tail's previous node becomes our new tail by pointing actual tail's back to the previous node. This will help us to track the new tail node. 20 | 5. Now point actual tail's back and new tail's next to NULL so it gets disconnected from the DLL. 21 | 6. Free up the memory by deleting the actual tree. 22 | 7. Return head. 23 | 24 | --- 25 | 26 | ```cpp 27 | Node* deleteHeadDLL(Node* head){ 28 | if (head == NULL || head->next == NULL){ 29 | return NULL; 30 | } 31 | 32 | Node* prev = head; 33 | head = head->next; 34 | head->back = NULL; 35 | prev->next = NULL; 36 | 37 | delete prev; 38 | return head; 39 | } 40 | 41 | Node* deleteTailDLL(Node* head){ 42 | if (head == NULL || head->next == NULL){ 43 | return NULL; 44 | } 45 | Node* tail = head; 46 | while(tail->next != NULL){ 47 | tail = tail->next; 48 | } 49 | Node* newTail = tail->back; 50 | tail->back = NULL: 51 | newTail->next = NULL; 52 | 53 | delete tail 54 | return head; 55 | } 56 | ``` 57 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Doubly-Linked-List/03-delete-kth-node.md: -------------------------------------------------------------------------------- 1 | ## Delete Kth Node of a DLL. 2 | 3 | ### Algorithm 4 | 5 | 1. Check if the DLL is empty, if so return NULL. 6 | 2. Create a pointer (here kNode) which will track the kth node to be deleted and initially point it to head. 7 | 3. Travers the DLL with the help of a counter and reach the kth node to be deleted. 8 | 4. Once reached, create 2 pointers, one pointing kNode's previous node and other pointing the just next node respectively. 9 | 5. Check if the kNode is a head or tail node with appropriate conditions and delete head or tail accordingly. 10 | 6. If not, point prev's next to front and front's back to prev, disconnecting both of them with kNode. 11 | 7. Still, kNode is conneted to prev and front so disconnect it as well. 12 | 8. Free up the kNode and return head. 13 | 14 | --- 15 | 16 | ### Implementation 17 | 18 | ```cpp 19 | Node* deleteKthNode(Node* head, int k){ 20 | if (head == NULL) return NULL; 21 | 22 | int cnt = 0; 23 | Node* kNode = head; // a pointer to the node to be deleted. 24 | while (kNode != NULL) { 25 | cnt++; 26 | if (cnt == k) break; 27 | kNode = kNode->next; 28 | } 29 | 30 | Node* prev = kNode->back; 31 | Node* front = kNode->next; 32 | 33 | if (prev == NULL && front == NULL){ 34 | return NULL; 35 | } 36 | else if (prev == NULL) { 37 | deleteHeadDLL(head); 38 | } 39 | else if (front == NULL){ 40 | deleteTailDLL(head) 41 | } 42 | 43 | prev->next = front; 44 | front->back = prev; 45 | kNode->next = kNode->back = NULL; 46 | delete kNode; 47 | return head; 48 | } 49 | 50 | 51 | Node* deleteHeadDLL(Node* head){ 52 | if (head == NULL || head->next == NULL){ 53 | return NULL; 54 | } 55 | 56 | Node* prev = head; 57 | head = head->next; 58 | head->back = NULL; 59 | prev->next = NULL; 60 | 61 | delete prev; 62 | return head; 63 | } 64 | 65 | Node* deleteTailDLL(Node* head){ 66 | if (head == NULL || head->next == NULL){ 67 | return NULL; 68 | } 69 | Node* tail = head; 70 | while(tail->next != NULL){ 71 | tail = tail->next; 72 | } 73 | Node* newTail = tail->back; 74 | tail->back = NULL: 75 | newTail->next = NULL; 76 | 77 | delete tail 78 | return head; 79 | } 80 | 81 | ``` 82 | 83 | ```cpp 84 | // delete given node : 85 | void deleteNode(Node* temp){ 86 | Node* prev = temp->back; 87 | Node* front = temp-> next; 88 | 89 | if (front = NULL){ 90 | prev->next = NULL; 91 | temp->back = NULL; 92 | free(temp); 93 | return; 94 | } 95 | prev->next = front; 96 | front->back = prev; 97 | 98 | temp->next = temp->back = NULL; 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Doubly-Linked-List/04-insert-head-tail.md: -------------------------------------------------------------------------------- 1 | ## Insert a Node before Head and Tail of a DLL 2 | 3 | ```cpp 4 | Node* insertBeforeHead(Node* head, int val){ 5 | if (head == NULL){ 6 | Node* newHead = new Node(val); 7 | return newHead; 8 | } 9 | Node* newHead = new Node(val, head, nullptr); 10 | head->back = newHead; 11 | return newHead; 12 | } 13 | 14 | Node* insertBeforeTail(Node* head, int val){ 15 | if (head == NULL){ 16 | Node* newHead = new Node(val); 17 | return newHead; 18 | } 19 | 20 | if (head->next == NULL && head->back == NULL) { 21 | insertBeforeHead(head, val); 22 | } 23 | 24 | Node* temp = head; 25 | while(temp->next->next != NULL){ 26 | temp = temp->next; 27 | } 28 | Node* front = temp->next; 29 | Node* newNode = new Node(val, front, temp); 30 | temp->next = front->back = newNode; 31 | return head; 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Doubly-Linked-List/05-reverseDLL.md: -------------------------------------------------------------------------------- 1 | ## Reverse the given DLL 2 | 3 | ### Brute Force (Stack Method) : 4 | 5 | 1. Create a temp pointer, point it to head. 6 | 2. Create a stack of type `int`. 7 | 3. Traverse through the DLL, push the current node's data into stack. 8 | 4. Once traversed, reassign temp to head and start traversing again. 9 | 5. In this traversal, assign the temp's data to stack's top and then pop the stack's top element. 10 | 6. In the end, return head of the revrsed DLL. 11 | 12 | **Time Complexity : O(2N)** 13 | 14 | **Space Complexity : O(N)** 15 | 16 | ```cpp 17 | Node* reverseDLL(Node* head){ 18 | Node* temp = head; 19 | stack st; 20 | while(temp != nullptr){ 21 | st.push(temp->data); 22 | temp = temp->next; 23 | } 24 | temp = head; 25 | while(temp != nullptr){ 26 | temp->data = st.top(); 27 | st.pop(); 28 | temp = temp->next; 29 | } 30 | return head; 31 | } 32 | ``` 33 | 34 | --- 35 | 36 | ### Optimal approach (Pointer Swap) : 37 | 38 | In this approach, we'll use a swaping method to swap `prev` and `next` pointers. This idea comes from generic two number swap equation, which is, temp = a, a = b, b = temp. 39 | 40 | 1. Check if the DLL is null or a singleton, in that case return the head itself. 41 | 2. Create a current pointer which points to head and a prev pointer which will point to null. 42 | 3. Start travering the DLL, For each current node : 43 | - Bring the prev pointer to it's back. 44 | - Point the current's back to current's next. 45 | - Point the current's next to back. 46 | - Move the current ahead. 47 | 4. Return prev's back, as current goes to null. 48 | 49 | **Time Complexity : O(N)** 50 | 51 | **Space Complexity : O(1)** 52 | 53 | ```cpp 54 | Node* reverseDLL(Node* head){ 55 | if (head == nullptr || head->next == nullptr){ 56 | return head; 57 | } 58 | Node* current = head; 59 | Node* prev = nullptr; 60 | 61 | while(current != nullptr){ 62 | prev = current->back; 63 | curreent->back = current->next; 64 | current->next = prev; 65 | current = current->back; 66 | } 67 | return prev->back; 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/01-array2LL.md: -------------------------------------------------------------------------------- 1 | ## Convert an Array to a Linked List 2 | 3 | ### Algorithm : 4 | 5 | 1. Create a head node and assign the first array element to it. 6 | 2. Create an another node "mover" which then points to head. 7 | 3. Start iteration from 1 to array size. 8 | 4. For each iteration, 9 | 10 | - Create a temp node and assign its `data` to the `i`th element of current array. 11 | 12 | - Now we want our head node to point the next nodes, but we can't have multiple heads, so we'll take help of mover node. 13 | 14 | Make the mover node point the next node, cause the mover ultimately points head node. 15 | 16 | - Now shift the mover node to temp node. 17 | 18 | 5. Return head of the Linked List. 19 | 20 | --- 21 | 22 | ### Implementation : 23 | 24 | ```cpp 25 | Node* convertArrToLL(const vector& arr) { 26 | Node* head = new Node(arr[0]); 27 | Node* mover = head; 28 | for (int i = 1; i < arr.size(); i++) { 29 | Node* temp = new Node(arr[i]); 30 | mover->next = temp; 31 | mover = temp; 32 | } 33 | return head; 34 | } 35 | ``` 36 | 37 | --- 38 | 39 | ### Depiction 40 | 41 | ![arr2LL](https://github.com/amitsuthar69/assets/blob/main/linked-lists/arr2LL.png?raw=true) 42 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/02-delete-head-tail.md: -------------------------------------------------------------------------------- 1 | ## Delete the head and tail of a Linked List 2 | 3 | ### Algorithm 4 | 5 | **Delete head :** 6 | 7 | 1. Check if the head is not NULL. 8 | 2. Create a temp pointer and point it to head. 9 | 3. Point the head to its adjacent node. 10 | 4. Free the previous head node. 11 | 12 | **Delete tail :** 13 | 14 | 1. Check if head isn't NULL or a singleton LL. 15 | 2. Create a temp pointer, point it to head. 16 | 3. Traverse till the second last node. (a second last node will be a node whose next->next is a NULL) 17 | 4. Once reached the second last node, free the next node (tail). 18 | 5. Point second last node to NULL 19 | 20 | --- 21 | 22 | ### Implementation 23 | 24 | ```cpp 25 | Node* deleteHead(Node* head){ 26 | if (head == NULL) return head; // edge case 27 | Node* temp = head; 28 | head = head->next; 29 | delete temp; // c++ lacks garbage collection 30 | return head; 31 | } 32 | 33 | Node* deleteTail(Node* head){ 34 | // either empty or singleton 35 | if (head == NULL || head->next == NULL) { 36 | return NULL; 37 | } 38 | Node* temp = head; 39 | while(temp->next->next != NULL) { 40 | temp = temp->next; 41 | } 42 | delete temp->next; 43 | temp->next = nullptr; 44 | return head; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/03-delete-kth-node.md: -------------------------------------------------------------------------------- 1 | ## Delete Kth node of a Linked list 2 | 3 | ### Algorithm 4 | 5 | 1. Check if LL is empty. 6 | 2. Check if the `k`th node we've to delete is the head itslef. 7 | 3. Create a counter to keep a track of current position in LL. 8 | 4. Create a prev node to keep a sustain the `k-1`th node. 9 | 5. Iterate thorugh the LL and do the following steps : 10 | 11 | - Increase counter to record current position. 12 | - Bring the prev node to temp and move temp ahead. 13 | - If current position is equal to k : 14 | - Point the prev node to prev's next to next node (means skipping the `k`th node). 15 | - Free the temp node (`k`th node) as it is no longer needed. 16 | - Break the loop to avoid further iterations. 17 | 18 | 6. Return head of the LL 19 | 20 | --- 21 | 22 | ### Implementation 23 | 24 | ```cpp 25 | Node* deleteK(Node* head, int k) { 26 | if (head == nullptr) 27 | return nullptr; 28 | if (k == 1) { // if head node 29 | Node* temp = head; 30 | head = head->next; 31 | delete temp; 32 | return head; 33 | } 34 | int cnt = 0; 35 | Node* temp = head; 36 | Node* prev = nullptr; 37 | while (temp != nullptr) { 38 | cnt++; 39 | if (cnt == k) { 40 | prev->next = prev->next->next; 41 | free(temp); 42 | break; 43 | } 44 | prev = temp; 45 | temp = temp->next; 46 | } 47 | return head; 48 | } 49 | ``` 50 | 51 | --- 52 | 53 | The step to create a temp node and then deleting it, is a memory saving option. The head could be deleted by just pointing current head to its next and then just returning the new head, but then we waste memory worth one node. 54 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/04-insert-head-tail.md: -------------------------------------------------------------------------------- 1 | ## Insert a new Node at Head and Tail of a Linked List 2 | 3 | ### Algorithm 4 | 5 | **Insertion at head** 6 | 7 | 1. Check if LL is empty, incase create new Node with new value. 8 | 2. Create a new node and assign the data to it. 9 | 3. Set the `next` pointer of the new node to the current head of the list. 10 | 4. Update the head of the list to the new node. 11 | 12 | --- 13 | 14 | **Insert at tail** 15 | 16 | 1. Check if LL is empty, incase create new Node with new value. 17 | 2. Create a temp node, point it to head. 18 | 3. Iterate through the LL unless reach the tail node. 19 | 4. Create a new node, assign it the new value. 20 | 5. Make the tail node point the temp node. 21 | 22 | --- 23 | 24 | ### Implementation 25 | 26 | ```cpp 27 | Node* insertAtHead(Node* head, int newVal){ 28 | if (head == nullptr) { 29 | return new Node(val); 30 | } 31 | /* assuming the constructor only accepts 32 | value and not pointer with it */ 33 | Node* temp = new Node(val); 34 | temp->next = head; 35 | temp = head; 36 | } 37 | 38 | Node* insertAtTail(Node* head, int newVal){ 39 | if (head == nullptr) { 40 | return new Node(newVal); 41 | } 42 | Node* temp = head; 43 | while (temp->next != nullptr){ 44 | temp = temp->next; 45 | } 46 | Node* newTail = new Node(newVal); 47 | temp->next = newTail; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/05-insert-at-kth-pos.md: -------------------------------------------------------------------------------- 1 | ## Insert a new node kth position 2 | 3 | ### Algorithm 4 | 5 | 1. Check if LL is empty, incase create new Node with new value. 6 | 2. If k is equal to 1, use insertAtHead logic. 7 | 3. Create a counter to keep track of just behind node of `k`th node. 8 | 4. Create a temp node and point to head. 9 | 5. Traverse thorugh the LL and check the following : 10 | - For each node, increase the counter and likewise move the temp ahead. 11 | - If it is `k-1`th node, create new Node with new value. 12 | - Point the new node's next to temp's next. 13 | - Point temp's next to new node and break the loop. 14 | 6. Return head. 15 | 16 | --- 17 | 18 | ### Implementation 19 | 20 | ```cpp 21 | Node* insertAtK(Node* head, int k, int newVal){ 22 | if (head == nullptr) { 23 | if (k == 1) return new Node(newVal); 24 | } 25 | 26 | if (k == 1) { 27 | Node* newNode = new Node(newVal); 28 | newNode->next = head; 29 | return newNode; 30 | } 31 | 32 | int cnt = 0; 33 | Node* temp = head; 34 | while (temp != nullptr){ 35 | cnt++; 36 | if (cnt == (k-1)){ 37 | Node* x = new Node(newVal); 38 | x->next = temp->next; 39 | temp->next = x; 40 | break; 41 | } 42 | temp = temp->next; 43 | } 44 | return head; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/07-segEvenOddNodes.md: -------------------------------------------------------------------------------- 1 | ## Segrregate Odd Even Nodes of a LL. 2 | 3 | Given the head of a singly linked list, group all the nodes with odd indices together followed by the nodes with even indices, and **return the reordered list.** 4 | 5 | **The first node is considered odd, and the second node is even, and so on.** 6 | 7 | Note that the relative order inside both the even and odd groups should remain as it was in the input. 8 | 9 | Expected TC: O(N), SC: O(1) 10 | 11 | --- 12 | 13 | ### Algorithm 14 | 15 | **Brute Force (Data replacement)** 16 | 17 | We can traverse the LL twice by jumping on alternate nodes, and store the elements into a list. Then again traversing the LL but this time assigning the segrregated values to LL. 18 | 19 | But then we end up with a TC of O(2N) {N/2 for each alternate jump and N for data re-assignment.} and a SC of O(N) for the list which is not acceptable. 20 | 21 | **Optimal (Pointer swapping)** 22 | 23 | 1. Assign the head node to a odd and next node to an even pointer. 24 | 2. Also point an another temporary pointer just to know where did the first even node was. 25 | 3. The idea of alternate jumps would be same, but this time it would be done in single traversal and the traversal will stop when the even node reaches the `nullptr` or points to it. 26 | 4. During traversal, point the odd nodes's next to its next's next so that the even node in between is skipped and move the odd pointer ahead. Do it for the even node as well. 27 | 5. Once all the odd and even indexed nodes are connected, connect the last odd node to our temporarily created pointer to connect the odd LL with even LL. 28 | 6. return the head. 29 | 30 | --- 31 | 32 | ### Implementation 33 | 34 | ```cpp 35 | Node* oddEvenNodes(Node* head){ 36 | Node* odd = head; 37 | Node* even = head->next; 38 | Node* evenNode = head->next; // memoization 39 | while (even != nullptr && even->next != nullptr){ 40 | odd->next == odd->next->next; 41 | odd = odd->next; 42 | even->next = even->next->next; 43 | even = even->next; 44 | } 45 | odd->next = evenNode; 46 | return head; 47 | } 48 | ``` 49 | 50 | --- 51 | 52 | ### Demonstration 53 | 54 | ![oddEvenSegrre](https://github.com/amitsuthar69/assets/blob/main/linked-lists/oddEvensegrregate.png?raw=true) 55 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/09-delete-nth-node-from-back.md: -------------------------------------------------------------------------------- 1 | ## Delete Nth Node from Back in a LL 2 | 3 | Given the head of a linked list, remove the nth node from the end of the list and return its head. 4 | 5 | **Expected TC : O(N), SC : O(1)** 6 | 7 | ### Algorithm 8 | 9 | **Brute Force (Two passes)** 10 | 11 | Two reach the node to be deleted from back, we can first traverse the entire LL to know the size (using a counter) and then traverse again till `count - n`th node. 12 | 13 | By this, we can reach the previous node of `n`th node and then we can easily remove the next node (technically `n`th node). 14 | 15 | **TC : O(Length + Length-N) ~ O(2N) _unacceptable_, SC : O(1)** 16 | 17 | ```cpp 18 | Node* removeNthFromEnd(Node* head, int n) { 19 | Node* temp = head; 20 | int cnt = 0; 21 | while(temp != nullptr){ 22 | cnt++; 23 | temp = temp->next; 24 | } 25 | temp = head; 26 | int res = cnt - n; 27 | 28 | // Check if the node to be deleted is the head 29 | if (res == 0) { 30 | Node* newHead = head->next; 31 | delete head; 32 | return newHead; 33 | } 34 | 35 | // Move to the node before the one to be deleted 36 | while (temp != nullptr){ 37 | res--; 38 | if (res == 0){ 39 | break; 40 | } 41 | temp = temp->next; 42 | } 43 | 44 | if (temp->next != nullptr) { 45 | Node* deleteNode = temp->next; 46 | temp->next = temp->next->next; 47 | delete deleteNode; 48 | } 49 | return head; 50 | } 51 | ``` 52 | 53 | --- 54 | 55 | **Optimal Solution (Two pointer)** 56 | 57 | 1. We'll take help of two pointers, `fast` and `slow` both initially pointing to head. 58 | 2. The fast pointer will move `n` steps and once it reaches, the slow pointer will start moving simultaneously unless the fast pointer reaches the last node. 59 | 3. Once the fast point reaches the last node, the slow node will be at the previous node of `n`th node. 60 | 4. Now we can easily remove the next node (technically `n`th node). 61 | 62 | ```cpp 63 | Node* removeNthFromEnd(Node* head, int n){ 64 | Node* fast = head; 65 | Node* slow = head; 66 | for (int i = 0; i < n; i++) fast = fast->next; 67 | if (fast == nullptr) return head->next; 68 | while (fast->next != nullptr){ 69 | slow = slow->next; 70 | fast = fast->next; 71 | } 72 | Node* delNode = slow->next; 73 | slow->next = delNode->next; 74 | delete delNode; 75 | return head; 76 | } 77 | ``` 78 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/10-reverseLL.md: -------------------------------------------------------------------------------- 1 | ## Reverse the given LL 2 | 3 | Given the head of a singly linked list, reverse the list, and return the reversed list. 4 | 5 | ### Algorithm 6 | 7 | **Brute force (Data replacement)** 8 | 9 | 1. The most simple way to reverse a LL is to replace the data in it. 10 | 2. Create a LIFO data structure (Stack), Traverse the LL, and push all elements in the stack. 11 | 3. Traverse the LL again and re-assign the Node data with stack's top elements. 12 | 4. The LL would be reversed, return the head. 13 | 14 | **TC : O(2N), SC : O(N)** 15 | 16 | ```cpp 17 | Node* reverseList(Node* head) { 18 | Node* temp = head; 19 | stack st; 20 | while(temp != nullptr){ 21 | st.push(temp->data); 22 | temp = temp->next; 23 | } 24 | temp = head; 25 | while(temp != nullptr){ 26 | temp->data = st.top(); 27 | st.pop(); 28 | temp = temp->next; 29 | } 30 | return head; 31 | } 32 | ``` 33 | 34 | --- 35 | 36 | **Optimal Solution (Pointer swapping)** 37 | 38 | 1. `Currrent` is a pointer to keep track of current nodes. Set it to head. `prev` is a pointer to keep track of previous nodes. Set it to NULL. `next` is a pointer to keep track of the next nodes. 39 | 40 | 2. Set `next` to point next node to node pointed by current. 41 | Change link between nodes pointed by `current` and `prev`. 42 | Update `prev` to `current` and `current` pointer to `next`. 43 | 44 | - Perform STEP 2 until current reaches the end of the list. 45 | 46 | 3. Set head as `prev`. This makes the head point at the last node. 47 | 48 | **TC : O(N) SC : O(1)** 49 | 50 | ```cpp 51 | Node* reverseList(Node* head) { 52 | Node* prev = nullptr; 53 | Node* current = head; 54 | while(current != nullptr){ 55 | Node* front = current->next; 56 | current->next = prev; 57 | prev = current; 58 | current = front; 59 | } 60 | return prev; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/Singly-Linked-List/11-check-palindrome.md: -------------------------------------------------------------------------------- 1 | ## Check if the LL is palindrome 2 | 3 | Given the head of a singly linked list, return true if it is a 4 | palindrome or false otherwise. 5 | 6 | **Expected TC : O(N), SC : O(1)** 7 | 8 | --- 9 | 10 | ### Algorithm 11 | 12 | **1. Brute Force (Stack method)** 13 | 14 | **TC O(2N), SC O(N)** 15 | 16 | ```cpp 17 | bool isPalindrome(Node* head) { 18 | stack st; 19 | Node* temp = head; 20 | while (temp != nullptr){ 21 | st.push(temp->val); 22 | temp = temp->next; 23 | } 24 | temp = head; 25 | while (temp != nullptr){ 26 | if (temp->val != st.top()){ 27 | return false; 28 | break; 29 | } 30 | temp = temp->next; 31 | st.pop(); 32 | } 33 | return true; 34 | } 35 | ``` 36 | 37 | --- 38 | 39 | **2. Optimal Solution (Reverse half LL)** 40 | 41 | Three Steps to follow : 42 | 43 | 1. Find the middle of LL (hare & tortoise method). 44 | 2. Reverse one half (obviously the second half). 45 | 3. Compare first half with another one. 46 | 47 | **TC O(2N), SC O(1)** 48 | 49 | ```cpp 50 | Node* reverse(Node* head){ 51 | // recursion 52 | if (head == nullptr || head->next == nullptr){ 53 | return head; 54 | } 55 | Node* newHead = reverse(head->next); 56 | Node* front = head->next; 57 | front->next = head; 58 | head->next = nullptr; 59 | return newHead; 60 | } 61 | 62 | bool isPalindrome(Node* head) { 63 | if (head == nullptr || head->next != nullptr){ 64 | return true; 65 | } 66 | 67 | // 1. find middle 68 | Node* slow = head; 69 | Node* fast = head; 70 | while (fast->next != nullptr && fast->next->next != nullptr) { // O(N/2) 71 | slow = slow->next; 72 | fast = fast->next->next; 73 | } 74 | 75 | // 2. Reverse 76 | slow->next = reverse(slow->next); 77 | 78 | // compare 79 | slow = slow->next; 80 | ListNode* dummy = head; 81 | 82 | while(slow!=NULL) { 83 | if(dummy->val != slow->val) return false; 84 | dummy = dummy->next; 85 | slow = slow->next; 86 | } 87 | return true; 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/reverseLinkedList.md: -------------------------------------------------------------------------------- 1 | ## Reverse a Linked List 2 | 3 | ### Approach : 4 | 5 | 1. Initialize prev to nullptr and current to the head of the original linked list. 6 | 2. Enter a while loop that terminates when current is nullptr. 7 | 3. Inside the while loop, do the following: 8 | - Store the next node in the original linked list in next. 9 | - Update the next pointer of the current node to point to the previous node. 10 | - Update the prev pointer to point to the current node. 11 | - Update the current pointer to point to the next node. 12 | 4. Return prev, which is now the head of the reversed linked list. 13 | 14 | --- 15 | 16 | ### Imlementation : 17 | 18 | ```cpp 19 | #include 20 | 21 | using std::cout, std::cin, std::endl; 22 | 23 | template class LinkedListNode { 24 | public: 25 | T data; 26 | LinkedListNode *next; 27 | LinkedListNode(T data) { 28 | this->data = data; 29 | this->next = NULL; 30 | } 31 | }; 32 | 33 | // Solution :- 34 | LinkedListNode *reverseLinkedList(LinkedListNode *head) { 35 | 36 | LinkedListNode *prev = nullptr; 37 | LinkedListNode *current = head; 38 | LinkedListNode *next = nullptr; 39 | 40 | while (current != nullptr) { 41 | next = current->next; 42 | current->next = prev; 43 | prev = current; 44 | current = next; 45 | } 46 | return prev; 47 | } 48 | 49 | int main() { return 0; } 50 | ``` 51 | -------------------------------------------------------------------------------- /Data-Structures/Linear-Data-Structures/Linked-List/temp2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::cout, std::endl, std::vector; 5 | 6 | class Node { 7 | public: 8 | // node members 9 | int data; // data 10 | Node* next; // pointer 11 | 12 | // constructor 13 | Node(int data1) { 14 | data = data1; 15 | next = nullptr; 16 | } 17 | }; 18 | 19 | int main() { 20 | vector arr = {2, 3, 4, 6, 3}; 21 | const Node* n1 = new Node(arr[1]); 22 | cout << n1->data << endl; 23 | cout << n1->next << endl; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /Data-Structures/Trees/01-intro.md: -------------------------------------------------------------------------------- 1 | ## Tress - A hierarchical Data Structure 2 | 3 | Trees are hierarchical data structures consisting of nodes. 4 | 5 | A tree consists of root node, parent nodes, children nodes, leaf-nodes, sub-tree and ancestors. 6 | 7 | ``` 8 | 1 <-- root node 9 | / \ 10 | 2 3 <-- Child node 11 | / \ / \ 12 | 4 5 6 7 13 | / / \ 14 | 8 9 10 <-- Leaf node 15 | ``` 16 | 17 | --- 18 | 19 | ### Binary Search Tree 20 | 21 | A Binary tree is a type of tree where each parent node consists of at **max 2** child nodes. 22 | 23 | **Types of Binary tree :** 24 | 25 | 1. **Fully Binary tree :** Every node will either have 0 or 2 children nodes. 26 | 27 | 2. **Complete Binary Tree :** All levels of tree should be completely filled. If not completely filled, then the last level should have all nodes as left as possible. 28 | 29 | 3. **Perfect Binary Tree :** All leaf nodes are at same level. 30 | 31 | 4. **Balnced Binary Tree :** The tree can at max have a height of **Log2(n)**, where n is number of nodes. For every node, height(left sub-tree) - height(right sub-tree) <= 1. 32 | 33 | 5. **Degenerate Tree :** When every node only have a single child or parent node. This type resembles to a Linked List. 34 | -------------------------------------------------------------------------------- /Data-Structures/Trees/02-basics.md: -------------------------------------------------------------------------------- 1 | ## Representation of a Tree in C++ 2 | 3 | ``` 4 | 1 <-- data 5 | left pointer --> / \ <-- right pointer 6 | 2 3 7 | / \ 8 | 4 NULL 9 | ``` 10 | 11 | --- 12 | 13 | ### Implementation : 14 | 15 | ```cpp 16 | struct Node { 17 | int data; 18 | struct Node* left; 19 | struct Node* right; 20 | // constructor 21 | Node(int value) { 22 | data = value; 23 | left = right = NULL; // initially pointing to null 24 | } 25 | } 26 | 27 | // Tree Creation 28 | int main() { 29 | // calling constructor and passing root's value. 30 | struct Node* root = new Node(1); 31 | 32 | root->left = new Node(2); 33 | root->right = new Node(3); 34 | 35 | root->left->left = new Node(4); 36 | 37 | return 0; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /Data-Structures/Trees/03-travsersals.md: -------------------------------------------------------------------------------- 1 | ## Traversing in a Tree 2 | 3 | There are two ways to traverse in a Binary search tree : 4 | 5 | 1. **Depth-First-Search [DFS] :** 6 | In this method, the tree is traversed through it's entire height / length. 7 | 8 | There are 3 types of DFS :- 9 | 10 | a. _In-order Traversal_ (left-**root**-right) : Start form the root, if there exists a left, go left, if no further left, print left, go back, print the root and now look for right, if right exists, apply the same logic. 11 | 12 | ``` 13 | 1 14 | / \ 15 | 2 3 16 | / \ / \ 17 | 4 5 6 7 18 | / / \ 19 | 8 9 10 20 | ``` 21 | 22 | In above BST, if we apply In-order traversal, we get : 23 | 24 | ``` 25 | 4 2 8 5 1 6 3 9 7 10 26 | ``` 27 | 28 | --- 29 | 30 | b. _Pre-Order-Traversal_ (**root**-left-right) : Start from the root, print root, if left exists, go left & print left, if no further left, go back, check for right, if right exists, apply the same logic. 31 | 32 | In above BST, if we apply Pre-order traversal, we get : 33 | 34 | ``` 35 | 1 2 4 5 8 3 6 7 9 10 36 | ``` 37 | 38 | --- 39 | 40 | c. _Post-Order-Traversal_ (left-right-**root**) : Start from the root, if left exists, go to left, print left, if no further left, go back, check if right exists, if exists print right, go back and print root. 41 | 42 | In above BST, if we apply Pre-order traversal, we get : 43 | 44 | ``` 45 | 4 5 8 2 6 7 9 10 7 3 1 46 | ``` 47 | 48 | --- 49 | 50 | 2. **Breadth-first-Search [BFS] :** In this method, we traverse the tree level by level, through it's entire breadth. 51 | 52 | ``` 53 | --> 1 54 | / \ 55 | --> 2 3 56 | / \ / \ 57 | --> 4 5 6 7 58 | / / \ 59 | --> 8 9 10 60 | ``` 61 | 62 | **BFS in Above Tree :** 63 | 64 | ``` 65 | 1 2 3 4 5 6 7 8 9 10 66 | ``` 67 | -------------------------------------------------------------------------------- /Data-Structures/Trees/04-in-order-recur.md: -------------------------------------------------------------------------------- 1 | ## In-Order-Traversal ~ Recursive approach C++ Implementation 2 | 3 | ``` 4 | 1 5 | / \ 6 | 2 3 7 | / \ / \ 8 | 4 5 6 7 9 | / / \ 10 | 8 9 10 11 | ``` 12 | 13 | ### Implementation : 14 | 15 | ```cpp 16 | void inorder(int node) { 17 | if (node == NULL) { // base case 18 | return; 19 | } 20 | inorder(node->left); // recursion 21 | cout << node->data << endl; 22 | inorder(node->right); // recursion 23 | } 24 | ``` 25 | 26 | pattern : left --> print --> right 27 | -------------------------------------------------------------------------------- /Data-Structures/Trees/05-pre-order-recur.md: -------------------------------------------------------------------------------- 1 | ## Pre-Order-Traversal ~ Recursive approach C++ Implementation 2 | 3 | ``` 4 | 1 5 | / \ 6 | 2 3 7 | / \ / \ 8 | 4 5 6 7 9 | / / \ 10 | 8 9 10 11 | ``` 12 | 13 | ### Implementation : 14 | 15 | ```cpp 16 | void preorder(int node) { 17 | if (node == NULL) { // base case 18 | return; 19 | } 20 | cout << node->data << endl; 21 | preorder(node->left); // recursion 22 | preorder(node->right); // recursion 23 | } 24 | ``` 25 | 26 | pattern : print --> left --> right 27 | -------------------------------------------------------------------------------- /Data-Structures/Trees/06-post-order-recur.md: -------------------------------------------------------------------------------- 1 | ## Post-Order-Traversal ~ Recursive approach C++ Implementation 2 | 3 | ``` 4 | 1 5 | / \ 6 | 2 3 7 | / \ / \ 8 | 4 5 6 7 9 | / / \ 10 | 8 9 10 11 | ``` 12 | 13 | ### Implementation : 14 | 15 | ```cpp 16 | void postorder(int node) { 17 | if (node == NULL) { // base case 18 | return; 19 | } 20 | postorder(node->left); // recursion 21 | postorder(node->right); // recursion 22 | cout << node->data << endl; 23 | } 24 | ``` 25 | 26 | pattern : left --> right --> print 27 | -------------------------------------------------------------------------------- /Data-Structures/Trees/09-pre-order-iterative.md: -------------------------------------------------------------------------------- 1 | ## Pre Order traversal ~ Iterative Approach 2 | 3 | **Approach :** 4 | 5 | 1. Take the root and push it into the stack. 6 | 2. Start the Stack iteration, pop the top most element out and push it to the answer vector, then check if it has any left or right. 7 | 3. If left or right not NULL, first push right then left into the stack. 8 | 4. The stack iteration continues, pop the top most (left) element out and push it to the answer vector, then check if it has any left or right. 9 | 5. Continue the iteration untill the stak gets empty. 10 | 11 | ![pre-order-itr](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/eb403e15-29ca-410a-913b-b9f79822c59a) 12 | 13 | ### Implementation : 14 | 15 | ```cpp 16 | /* Defination for binary tree : 17 | struct TreeNode { 18 | int val; 19 | TreeNode *left; 20 | TreeNode *right; 21 | TreeNode() : val(x), left(nullptr), right(nullptr) {} 22 | TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 23 | TreeNode(int x, TreeNode *left, TreeNode *right): val(x), left(left), 24 | right(right) {} 25 | } 26 | */ 27 | 28 | class Solution { 29 | public: 30 | vector preorder(TreeNode* root) { 31 | 32 | vectro ans; 33 | if (root == NULL) 34 | return ans; 35 | 36 | stack st; 37 | st.push(root); 38 | 39 | while (!st.empty()) { 40 | 41 | root = st.top(); 42 | st.pop(); 43 | ans.push_back(root->val); 44 | 45 | if (root->right != NULL) { 46 | st.push(root->right); 47 | } 48 | if (root->left != NULL) { 49 | st.push(root->left); 50 | } 51 | } 52 | return ans; 53 | } 54 | }; 55 | ``` 56 | -------------------------------------------------------------------------------- /Data-Structures/Trees/10-post-order-twoStack.md: -------------------------------------------------------------------------------- 1 | ## Post Order Traversal ~ Two stack iteration 2 | 3 | **Approach :** 4 | 5 | 1. Declare Two empty stacks. Push root of the tree into st1. 6 | 7 | 2. Start the st1 iteration, pop the top most element into st2. 8 | 9 | 3. Now if the top element of st2 has a left or right, push them into st1. 10 | 11 | 4. The iteration continues, pop the top most element into st2, check if it has left or right, push the left / right into st1. 12 | 13 | 5. The iteration stops when st1 gets empty. 14 | 15 | 6. When st1 gets empty, pop out all the element from st2 into answer vector. 16 | 17 | ### Implementation 18 | 19 | ```cpp 20 | /* Definition for binary tree : 21 | struct TreeNode { 22 | int val; 23 | TreeNode *left; 24 | TreeNode *right; 25 | TreeNode() : val(x), left(nullptr), right(nullptr) {} 26 | TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 27 | TreeNode(int x, TreeNode *left, TreeNode *right): val(x), left(left), 28 | right(right) {} 29 | } 30 | */ 31 | 32 | class Solution { 33 | public: 34 | vector postOrderTwoStack(TreeNode* root) { 35 | 36 | vector ans; 37 | if (root == NULL) 38 | return and; 39 | 40 | stack st1, st2; 41 | st1.push(root); 42 | 43 | while (!st1.empty()) { 44 | 45 | root = st1.top(); 46 | st1.pop(); 47 | st2.push(root); 48 | 49 | if (root->left != NULL) { 50 | st1.push(root->left); 51 | } 52 | if (root->right != NULL) { 53 | st1.push(root->right); 54 | } 55 | } 56 | 57 | while (!st2.empty()) { 58 | ans.push_back(st2.top()->val); 59 | st2.pop(); 60 | } 61 | 62 | return ans; 63 | } 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /Data-Structures/Trees/11-post-order-oneStack.md: -------------------------------------------------------------------------------- 1 | ## Post Order Traversal ~ One Stack Iteration 2 | 3 | ```cpp 4 | /* Defination for binary tree : 5 | struct TreeNode { 6 | int val; 7 | TreeNode *left; 8 | TreeNode *right; 9 | TreeNode() : val(x), left(nullptr), right(nullptr) {} 10 | TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 11 | TreeNode(int x, TreeNode *left, TreeNode *right): val(x), left(left), 12 | right(right) {} 13 | } 14 | */ 15 | 16 | class Solution { 17 | public: 18 | vector postOrderOneStack(TreeNode* root) { 19 | vector ans; 20 | if (root == NULL) 21 | return ans; 22 | 23 | TreeNode* curr = root; 24 | TreeNode* temp = NULL; 25 | stack st; 26 | 27 | while (curr != NULL || !st.empty()) { 28 | if (curr != NULL) { 29 | st.push(curr); 30 | curr = curr->left; 31 | } else { 32 | temp = st.top()->right; 33 | if (temp == NULL) { 34 | temp = st.top(); 35 | st.pop(); 36 | ans.push_back(temp); 37 | while (!st.empty()&& temp = st.top()->right) { 38 | temp = st.top(); 39 | st.pop(); 40 | ans.push_back(temp); 41 | } 42 | } else { 43 | curr = temp; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /Data-Structures/Trees/problems/check-for-balanced-bt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode { 5 | int val; 6 | TreeNode* left; 7 | TreeNode* right; 8 | TreeNode() : val(0), left(nullptr), right(nullptr) {} 9 | TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 10 | TreeNode(int x, TreeNode* left, TreeNode* right) 11 | : val(x), left(left), right(right) {} 12 | }; 13 | 14 | class Solution { 15 | public: 16 | // a function to check if tree is balanced or not on basis of it's height. 17 | bool isBalanced(TreeNode* root) { return dfsHeight(root) != -1; } 18 | 19 | /* a function to calculate height of tree, if this function returns -1, 20 | the tree is not balanced. The tree will always be balanced if this 21 | function returns some non-negative height */ 22 | 23 | int dfsHeight(TreeNode* root) { 24 | if (root == NULL) 25 | return 0; 26 | 27 | int lh = dfsHeight(root->left); 28 | if (lh == -1) 29 | return -1; 30 | 31 | int rh = dfsHeight(root->right); 32 | if (rh == -1) 33 | return -1; 34 | 35 | // for a balanced BT, height(left sub-tree) - height(right sub-tree) <= 36 | // 1 37 | if (abs(lh - rh) > 1) 38 | return -1; 39 | 40 | return max(lh, rh) + 1; 41 | } 42 | 43 | void deleteTree(TreeNode* node) { 44 | if (node != NULL) { 45 | deleteTree(node->left); 46 | deleteTree(node->right); 47 | delete node; 48 | } 49 | } 50 | }; 51 | 52 | int main() { 53 | Solution solution; 54 | 55 | TreeNode* balancedTree = new TreeNode(1); 56 | balancedTree->left = new TreeNode(2); 57 | balancedTree->right = new TreeNode(3); 58 | balancedTree->left->left = new TreeNode(4); 59 | balancedTree->left->right = new TreeNode(5); 60 | balancedTree->right->left = new TreeNode(6); 61 | balancedTree->right->right = new TreeNode(7); 62 | 63 | bool isBalancedResult = solution.isBalanced(balancedTree); 64 | cout << "tree balanced? " << (isBalancedResult ? "Yes" : "No") << endl; 65 | 66 | solution.deleteTree(balancedTree); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /Data-Structures/Trees/problems/count-leaves.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode { 5 | int val; 6 | TreeNode* left; 7 | TreeNode* right; 8 | explicit TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | }; 10 | 11 | class Solution { 12 | public: 13 | int countLeaves(TreeNode* root) { 14 | 15 | if (root == NULL) 16 | return 0; 17 | if (root->left == NULL && root->right == NULL) 18 | return 1; 19 | 20 | int leftLeaves = countLeaves(root->left); 21 | int rightLeaves = countLeaves(root->right); 22 | 23 | return leftLeaves + rightLeaves; 24 | } 25 | void deleteTree(TreeNode* node) { 26 | if (node != NULL) { 27 | deleteTree(node->left); 28 | deleteTree(node->right); 29 | delete node; 30 | } 31 | } 32 | }; 33 | 34 | int main() { 35 | // Create a sample binary tree 36 | TreeNode* root = new TreeNode(3); 37 | root->left = new TreeNode(9); 38 | root->right = new TreeNode(20); 39 | root->right->left = new TreeNode(15); 40 | root->right->right = new TreeNode(7); 41 | 42 | Solution solution; 43 | 44 | int result = solution.countLeaves(root); 45 | cout << "Sum of left leaves: " << result << std::endl; 46 | 47 | solution.deleteTree(root); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /Data-Structures/Trees/problems/depth-of-bt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct TreeNode { 6 | int val; 7 | TreeNode* left; 8 | TreeNode* right; 9 | explicit TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 10 | }; 11 | 12 | class Solution { 13 | public: 14 | int maxDepth(TreeNode* root) { 15 | if (root == NULL) 16 | return 0; 17 | int lh = maxDepth(root->left); 18 | int rh = maxDepth(root->right); 19 | return 1 + max(lh, rh); // formula 20 | } 21 | int minDepth(TreeNode* root) { 22 | if (root == NULL) 23 | return 0; 24 | 25 | // if the tree is a skew tree 26 | if (root->left == NULL && root->right != NULL) { 27 | return minDepth(root->right) + 1; 28 | } else if (root->left != NULL && root->right == NULL) { 29 | return minDepth(root->left) + 1; 30 | } 31 | 32 | // if a normal binary tree 33 | int lh = minDepth(root->left); 34 | int rh = minDepth(root->right); 35 | return 1 + min(lh, rh); // formula 36 | } 37 | void deleteTree(TreeNode* node) { 38 | if (node != NULL) { 39 | deleteTree(node->left); 40 | deleteTree(node->right); 41 | delete node; 42 | } 43 | } 44 | }; 45 | 46 | int main() { 47 | TreeNode* root = new TreeNode(3); 48 | root->left = new TreeNode(9); 49 | root->right = new TreeNode(20); 50 | root->right->left = new TreeNode(15); 51 | root->right->right = new TreeNode(7); 52 | 53 | Solution solution; 54 | 55 | int maxDepth = solution.maxDepth(root); 56 | int minDepth = solution.maxDepth(root); 57 | std::cout << "Max Depth of tree : " << maxDepth << std::endl; 58 | std::cout << "Min Depth of tree : " << minDepth << std::endl; 59 | 60 | solution.deleteTree(root); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /Data-Structures/Trees/problems/diameter-of-bt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode { 5 | int val; 6 | TreeNode* left; 7 | TreeNode* right; 8 | TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | }; 10 | 11 | /* 12 | The diameter of a binary tree is the length of the longest path between any two 13 | nodes in a tree. This path may or may not pass through the root. 14 | The length of a path between two nodes is represented by the number of edges 15 | between them. 16 | */ 17 | 18 | class Solution { 19 | public: 20 | int diameter = 0; 21 | int diameterOfBinaryTree(TreeNode* root) { 22 | height(root); 23 | return diameter; 24 | } 25 | int height(TreeNode* node) { 26 | if (!node) 27 | return 0; 28 | int lh = height(node->left); 29 | int rh = height(node->right); 30 | diameter = max(diameter, lh + rh); 31 | return 1 + max(lh, rh); 32 | } 33 | }; 34 | 35 | int main() { 36 | TreeNode* root = new TreeNode(3); 37 | root->left = new TreeNode(9); 38 | root->right = new TreeNode(20); 39 | root->right->left = new TreeNode(15); 40 | root->right->right = new TreeNode(7); 41 | 42 | Solution solution; 43 | 44 | int result = solution.diameterOfBinaryTree(root); 45 | 46 | cout << "Diameter of the binary tree: " << result << endl; 47 | 48 | delete root->left; 49 | delete root->right->left; 50 | delete root->right->right; 51 | delete root; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /Data-Structures/Trees/problems/sum-of-left-leaves.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode { 5 | int val; 6 | TreeNode* left; 7 | TreeNode* right; 8 | explicit TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | }; 10 | 11 | class Solution { 12 | public: 13 | int sumOfLeftLeaves(TreeNode* root) { 14 | if (root == NULL) 15 | return 0; 16 | 17 | int sum = 0; 18 | 19 | // checking if the root has a left leaf 20 | if (root->left != NULL && root->left->left == NULL && 21 | root->left->right == NULL) { 22 | sum += root->left->val; 23 | } 24 | 25 | sum += sumOfLeftLeaves(root->left); 26 | sum += sumOfLeftLeaves(root->right); 27 | 28 | return sum; 29 | } 30 | void deleteTree(TreeNode* node) { 31 | if (node != NULL) { 32 | deleteTree(node->left); 33 | deleteTree(node->right); 34 | delete node; 35 | } 36 | } 37 | }; 38 | 39 | int main() { 40 | TreeNode* root = new TreeNode(3); 41 | root->left = new TreeNode(9); 42 | root->right = new TreeNode(20); 43 | root->right->left = new TreeNode(15); 44 | root->right->right = new TreeNode(7); 45 | 46 | Solution solution; 47 | 48 | int result = solution.sumOfLeftLeaves(root); 49 | std::cout << "Sum of left leaves: " << result << std::endl; 50 | 51 | solution.deleteTree(root); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /Data-Structures/Trees/problems/symmetric-bt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode { 5 | int val; 6 | TreeNode* left; 7 | TreeNode* right; 8 | TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | }; 10 | 11 | /* 12 | A symmetric binary tree is a binary tree where the left and right subtrees of 13 | the root node are mirror images of each other. 14 | */ 15 | 16 | class Solution { 17 | public: 18 | bool isSymmetric(TreeNode* root) { 19 | return root == NULL || helper(root->left, root->right); 20 | } 21 | bool helper(TreeNode* left, TreeNode* right) { 22 | if (left == NULL || right == NULL) 23 | return left == right; 24 | if (left->val != right->val) 25 | return false; 26 | return helper(left->left, right->right) && 27 | helper(left->right, right->left); 28 | } 29 | // recursively free the memory of all the nodes 30 | // call this function at the end of the program 31 | void deleteTree(TreeNode* node) { 32 | if (node != NULL) { 33 | deleteTree(node->left); 34 | deleteTree(node->right); 35 | delete node; 36 | } 37 | } 38 | }; 39 | 40 | int main() { 41 | TreeNode* root = new TreeNode(1); 42 | root->left = new TreeNode(2); 43 | root->right = new TreeNode(2); 44 | root->left->left = new TreeNode(3); 45 | root->left->right = new TreeNode(4); 46 | root->right->left = new TreeNode(4); 47 | root->right->right = new TreeNode(3); 48 | 49 | Solution solution; 50 | bool isSymmetric = solution.isSymmetric(root); 51 | 52 | if (isSymmetric) { 53 | cout << "The tree is symmetric." << endl; 54 | } else { 55 | cout << "The tree is not symmetric." << endl; 56 | } 57 | // whenever you are allocating on the heap by using the new keyword you 58 | // need to free that memory with the delete keyword 59 | solution.deleteTree(root); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /Data-Structures/stl-reference.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # STL Quick Reference 4 | 5 |
6 | 7 | ![C++ STL Quick Reference (2)-1](https://user-images.githubusercontent.com/53911515/229293159-04ddf328-3bb5-4508-bfe1-7cff06d8a22b.jpg) 8 | ![C++ STL Quick Reference (2)-2](https://user-images.githubusercontent.com/53911515/229293161-f0618394-ec65-450f-b02c-97f318737dd4.jpg) 9 | ![C++ STL Quick Reference (2)-3](https://user-images.githubusercontent.com/53911515/229293162-db8f8a94-eb7b-4f4c-8c1b-3fe36a6d3239.jpg) 10 | ![C++ STL Quick Reference (2)-4](https://user-images.githubusercontent.com/53911515/229293164-4173335e-8083-4c13-8fd7-82111916244e.jpg) 11 | ![C++ STL Quick Reference (2)-5](https://user-images.githubusercontent.com/53911515/229293167-b347df15-77eb-4745-bbc6-47732416e8b8.jpg) 12 | ![C++ STL Quick Reference (2)-6](https://user-images.githubusercontent.com/53911515/229293168-b0fddfd3-9058-409c-bf78-cd1bc2c550bf.jpg) 13 | ![C++ STL Quick Reference (2)-7](https://user-images.githubusercontent.com/53911515/229293169-f090fc7e-a309-4407-a186-289434428433.jpg) 14 | ![C++ STL Quick Reference (2)-8](https://user-images.githubusercontent.com/53911515/229293172-383b17ed-4042-49f0-87fc-ee0f4b195056.jpg) 15 | -------------------------------------------------------------------------------- /Database/normalization.md: -------------------------------------------------------------------------------- 1 | # Normalization forms 2 | 3 | A good database design can protect us from data integrity issues, this is the case where the data disagrees with 4 | itself for example, the same person in a database can't have 2 birth dates, a good database design can protect us 5 | from this issues, and also we do normalization to protect us from data integrity issues. 6 | When we normalize the data, we are structuring the data in a way where it cant express redundant information. 7 | 8 | We use different normal forms to basically tell how safe the database is from redundant data. 9 | 10 | We will discuss 5 normal forms 11 | 12 | ## First Normal Form 13 | 14 | - Don't convey information about a row using the row order. 15 | 16 | - Instead use a different column to convey that information 17 | - To convey the height of people use a different column for the height 18 | 19 | - Don't have different data types in a same column 20 | 21 | - Most database software prevent us from doing this by default 22 | 23 | - Not having a primary key is a violation of first normal form 24 | 25 | - Primary key uniquely identifies a row in a table 26 | - SQL query: `ALTER TABLE table_name ADD PRIMARY KEY (row_name)` 27 | 28 | - Storing a repeating group of data items in a single row violates first normal form 29 | - Make a row for each group of data 30 | 31 | ## Second Normal Form 32 | 33 | **Deletion Anomalies**: When a deletion of a record from a table results in a data loss in a table, that is called a 34 | deletion anomaly. 35 | 36 | **Update Anomalies**: Same as deletion anomalies but at the time of update. 37 | 38 | **Insertion Anomalies**: These anomalies occur when it is not possible to insert data into a database because the 39 | required fields are missing or because the data is incomplete. 40 | 41 | - First Normal form can be more prone to deletion, update and insertion anomalies, Second normal form tries to prevent this 42 | 43 | - Second normal form is about how the non key column relates to the primary key. 44 | - Each non-key attribute must depend on the entire primary key 45 | 46 | ![Image](https://github.com/user-attachments/assets/a5766d74-9cdd-44ae-a1c2-01b5f8d76b1f) 47 | 48 | ## Third Normal Form 49 | 50 | - Third normal form prevents the existence of transitive dependencies, that is a non key attribute depending on a non 51 | normal form 52 | 53 | - Third Normal Form: Every non-key attribute in a table should depend on the key, the whole key, and nothing but the key. 54 | 55 | ### Summary 56 | 57 | ![Image](https://github.com/user-attachments/assets/b79274b3-4233-4d9c-befb-d29fbf335651) 58 | 59 | ### Reference 60 | 61 | - [Learn Database Normalization - 1Nf, 2Nf, 3Nf, 4Nf, 5Nf](https://www.youtube.com/watch?v=GFQaEYEc8_8) 62 | 63 | - [Anomalies in DB](https://www.geeksforgeeks.org/anomalies-in-relational-model/) 64 | -------------------------------------------------------------------------------- /Go/Basics/00-intro.md: -------------------------------------------------------------------------------- 1 | ## Introduction to Go 2 | 3 | **Table of contents:** 4 | 5 | 1. Introduciton to Go Language. 6 | 2. Go under the hood. 7 | 3. Memory Management. 8 | 4. Comparison with other languages. 9 | 10 | --- 11 | 12 | ### Introduciton to Go Language. 13 | 14 | Go, often called Golang, is a statically typed & compiled programming language created at Google. 15 | 16 | It aims for simplicity, readability, and **concurrency**, making it great for building performant web services, network applications, and CLI tools. 17 | 18 | _statically typed_ : the data type of each variable must be explicitly declared. 19 | 20 | _compiled language_ : translated directly into machine code. 21 | 22 | _concurrency_ : the ability of a program to handle multiple tasks or computations seemingly at the same time. 23 | 24 | --- 25 | 26 | ### Go under the Hood 27 | 28 | Go uses a compiler to translate code into machine code. Its runtime environment manages memory, concurrency, and other low-level functionality. 29 | 30 | Concurrency features are implemented using lightweight threads called **goroutines**, which communicate data through channels. 31 | 32 | _goroutines_ : these are the foundation of Go's powerful concurrency features. They are lightweight threads of execution that run concurrently with other goroutines and the main program thread. 33 | 34 | --- 35 | 36 | ### Memory Management 37 | 38 | Go uses garbage collection (GC) to automatically reclaim unused memory allocated during program execution. This simplifies memory management for developers and prevents memory leaks. 39 | 40 | The Go runtime automatically manages memory allocation and deallocation for the programmer. This eliminates the need for manual memory management, but it comes with a cost: 41 | 42 | - The Go runtime must keep track of every object that is allocated, leading to increased performance overhead. 43 | 44 | - In certain scenarios, such as when an HTTP server processes requests with large protobuf blobs (which contain many small objects), this can result in the Go runtime spending a significant amount of time tracking each of those individual allocations, and then deallocating them. As a result this also causes signicant performance overhead. 45 | 46 | --- 47 | 48 | ### Comparison with other languages: 49 | 50 | Unlike interpreted languages like Python, Go compiles to native code, offering faster execution. However, compilation adds an extra step compared to directly running interpreted code. 51 | 52 | Go's static type system provides better error checking and refactoring possibilities compared to dynamically typed languages like JavaScript. 53 | 54 | Go shines in concurrency with its goroutines and channels, compared to languages like JavaScript which is single-threaded & relies on an event loop to handle asynchronous operations. 55 | 56 | --- 57 | 58 | Go [Installation](https://go.dev/doc/install). 59 | -------------------------------------------------------------------------------- /Go/Basics/01-helloGo.md: -------------------------------------------------------------------------------- 1 | ## Hello Go! 2 | 3 | Ensure you've Go installed in your system! 4 | 5 | 1. Create a Go module : 6 | 7 | Navigate to the directory where you want to create your Go project and run the command 8 | 9 | ```bash 10 | mkdir hellogo 11 | cd hellogo 12 | ``` 13 | 14 | - **go mod init {REMOTE}/{USERNAME}/hellogo** 15 | 16 | ```bash 17 | go mod init github.com/amitsuthar69/hellogo 18 | ``` 19 | 20 | What it does: 21 | 22 | - Initializes a new Go module named `github.com/amitsuthar69/hellogo` in the current directory. 23 | - Generates a file named `go.mod` at the root of your project, which tracks the module's dependencies. 24 | 25 | Purpose of `go.mod`: 26 | 27 | - Manages the dependencies required for your project, ensuring reproducible builds and managing version conflicts. 28 | - Helps organize your code into modules, promoting modularity and reusability. 29 | 30 | `go.mod` file : 31 | 32 | ```mod 33 | module github.com/amitsuthar69/hellogo 34 | 35 | go 1.21.5 36 | ``` 37 | 38 | --- 39 | 40 | 2. Write Go code: 41 | 42 | Create your first Go source files with `.go` extension files within the module directory. 43 | 44 | ```go 45 | // hello.go file 46 | package main 47 | 48 | import "fmt" 49 | 50 | func main() { 51 | fmt.Print("Let's Fckn Go!") 52 | } 53 | ``` 54 | 55 | Here's a breakdown of the syntax : 56 | 57 | - `package main`: This line declares that the code belongs to a package named `main`. 58 | 59 | The main package is special in Go because it's **the entry point for executable programs**. 60 | 61 | - `import "fmt"`: This line imports the `fmt` package, which provides functions for formatted I/O (input and output) operations, such as printing to the console. 62 | 63 | - `func main() { ... }`: This defines a function named main. In Go, the main function is the first function that gets executed when a program starts. 64 | 65 | - `fmt.Print("Let's Fckn Go!")`: The `Print` function function from the `fmt` package prints the string to the console without adding a newline character at the end. 66 | 67 | --- 68 | 69 | 3. Run your code to see the greeting. 70 | 71 | ``` 72 | $ go run . 73 | ``` 74 | 75 | This `go run` command is used to quickly compile and run a Go package. The compiled binary is not saved in our working directory. 76 | 77 | Instead we should use `go build` to compile production executables. 78 | 79 | To make this executable file run anywhere on your mchine, you can run `go install` which will make this `hellogo` executable file globally available and now anywhere in your system, you can simply run `hellgo` as a shell scrpit! 80 | 81 | This is helpful to make our custom scripts written in go! 82 | 83 | **NOTE:** Once used `go build`, you need to re-compile (`go build`) our code everytime you make changes in our code or else the changes would not be reflected. 84 | -------------------------------------------------------------------------------- /Go/Basics/02-packages.md: -------------------------------------------------------------------------------- 1 | ## Packages 2 | 3 | Every Go program is mode up of packages! 4 | 5 | You have probably noticed the `package main` at the top of the programs we've seen yet. A package named `main` has an entrypoint at the `main()` function. **A main package is compiled into an executable program.** 6 | 7 | A package by any other name is a `library package`. Such libraries have no entry point. Libraries simply export functionality that can be used by other packages. 8 | 9 | A collection of these packages that are released together are called **Go module(s)** 10 | 11 | --- 12 | 13 | When you need your code to do something that might have been implemented by someone else, you can look for a package that has functions you can use in your code. 14 | 15 | ```go 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | 21 | "rsc.io/quote" // importing an external package 22 | ) 23 | 24 | func main() { 25 | fmt.Println(quote.Go()) // callling the Go function 26 | } 27 | ``` 28 | 29 | --- 30 | 31 | ### Add new module requirements and sums. 32 | 33 | Go will add the quote module as a requirement in `go.mod` file, as well as a `go.sum` file for use in **authenticating the module**. 34 | 35 | ``` 36 | $ go mod tidy 37 | ``` 38 | 39 | Run your code to see the message generated by the function you're calling. 40 | 41 | ``` 42 | $ go run . 43 | ``` 44 | 45 | Notice that your code calls the Go function, printing a clever message about communication. 46 | 47 | When you ran `go mod tidy`, it located and downloaded the `rsc.io/quote` module that contains the package you imported. 48 | 49 | By default, it downloaded the latest version `-- v1.5.2`. 50 | 51 | --- 52 | 53 | `go.mod` file updates to : 54 | 55 | ```mod 56 | module example/hello 57 | 58 | go 1.21.5 59 | 60 | require rsc.io/quote v1.5.2 61 | 62 | require ( 63 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect 64 | rsc.io/sampler v1.3.0 // indirect 65 | ) 66 | ``` 67 | 68 | the new `go.sum` file : 69 | 70 | ```sum 71 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8= 72 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 73 | rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y= 74 | rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= 75 | rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= 76 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 77 | ``` 78 | -------------------------------------------------------------------------------- /Go/Basics/08-maps(theGoObjects).md: -------------------------------------------------------------------------------- 1 | ## Maps ~ The Go Objects 2 | 3 | **Table of content** 4 | 5 | 1. What are Maps in Go? 6 | 2. Mutating maps 7 | 8 | --- 9 | 10 | ### What are Maps in Go? 11 | 12 | Maps in Go are similar to JavaScript objects or Python dictionaries. Maps are a data structure that provides a key->value mapping. 13 | 14 | We can create maps using a literal or `make()` function : 15 | 16 | ```go 17 | // mapName := make(map[keyType]valueType) creates an empty map 18 | ages := make(map[string]int) 19 | ages["Amit"] = 18 20 | ages["Rishabh"] = 18 21 | ages["Amit"] = 19 // overwrites 18 22 | ``` 23 | 24 | ```go 25 | // mapName := map[keyType]valueType{...} 26 | ages := map[string]int{ 27 | "Amit": 19, 28 | "Rishabh": 18, 29 | } 30 | ``` 31 | 32 | The `len` function works on maps as well, it returns the total number of key-value pairs in that map 33 | 34 | ```go 35 | fmt.Println(len(ages)) // 2 36 | ``` 37 | 38 | To print these key-value pairs, we can use `for` loops as : 39 | 40 | ```go 41 | for key, value := range ages { 42 | fmt.Println(key, value) 43 | } 44 | // Amit 19 45 | // Rishabh 18 46 | ``` 47 | 48 | Looking up a value in a map is much faster than searching thorough a slice. 49 | 50 | --- 51 | 52 | ### Mutating maps 53 | 54 | 1. Inset an element : 55 | 56 | ```go 57 | m[key] = elem 58 | ``` 59 | 60 | 2. Get an element : 61 | 62 | ```go 63 | elem = m[key] 64 | ``` 65 | 66 | 3. Deleting an element 67 | 68 | ```go 69 | delete(m, key) 70 | ``` 71 | 72 | 4. Check if key exists : 73 | 74 | ```go 75 | elem, ok := m[key] 76 | // if key is in m, ok is true else, its false 77 | ``` 78 | 79 | If key is not in the map, then `elem` is the zero value for the map's element type. 80 | 81 | --- 82 | 83 | The key types in maps can be anything comporable among primitive data types, and not slices, maps or functions which are not a comparable data type. 84 | 85 | ```go 86 | myMap = make(map[string]map[string]int) 87 | ``` 88 | 89 | The above code, creates a map whose key is a `string` but the value is again an another map whose key is also a `string` and value is an `int`. 90 | -------------------------------------------------------------------------------- /Go/Basics/10-pointers.md: -------------------------------------------------------------------------------- 1 | ## Pointers in Go 2 | 3 | **Table of content :** 4 | 5 | 1. Pointers 6 | 2. Pointer Receivers 7 | 8 | --- 9 | 10 | ### Pointers 11 | 12 | In any programming language, **pointers are variables which stores memory address of another variable**. This means that the pointer "points to" the location of where the data is stored _NOT_ the actual data itself. 13 | 14 | Below image will help you understand pointers on memory level: 15 | 16 | ![pointers](https://github.com/amitsuthar69/assets/blob/main/Go/pointers.png?raw=true) 17 | 18 | The type of a pointer in go is defined with `*` syntax 19 | 20 | ```go 21 | var p *int // creates a pointer to an integer 22 | ``` 23 | 24 | This `&` operator generates a pointer to its operand. 25 | 26 | ```go 27 | myString := "hello" 28 | myStringPtr = &myString 29 | ``` 30 | 31 | Example : 32 | 33 | ```go 34 | myString := "Hello" 35 | fmt.Println(myString) // Hello 36 | 37 | myStringPtr := &myString // creates a pointer 38 | 39 | fmt.Println(myStringPtr) // memory address 0xc000014080 40 | fmt.Println(*myStringPtr) // Dereferences the pointer, prints Hello 41 | 42 | *myStringPtr = "world" // mutating myString with reference 43 | fmt.Println(myString) // world 44 | ``` 45 | 46 | --- 47 | 48 | ### Pointer Receivers 49 | 50 | A receiver type on a method can also be a pointer. 51 | 52 | Methods with pointer receivers can modify the value to which the receiver points. Since methods often need to modify their receiver, pointer receivers are more common than value receivers. 53 | 54 | ```go 55 | type car struct { 56 | color string 57 | } 58 | 59 | // making changes to the instance of type 60 | func (c car) setColor(color string) { 61 | c.color = color // warning: ineffective assignment to field car.color 62 | } 63 | ``` 64 | 65 | As soon as you try modifying the color property, your LSP warns you that this operation is ineffective. And even if you try to setColor to something else the changes would not be reflected. 66 | 67 | So instead of passing the `car` struct, we can pass a reference of that struct as : 68 | 69 | ```go 70 | type car struct { 71 | color string 72 | } 73 | 74 | func (c *car) setColor(color string) { 75 | c.color = color 76 | } 77 | 78 | func main(){ 79 | c := car{ 80 | color: "red", 81 | } 82 | c.setColor("black") 83 | fmt.Println(c.color) // black 84 | } 85 | ``` 86 | 87 | NOTE that `c` is not a pointer to in the calling fuction but the method still gains access to a pointer to `c`. 88 | -------------------------------------------------------------------------------- /Go/Concurrency/2-deadlocks.md: -------------------------------------------------------------------------------- 1 | ## Blockings and Deadlocks 2 | 3 | A deadlock happens when a group of goroutines are all blocking, so none of them can continue. This is a common bug that we need to watch out for in concurrent programming. 4 | 5 | ```go 6 | func main(){ 7 | c1 := make(chan int) 8 | 9 | fmt.Println("push into channel") 10 | c1 <- 10 11 | 12 | go func() { 13 | g1 := <-c1 14 | fmt.Println("get g1: ", g1) 15 | }() 16 | } 17 | ``` 18 | 19 | ```bash 20 | push into channel 21 | fatal error: all goroutines are asleep - deadlock! 22 | 23 | goroutine 1 [chan send]: 24 | main.main() 25 | /home/amit/Documents/Programming-Notes/Go/codes/temp.go:23 +0x16b 26 | exit status 2 27 | ``` 28 | 29 | The above code results a deadlock because we are attempting to send a value to the channel `c1` in the `main` goroutine without any other goroutine ready to receive the value. 30 | 31 | The channel operation `<-c1` in the goroutine is expecting to receive a value before proceeding, and since there is no other goroutine ready to send, it leads to a deadlock. 32 | 33 | Correct Code : 34 | 35 | ```go 36 | func main(){ 37 | c1 := make(chan int) 38 | 39 | fmt.Println("push into channel") 40 | go func() { 41 | g1 := <-c1 42 | }() 43 | 44 | c1 <- 69 45 | fmt.Println("got g1: ", g1) 46 | } 47 | ``` 48 | 49 | In this corrected version: 50 | 51 | - The goroutine is started before attempting to send a value to the channel. 52 | - The value 10 is sent to the channel inside the main goroutine. 53 | 54 | Taking care of deadlocks can be a major headache if not handled properly. 55 | 56 | To handle this, Go comes with **buffered channels**, which provide a flexible mechanism for managing asynchronous communication between goroutines, allowing temporary storage of values and reducing the risk of deadlocks by decoupling the timing of senders and receivers. 57 | 58 | Learn more about [Buffered channels](13-buffered-channels.md). 59 | -------------------------------------------------------------------------------- /Go/codes/temp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Book struct { 6 | title string 7 | author string 8 | pages int 9 | isRead bool 10 | } 11 | 12 | type Shelf []Book 13 | 14 | func addBookToShelf(b Book, s *Shelf) { 15 | *s = append(*s, b) 16 | } 17 | 18 | func addBook(t, a string, p int, r bool) Book { 19 | book := Book{ 20 | title: t, author: a, pages: p, isRead: r, 21 | } 22 | return book 23 | } 24 | 25 | func readBook(b *Book) { 26 | b.isRead = true 27 | } 28 | 29 | func printBook(b Book) { 30 | fmt.Printf("Title: %s by %s\nPages: %d\nisRead: %v", 31 | b.title, b.author, b.pages, b.isRead, 32 | ) 33 | } 34 | 35 | func printShelf(s Shelf) { 36 | for i, book := range s { 37 | fmt.Printf("Book no: %d\n", i+1) 38 | printBook(book) 39 | fmt.Println() 40 | fmt.Println() 41 | } 42 | } 43 | 44 | func main() { 45 | fmt.Println("============> Book Shelf <===========") 46 | var myShelf Shelf 47 | 48 | book1 := addBook("Ramayana", "Valmiki", 200, false) 49 | addBookToShelf(book1, &myShelf) 50 | 51 | book2 := addBook("Can't Hurt Me", "David Goggins", 100, false) 52 | addBookToShelf(book2, &myShelf) 53 | 54 | readBook(&myShelf[0]) 55 | fmt.Println() 56 | printShelf(myShelf) 57 | } 58 | -------------------------------------------------------------------------------- /Go/wise-words.md: -------------------------------------------------------------------------------- 1 | # Go Proverbs 2 | 3 | The [Go Proverbs](https://go-proverbs.github.io/) are a beautiful collection of wise words from Rob Pike, one of Go's creators. 4 | 5 | > Don't communicate by sharing memory, share memory by communicating. 6 | > 7 | > Concurrency is not parallelism. 8 | > 9 | > Channels orchestrate; mutexes serialize. 10 | > 11 | > The bigger the interface, the weaker the abstraction. 12 | > 13 | > Make the zero value useful. 14 | > 15 | > interface{} says nothing. 16 | > 17 | > Gofmt's style is no one's favorite, yet gofmt is everyone's favorite. 18 | > 19 | > A little copying is better than a little dependency. 20 | > 21 | > Syscall must always be guarded with build tags. 22 | > 23 | > Cgo must always be guarded with build tags. 24 | > 25 | > Cgo is not Go. 26 | > 27 | > With the unsafe package there are no guarantees. 28 | > 29 | > Clear is better than clever. 30 | > 31 | > Reflection is never clear. 32 | > 33 | > Errors are values. 34 | > 35 | > Don't just check errors, handle them gracefully. 36 | > 37 | > Design the architecture, name the components, document the details. 38 | > 39 | > Documentation is for users. 40 | > 41 | > Don't panic. 42 | 43 | @[youtube](https://www.youtube.com/watch?v=PAAkCSZUG1c) 44 | -------------------------------------------------------------------------------- /JavaScript/01-intro.md: -------------------------------------------------------------------------------- 1 | # Introduction : 2 | 3 | JavaScript does not use datatypes as opposed to c , c++ , Java. It has three initialisation techniques namely 4 | 5 | - let 6 | 7 | - var 8 | 9 | - const 10 | 11 | Semicolon " ; " is not essential to put at the end of every line but it is a good practice if you do so 12 | 13 | --- 14 | 15 | # Arrays 16 | 17 | ```js 18 | let arr = [1, 2, 3, 4]; 19 | 20 | //This creates an array of length 3, as the indexing starts from 0 , even though you can see four elements inside the array 21 | ``` 22 | 23 | ## Adding elements in the front: 24 | 25 | ```js 26 | let arr = [1, 2, 3, 4]; 27 | arr.unshift(-1, 0); 28 | 29 | //You can also use 30 | 31 | arr.concat(arr(-1, 0)); 32 | 33 | /*these techniques will add two elements in the beginning of the array 34 | output: 35 | [-1 , 0 , 1 , 2 , 3 , 4] */ 36 | ``` 37 | 38 | --- 39 | 40 | # Functions : 41 | 42 | ### Different ways to declare a function: 43 | 44 | ```js 45 | function fn(){ } 46 | //OR 47 | const fn = function(){ } 48 | //OR 49 | const fn => { } 50 | ``` 51 | 52 | Here "fn" is the function name 53 | 54 | --- 55 | 56 | # **forEach** : 57 | 58 | - Creates a function for each element of an array 59 | - It does not return a value 60 | 61 | ```js 62 | arr.forEach(function fn(arr) { 63 | console.log(arr + 2); 64 | }); 65 | ``` 66 | 67 | This will display each element of the array after adding 2 to them 68 | 69 | --- 70 | 71 | # **Map** : 72 | 73 | - This creates a new array consisting the functions of each element of other array 74 | 75 | ```js 76 | let arr1 = arr.map((item) => { 77 | return item + 2; 78 | }); 79 | ``` 80 | 81 | The values of array "arr" will increase by 2 and get returned to new array "arr1" 82 | 83 | --- 84 | 85 | # **Filter** : 86 | 87 | - It follows the boolean concept 88 | - It creates a new array and puts only those values which fulfill the criteria mentioned by you 89 | 90 | ```js 91 | let f1 = arr.filter((arr) => { 92 | return arr > 2; 93 | }); 94 | 95 | // This will print only those numbers present in array "arr" which are greater than 2 96 | ``` 97 | -------------------------------------------------------------------------------- /JavaScript/02-basics.md: -------------------------------------------------------------------------------- 1 | # JavaScript - Basics 2 | 3 | - JavaScript is used to program behaviour of pages. 4 | - JavaScript Can Change HTML Content. 5 | - JavaScript Can Change HTML Attribute Values. 6 | - JavaScript Can Change HTML styles. 7 | - JavaScript Can Hide HTML Elements. 8 | 9 | --- 10 | 11 | # Where to add JavaScript 12 | 13 | 1. In 19 | // Script tag can be added in 20 | 21 | tag or in 22 | 23 | tag. 24 | 25 | 26 | ``` 27 | 28 | 2. In External .js File [ Without Script Tag ]. 29 | 30 | Exernal javascipt file is prefferd over all. 31 | 32 | - Easy to maintain and read 33 | - Cached files can speed up page load. 34 | 35 | --- 36 | 37 | #