diff --git a/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39 (1).jpeg b/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39 (1).jpeg new file mode 100644 index 0000000..db2155b Binary files /dev/null and b/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39 (1).jpeg differ diff --git a/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39 (2).jpeg b/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39 (2).jpeg new file mode 100644 index 0000000..491ae16 Binary files /dev/null and b/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39 (2).jpeg differ diff --git a/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39.jpeg b/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39.jpeg new file mode 100644 index 0000000..491ae16 Binary files /dev/null and b/.gitbook/assets/WhatsApp Image 2023-12-24 at 16.19.39.jpeg differ diff --git a/.gitbook/assets/array-representation-trie.png b/.gitbook/assets/array-representation-trie.png new file mode 100644 index 0000000..2525392 Binary files /dev/null and b/.gitbook/assets/array-representation-trie.png differ diff --git a/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png new file mode 100644 index 0000000..c5aed67 Binary files /dev/null and b/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png differ diff --git a/.gitbook/assets/image (1) (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1) (1).png new file mode 100644 index 0000000..b4ec261 Binary files /dev/null and b/.gitbook/assets/image (1) (1) (1) (1) (1).png differ diff --git a/.gitbook/assets/image (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1).png new file mode 100644 index 0000000..078a0b3 Binary files /dev/null and b/.gitbook/assets/image (1) (1) (1) (1).png differ diff --git a/.gitbook/assets/image (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1).png new file mode 100644 index 0000000..350a511 Binary files /dev/null and b/.gitbook/assets/image (1) (1) (1).png differ diff --git a/.gitbook/assets/image (1) (1).png b/.gitbook/assets/image (1) (1).png new file mode 100644 index 0000000..003877f Binary files /dev/null and b/.gitbook/assets/image (1) (1).png differ diff --git a/.gitbook/assets/image (1).png b/.gitbook/assets/image (1).png new file mode 100644 index 0000000..01e4ce4 Binary files /dev/null and b/.gitbook/assets/image (1).png differ diff --git a/.gitbook/assets/image (10).png b/.gitbook/assets/image (10).png new file mode 100644 index 0000000..6a4ff2d Binary files /dev/null and b/.gitbook/assets/image (10).png differ diff --git a/.gitbook/assets/image (11).png b/.gitbook/assets/image (11).png new file mode 100644 index 0000000..a226eff Binary files /dev/null and b/.gitbook/assets/image (11).png differ diff --git a/.gitbook/assets/image (12).png b/.gitbook/assets/image (12).png new file mode 100644 index 0000000..b63ab34 Binary files /dev/null and b/.gitbook/assets/image (12).png differ diff --git a/.gitbook/assets/image (13).png b/.gitbook/assets/image (13).png new file mode 100644 index 0000000..3f1039b Binary files /dev/null and b/.gitbook/assets/image (13).png differ diff --git a/.gitbook/assets/image (14).png b/.gitbook/assets/image (14).png new file mode 100644 index 0000000..1f3b906 Binary files /dev/null and b/.gitbook/assets/image (14).png differ diff --git a/.gitbook/assets/image (15).png b/.gitbook/assets/image (15).png new file mode 100644 index 0000000..e12e508 Binary files /dev/null and b/.gitbook/assets/image (15).png differ diff --git a/.gitbook/assets/image (16).png b/.gitbook/assets/image (16).png new file mode 100644 index 0000000..e83633f Binary files /dev/null and b/.gitbook/assets/image (16).png differ diff --git a/.gitbook/assets/image (17).png b/.gitbook/assets/image (17).png new file mode 100644 index 0000000..cbafcde Binary files /dev/null and b/.gitbook/assets/image (17).png differ diff --git a/.gitbook/assets/image (18).png b/.gitbook/assets/image (18).png new file mode 100644 index 0000000..f9c64db Binary files /dev/null and b/.gitbook/assets/image (18).png differ diff --git a/.gitbook/assets/image (2) (1) (1) (1).png b/.gitbook/assets/image (2) (1) (1) (1).png new file mode 100644 index 0000000..301abde Binary files /dev/null and b/.gitbook/assets/image (2) (1) (1) (1).png differ diff --git a/.gitbook/assets/image (2) (1) (1).png b/.gitbook/assets/image (2) (1) (1).png new file mode 100644 index 0000000..2782b94 Binary files /dev/null and b/.gitbook/assets/image (2) (1) (1).png differ diff --git a/.gitbook/assets/image (2) (1).png b/.gitbook/assets/image (2) (1).png new file mode 100644 index 0000000..250f463 Binary files /dev/null and b/.gitbook/assets/image (2) (1).png differ diff --git a/.gitbook/assets/image (2).png b/.gitbook/assets/image (2).png new file mode 100644 index 0000000..93f5ebd Binary files /dev/null and b/.gitbook/assets/image (2).png differ diff --git a/.gitbook/assets/image (3) (1) (1) (1).png b/.gitbook/assets/image (3) (1) (1) (1).png new file mode 100644 index 0000000..1f87bb2 Binary files /dev/null and b/.gitbook/assets/image (3) (1) (1) (1).png differ diff --git a/.gitbook/assets/image (3) (1) (1).png b/.gitbook/assets/image (3) (1) (1).png new file mode 100644 index 0000000..36cd2d6 Binary files /dev/null and b/.gitbook/assets/image (3) (1) (1).png differ diff --git a/.gitbook/assets/image (3) (1).png b/.gitbook/assets/image (3) (1).png new file mode 100644 index 0000000..c1ffbe4 Binary files /dev/null and b/.gitbook/assets/image (3) (1).png differ diff --git a/.gitbook/assets/image (3).png b/.gitbook/assets/image (3).png new file mode 100644 index 0000000..153a87b Binary files /dev/null and b/.gitbook/assets/image (3).png differ diff --git a/.gitbook/assets/image (4) (1).png b/.gitbook/assets/image (4) (1).png new file mode 100644 index 0000000..5ceb027 Binary files /dev/null and b/.gitbook/assets/image (4) (1).png differ diff --git a/.gitbook/assets/image (4).png b/.gitbook/assets/image (4).png new file mode 100644 index 0000000..fb82f3c Binary files /dev/null and b/.gitbook/assets/image (4).png differ diff --git a/.gitbook/assets/image (5) (1).png b/.gitbook/assets/image (5) (1).png new file mode 100644 index 0000000..2d659b8 Binary files /dev/null and b/.gitbook/assets/image (5) (1).png differ diff --git a/.gitbook/assets/image (5).png b/.gitbook/assets/image (5).png new file mode 100644 index 0000000..88c9975 Binary files /dev/null and b/.gitbook/assets/image (5).png differ diff --git a/.gitbook/assets/image (6).png b/.gitbook/assets/image (6).png new file mode 100644 index 0000000..fb82f3c Binary files /dev/null and b/.gitbook/assets/image (6).png differ diff --git a/.gitbook/assets/image (7).png b/.gitbook/assets/image (7).png new file mode 100644 index 0000000..c1ffbe4 Binary files /dev/null and b/.gitbook/assets/image (7).png differ diff --git a/.gitbook/assets/image (8).png b/.gitbook/assets/image (8).png new file mode 100644 index 0000000..c8c27fc Binary files /dev/null and b/.gitbook/assets/image (8).png differ diff --git a/.gitbook/assets/image (9).png b/.gitbook/assets/image (9).png new file mode 100644 index 0000000..8e79ee1 Binary files /dev/null and b/.gitbook/assets/image (9).png differ diff --git a/.gitbook/assets/image.png b/.gitbook/assets/image.png new file mode 100644 index 0000000..9477ba8 Binary files /dev/null and b/.gitbook/assets/image.png differ diff --git a/.gitbook/assets/image1.gif b/.gitbook/assets/image1.gif new file mode 100644 index 0000000..10aaa70 Binary files /dev/null and b/.gitbook/assets/image1.gif differ diff --git a/Algorithms/Backtracking/README.md b/Algorithms/Backtracking/README.md index 2239297..dc406e3 100644 --- a/Algorithms/Backtracking/README.md +++ b/Algorithms/Backtracking/README.md @@ -1,8 +1,12 @@ -## Backtracking Algorithm Applications -- To find all Hamiltonian Paths present in a graph. -- To solve the N Queen problem. -- Maze solving problem. -- The Knight's tour problem. - -## References -- [Programiz - Backtracking-Algorithm](https://www.programiz.com/dsa/backtracking-algorithm) \ No newline at end of file +# Backtracking + +### Backtracking Algorithm Applications + +* To find all Hamiltonian Paths present in a graph. +* To solve the N Queen problem. +* Maze solving problem. +* The Knight's tour problem. + +### References + +* [Programiz - Backtracking-Algorithm](https://www.programiz.com/dsa/backtracking-algorithm) diff --git a/Data-Structures/Array/README.md b/Data-Structures/Array/README.md index 8b13789..677183c 100644 --- a/Data-Structures/Array/README.md +++ b/Data-Structures/Array/README.md @@ -1 +1,140 @@ +# Array +**Arrays** **provide** a means of **storing and organizing data** in a systematic and computer-memory-efficient manner. + +Essentially, **an array** is a collection of elements, **with each element identified** by an array index. The array _elements **are stored** in contiguous memory locations_, **implying that they are stored** in a sequence. + + + +Arrays can be categorized into two types based on their ability to adjust size: + +* **Static Arrays:** + * Maintain a fixed size determined during declaration. + * Size remains unchangeable throughout program execution. + * Memory allocation occurs once. + * Array size never changes. +* **Dynamic Arrays:** + * Can adjust size during runtime. + * Adapt to the volume of data they store. + * Efficient memory usage. + * Resizing may involve additional operations (e.g., creating a new array, copying elements), imposing overhead on certain operations. + + + +### Operations + +#### Accessing Elements + +* The position of an element within an array can be determined by its index, through which the element is accessed. +* Accessing elements in an array is an `O(1)` time complexity operation. + + + +#### Inserting Elements + +* At the end: An element **can be inserted** at the end of an array, which is usually an `O(1)` **operation**. +* At a specific index: If insertion is desired at a particular index, subsequent elements **must be shifted** to make room, **escalating the time complexity** to `O(n)` in the worst case. + + + +#### Deleting Elements + +* From the end: An element **can be removed** from the end, which is typically an `O(1)` **operation**, as it doesn’t require repositioning of other elements. +* From a specific index: Deletion from a particular index **requires shifting** the subsequent elements to fill the gap, making it an **operation** with time complexity `O(n)` in the worst case. + + + +#### Searching + +* **Identifying the index** of a specified element **involves searching**. Without any additional information or constraints, **a linear search is performed**, scanning each element until the sought one is found, **associating it with an `O(n)` complexity**. +* However, if the array is sorted, **binary search can be employed**, **reducing the complexity to `O(logn)`**. + + + +#### Updating Elements + +* Generally the updating operation can take `O(1)`, because it changes the value at a specified memory location, which can be accessed without scanning the array. + + + +#### Array Time Complexity Operations Summary + +

Font: Design Gurus, 2023a

+ +### Properties + +#### Memory Allocation + +Contiguous memory allocation defines arrays, implying that each element is stored in adjacent memory locations. This enables **arrays to offer constant-time access to any element using its index**, as the memory address of any element can be calculated using the base address, the size of an element, and the index of the element. + + + +#### Indexing + +Indexing enables direct access to any element within the array, thereby facilitating operations like search, update, and direct access with a consistent time complexity of `O(1)`. + + + +### Arrays in Coding Interviews + +1. **Validating Assumptions**: + * Clarify if duplicate values are allowed. + * Check whether the array is sorted. +2. **Boundary Conditions**: + * Prevent index out of bounds errors. + * Be cautious with negative indices. +3. **Efficiency Concerns**: + * Be careful with slicing and concatenating, because slicing and concatenating can take `O(n)` time. + * Consider in-place manipulation vs. creating new arrays. +4. **Variable Naming and Loop Indices**: + * Use descriptive variable names. + * Mind loop indices to prevent off-by-one errors. +5. **Algorithm Choice and Complexity**: + * Understand time and space complexity. + * Beware of nested loops, because time complexity can rapidly escale (e.g., to `O(n²)`) +6. **Testing**: + * Test with edge cases for robustness. + * Handle various inputs. +7. **Handling Zeros and Negatives**: + * Always clarify how to handle zeros and negative numbers in array problems. + * Crucial for problems related to product or sum. +8. **Modification During Iteration**: + * Be cautious when modifying an array during iteration. + * Modifying in-place can introduce bugs or unintended behaviors. + * Consider **iterating backwards** or using a separate array for modifications. +9. **Array Methods Familiarity**: + * Understand the array methods provided by your programming language. + * Know their time and space complexities. +10. **Partial Results**: + * Use intermediate variables (e.g., prefix sums or suffix products) to optimize repeated calculations. + * Weigh the pros and cons of making multiple passes through the array. +11. **Parallel and Reverse Iteration**: + * Iterating through an array from the end or using parallel iteration can lead to optimal solutions. +12. **Understanding Problem Requirements**: + * Ensure you correctly understand problem requirements and constraints to avoid incorrect solutions. + + + +### **Java Arrays** + +1. **Fixed Size**: In Java, when you create an array, you need to define its size, and it can’t be changed later. + * Example: `int[] numbers = new int[115];` +2. **Same Data Type**: All elements in a Java array must be of the same type. +3. **Primitive and Object Arrays**: Java supports arrays of primitives (int, char, etc.) and objects. + * Primitive arrays are more memory-efficient. +4. **Direct Memory Allocation**: Java arrays are allocated memory directly, ensuring quick access but also meaning you need to manage sizes carefully. + + + +### Python Arrays + +1. **Dynamic Lists**: Python’s “arrays” are actually lists, and they can grow or shrink in size. + * Example: `numbers = [1, 2, 3, 5, 7]`, and you can simply do `numbers.append(4)`. +2. **Mixed Data Types**: You can store different types of elements in a Python list. + * Example: `mixed = [1, "dois", 3.0]` +3. **Objects Under the Hood**: Even if you store a primitive type like an integer, Python treats it as an object. +4. **Memory Overhead**: Because of its flexibility and dynamic nature, Python lists have more memory overhead than Java arrays. + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Arrays. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6465cce0468851553fab6fdc](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6465cce0468851553fab6fdc)>. Acesso em: 8 dez. 2023a. diff --git a/Data-Structures/Heap/README.md b/Data-Structures/Heap/README.md index 1ffbc74..df17c7b 100644 --- a/Data-Structures/Heap/README.md +++ b/Data-Structures/Heap/README.md @@ -1,26 +1,272 @@ -## What’s a heap? -A heap is a tree-like data structure where each node must be ordered with respect to the value of its children. There are two types of heap: max heap and min heap. In a max heap, parent node values are greater than those of their children, whereas the opposite is true in a min heap.3 +# Heap -## Why Study Heap ? -A heap is a useful and efficient way to store and look up data that must maintain order. An practical implementation of heap in the real world is priority queue. +### What we are trying to Solve? Handling priority -Priority queue is a set of data where higher or lower valued data points to the front of the queue and are therefore accessed first. +* Problem Description: given a collection of tasks with different priorities, determine which task should be executed next. +* Whenever resources (for example, CPU usage) are limited, there comes the need to prioritise. +* Applications include: graph algorithms like Dijkstra's, scheduling algorithms, and sorting. + + + +### What’s a heap? + +* A heap is a tree-like data structure where each node must be ordered with respect to the value of its children. +* There are two types of heap: **maxHeap** and **minHeap**. In a **maxHeap**, parent node values are greater than those of their children, whereas the opposite is true in a **minHeap**. + + + +### Why Study Heap ? + +A heap is a useful and efficient way to store and look up data that must maintain order. An practical implementation of heap in the real world is priority queue. + +Priority queue is a set of data where higher or lower valued data points to the front of the queue and are therefore accessed first. + + + +### Binary Heap -## Priority queues Priority queues are frequently implemented as binary heap. -- enqueue and extract-min/max run in time O(log n); -- findmin runs in time O(1) -## Heap Important Features -Definition: We define the “height” of a node in a heap to be the number of edges on the longest simple downward path from the node to a leaf. The height of a heap is the height of its root. +* enqueue and extract-min/max run in time `O(log n)`. +* `findMin()`/`findMax()` runs in time `O(1)`. +* :information\_source: Awesome video from WILLIAN FISET explaining Priority Queue/Heaps :link:[Priority Queue Intro](https://www.youtube.com/watch?app=desktop\&v=wptevk0bshY). +* The heapify operation efficiently converts an array into a heap in `O(n)` time. + + + +* Binary heaps are a type of binary tree commonly used to implement heaps. +* **The structure of a binary heap** ensures **completeness** and **shape**. + * Completeness means all levels of the tree are filled except the last level, which is filled from left to right. + * Shape refers to the binary tree being a full binary tree, with the last level having the fewest nodes. +* **The heap order property** determines the **arrangement** of **elements** within the binary heap. In a **maxHeap**, the key of a node is greater than or equal to the keys of its descendants. In a **minHeap**, the key of a node is less than or equal to the keys of its descendants. +* To maintain the proper functioning of insertion and deletion operations, it is crucial to preserve the heap ordering property. + * New elements added to the heap should either "bubble up" (percolate upwards) or "bubble down" (percolate downwards) to maintain the heap invariant. + + + +#### Stacks & Queues vs. Priority Queue + +> Whereas both stacks and queues 4 depended solely on the order in which data was inserted, priority queues use an additional piece of information to determine the retrieval order. +> +> \- KUBICA, 2022 + + + +#### Adding a new Element in a minHeap + +1. Begin by placing the key in the first available spot from the left on the heap’s last level. + * If the last level is fully occupied, position the key as the leftmost element on the subsequent level (This action maintains the property of a complete binary tree). +2. Now it is necessary verify if the **minHeap** property is still intact. + 1. If the parent of the inserted key is less than the key, the **minHeap** property remains unviolated. + 2. Else, the parent’s value is greater than the inserted key, swap their positions. + * :information\_source: This action might disrupt the heap property at the parent node, so continue this process until the heap property is restored. + +* The time complexity of inserting an element is O(logN). +* The following illustrates how -1 is inserted into a Binary heap by adhering to the steps outlined above. + +

Font: ANGAJALA, 2022

+ + + +### Binary Heap - Implementation + + + +#### Iterative Approach + +1. Append the new node at the end of the array. +2. Initialize index to the new item's index +3. Loop while index is not at the root: + 1. Calculate the parent's index + 2. Swap if the parent has the greater key. + 3. Set index to the parent's index +4. Exit loop once heap property is satisfied. + +```java +public void insertMinHeap(int[] arr, int value) { + int n = arr.length; + arr[n] = value; + int index = n; + + while (index > 0 && value < arr[(index - 1) / 2]) { + arr[index] = arr[(index - 1) / 2]; + index = (index - 1) / 2; + } + + arr[index] = value; +} +``` + +```java +import java.util.Arrays; + +public class Solution { + private int[] arr; + private int size; + + public Solution() { + arr = new int[10]; // Initial capacity, can be adjusted as needed + size = 0; + } + + public void insertMinHeap(int value) { + /** + * Insert a new element into the min heap. + * + * @param value (int): The value to be inserted into the min heap. + */ + int n = size; + if (size >= arr.length) { + // Double the size of the array if it's full + arr = Arrays.copyOf(arr, arr.length * 2); + } + arr[n] = value; + size++; + + int key = n; + while (key > 0 && value < arr[(key - 1) / 2]) { + arr[key] = arr[(key - 1) / 2]; + key = (key - 1) / 2; + } + + arr[key] = value; + } + + //Print the min heap. + public void printMinHeap() { + System.out.print("Min Heap: "); + for (int index = 0; index < size; index++) { + System.out.print(arr[index] + " "); + } + System.out.println(); + } + + public static void main(String[] args) { + Solution minHeap = new Solution(); + + // Test case 1 + minHeap.insertMinHeap(5); + minHeap.printMinHeap(); + + // Test case 2 + minHeap.insertMinHeap(2); + minHeap.printMinHeap(); + + // Test case 3 + minHeap.insertMinHeap(8); + minHeap.printMinHeap(); + } +} + +``` + + + +#### Iterative Approach + +1. Append new item to end of heap array +2. Call recursive helper to heapify up: + 1. If index 0, return (base case) + 2. Get parent index + 3. If parent > item, swap them + 4. Call heapifyUp recursively on the parent index. + +````java +import java.util.Arrays; + +public class Solution { + public static void printMinHeap(int[] arr, int size) { + // Function to print the min heap + System.out.print("Min Heap: "); + for (int index = 0; index < size; index++) { + System.out.print(arr[index] + " "); + } + System.out.println(); + } + + public static void heapify(int[] arr, int size, int index) { + // Function to heapify the min heap from the given index + int smallestValue = index; + int leftChild = 2 * index + 1; + int rightChild = 2 * index + 2; + + if (leftChild < size && arr[leftChild] < arr[smallestValue]) { + smallestValue = leftChild; + } + + if (rightChild < size && arr[rightChild] < arr[smallestValue]) { + smallestValue = rightChild; + } + + if (smallestValue != index) { + int temp = arr[index]; + arr[index] = arr[smallestValue]; + arr[smallestValue] = temp; + heapify(arr, size, smallestValue); + } + } + + public static void insertMinHeap(int[] arr, int value, int size) { + arr[size] = value; + size++; + + for (int index = size / 2 - 1; index >= 0; index--) { + heapify(arr, size, index); + } + } + + public static void main(String[] args) { + int[] minHeap = new int[100]; // Assuming max heap size is 100 + int size = 0; // Current size of the heap + + // Test case 1 + insertMinHeap(minHeap, 5, size++); + printMinHeap(minHeap, size); + + // Test case 2 + insertMinHeap(minHeap, 2, size++); + printMinHeap(minHeap, size); + + // Test case 3 + insertMinHeap(minHeap, 8, size++); + printMinHeap(minHeap, size); + } +} +``` +```` + + + +### Array Time Complexity Operations Summary + +

Font: Design Gurus, 2023a

+ + + +### Heap Important Features + +**Definition:** We define the “height” of a node in a heap to be the number of edges on the longest simple downward path from the node to a leaf. **The height of a heap is the height of its root**. + +**Fact:** A heap of `n` nodes has a height of logn c. (Why? Hint: if a heap has height h, what are the minimum and maximum possible number of elements in it? Answer: 2h ≤ n ≤ 2 h+1 − 1) + +Definition: The “max-heap property” (of a heap A) is the property we were talking about, where for every node i other than the root, A\[parent\[i]] ≥ A\[i]. The “min-heap property” is defined analogously. + +* Its left child has index 2i +* Its right child has index 2i + 1 +* Its parent has index bi/2c +* the number of non-leaves nodes are `|_n/2_|` +* The leaves of the heap are the nodes indexed by `|_n/2_|` + 1, . . . , n. + + + +### References + +KUBICA, Jeremy. Data Structures the Fun Way_._ 2nd ed_._ San Francisco: No Starch Press, 2022. + + -Fact: A heap of n nodes has a height of blog nc. (Why? Hint: if a heap has height h, what are the minimum and maximum possible number of elements in it? Answer: 2h ≤ n ≤ 2 h+1 − 1) +ANGAJALA, SaiSri. Insert in Binary Heap. takeUforward, 2022. Disponível em: <[https://takeuforward.org/heap/insert-in-binary-heap/](https://takeuforward.org/heap/insert-in-binary-heap/)>. Acesso em: 6 jan. 2024. -Definition: The “max-heap property” (of a heap A) is the property we were talking about, where for every node i other than the root, A[parent[i]] ≥ A[i]. The “min-heap property” is defined analogously. -- Its left child has index 2i -- Its right child has index 2i + 1 -- Its parent has index bi/2c -- the number of non-leaves nodes are `|_n/2_|` -- The leaves of the heap are the nodes indexed by `|_n/2_|` + 1, . . . , n. +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Heap. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 6 jan. 2024a. diff --git a/Data-Structures/README.md b/Data-Structures/README.md index 1be11cc..c126ba8 100644 --- a/Data-Structures/README.md +++ b/Data-Structures/README.md @@ -1 +1,16 @@ -# [Data-Structures](https://sixth-gibbon-10e.notion.site/Data-Structure-1acc24808b1540c79e6a3cbe71498364) \ No newline at end of file +# Data-Structures + +Data structures **can be broadly categorized** into: + +1. **Primitive Data Structures**: Basic data structures that **include** Integers, Float, Character, and Boolean. +2. **Non-Primitive Data Structures**: More complex data structures that **are further classified** into: + * **Linear Data Structures**: In these data structures, data elements **are arranged** sequentially. Examples **include** arrays, linked lists, stacks, and queues. + * **Non-Linear Data Structures**: Here, data elements **aren’t placed** in a sequence. Examples **are** graphs and trees. + +

Font: Design Gurus, 2023a

+ + + +### Reference + +Design Gurus. Grokking Data Structures for Coding Interviews: Types of Data Structures. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/647dac25f9f9b054d2a2a56c](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/647dac25f9f9b054d2a2a56c)>. Acesso em: 8 dez. 2023a. diff --git a/Data-Structures/graph/README.md b/Data-Structures/graph/README.md new file mode 100644 index 0000000..7af39f9 --- /dev/null +++ b/Data-Structures/graph/README.md @@ -0,0 +1,2 @@ +# Graph + diff --git a/Data-Structures/graph/graph-introduction.md b/Data-Structures/graph/graph-introduction.md new file mode 100644 index 0000000..4f5f872 --- /dev/null +++ b/Data-Structures/graph/graph-introduction.md @@ -0,0 +1,61 @@ +# Graph Introduction + +According to Kubica (2022), a graph is a set of nodes and a set of edges, and each edge connects a pair of nodes. + + + +What a graph can represent? (KUBICA, 2022): + +* Social networks (nodes are people and edges are their connections). +* Transportation networks (nodes are cities and edges represent paths). +* Computer networks (nodes are computers and edges represent the connections between them). + + + +Well-known graph algorithms (KUBICA, 2022): + +* Dijkstra’s algorithm for shortest paths. +* Prim’s algorithm for minimum-cost spanning trees. +* Kahn’s algorithm for topological sort. + + + +### Graph Types + +Graph Types (KUBICA, 2022 e Design Gurus, 2023): + +* **Undirected graph** (represent two-way relationships). + +

Font: KUBICA, 2022

+ +* **Directed graph** or digraph (represent one-way relationships)_._ + +

Font: KUBICA, 2022

+ +* **Edge weights** graph (capture the link between nodes but also **the cost of that link**). + +

Font: KUBICA, 2022

+ +* **Cyclic graph** (there is a closed path (sequence of nodes) that starts and ends at the same node). +* **Acyclic graph** (the **directed** edges arranged such that the graph contains no cycles). + +

Font: KUBICA, 2022

+ + + +### Common Graph Terminologies + +* Digraph: A digraph, short for directed graph. +* Loop in graph: refers to an edge that connects a node to itself. +* Adjacent Nodes: Two nodes are adjacent if an edge is connected directly. +* Degree of a Node: The degree of a node is the number of edges connected to it. + * The in-degree (number of incoming edges). + * The out-degree (number of outgoing edges). + + + +### References + +KUBICA, Jeremy. Data Structures the Fun Way_._ 2nd ed_._ San Francisco: No Starch Press, 2022. + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Heap. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 6 jan. 2024a. diff --git a/Data-Structures/graph/graph-knowledge-to-solve-problems.md b/Data-Structures/graph/graph-knowledge-to-solve-problems.md new file mode 100644 index 0000000..73e96bf --- /dev/null +++ b/Data-Structures/graph/graph-knowledge-to-solve-problems.md @@ -0,0 +1,42 @@ +# Graph Knowledge to Solve Problems + +### Problem - Find the smallest number of starting points to reach all nodes + +Given a directed acyclic graph determine the smallest number of initial nodes such that you can access all the nodes by traversing edges. + +In a directed graph, if a node doesn't have any incoming edges (in-degree of 0), then it means that the node cannot be reached from any other node. Hence, such nodes are mandatory starting points to ensure that every node in the graph can be reached. + +[Minimum Number of Vertices to Reach All Nodes](https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/) + + + +### Problem - **Solving puzzles with only one solution** + +**DFS** can be used to find a solution to a puzzle with only one solution, such as a maze or a sudoku. + + + +### Problem - **Path Finding** + +DFS can be used to find a path between two given nodes u and v. + + + +### Problem - Test if a graph is strongly connected + +**To Test if a graph is strongly connected**: DFS can be used to find out whether a graph is strongly connected or not. + + + +### Problem - Find shortest path + +**BFS** is useful for finding the **shortest path** in unweighted graphs and for + + + +### **Problem - Systematicaly exploring graph** + +**BFS is useful for systematically exploring graphs**. Also, it can be useful for detecting cycles. + + + diff --git a/Data-Structures/graph/graph-operations.md b/Data-Structures/graph/graph-operations.md new file mode 100644 index 0000000..e1e71f5 --- /dev/null +++ b/Data-Structures/graph/graph-operations.md @@ -0,0 +1,184 @@ +# Graph Operations + +Graph operations: + +* Adding a new node +* Removing a node +* Adding an edge between two node +* Removing an edge between two node +* Getting a list of all the node +* Checking if two graph nodes are adjacent to each other or not +* Getting count of the total node in the graph +* Getting count of the total edges in the graph +* Getting a list of the graph edges +* Getting neighbors of a graph node + + + +```java +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Graph { + private Map> adjacencyList; + + public Graph() { + adjacencyList = new HashMap<>(); + } + + + // Check if node already exists + // Use predefined map or dictionary search methods + // If not, add it by inserting new key-value pair + // Keep value of the new inserted node as empty list + public void addNode(int node) { + if (!adjacencyList.containsKey(node)) { + adjacencyList.put(node, new ArrayList<>()); + } + } + + public void removeNode(int node) { + if (!adjacencyList.containsKey(node)) { + return; + } + adjacencyList.remove(node); + for (List neighbors : adjacencyList.values()) { + neighbors.removeIf(v -> v == node); + } + } + + // Undirected relationship + public void addEdge(int node1, int node2) { + adjacencyList.computeIfAbsent(node1, k -> new ArrayList<>()).add(node2); + adjacencyList.computeIfAbsent(node2, k -> new ArrayList<>()).add(node1); + + //adjacencyList.get(node1).add(node2); + //adjacencyList.get(node2).add(node1); + } + + public void removeEdge(int node1, int node2) { + adjacencyList.get(node1).removeIf(v -> v == node2); + adjacencyList.get(node2).removeIf(v -> v == node1); + } + + public List getNodes() { + return new ArrayList<>(adjacencyList.keySet()); + } + + public List> getEdges() { + List> edges = new ArrayList<>(); + for (Map.Entry> entry : adjacencyList.entrySet()) { + int node1 = entry.getKey(); + for (int neighbor : entry.getValue()) { + int node2 = neighbor; + if (node1 < node2) { + edges.add(new Pair<>(node1, node2)); + } + } + } + return edges; + } + + public List getNeighbors(int node) { + return new ArrayList<>(adjacencyList.getOrDefault(node, new ArrayList<>())); + } + + public boolean isAdjacent(int node1, int node2) { + List neighbors = adjacencyList.getOrDefault(node1, new ArrayList<>()); + return neighbors.contains(node2); + } + + public int getNodeCount() { + return adjacencyList.size(); + } + + public int getEdgeCount() { + int count = 0; + for (List neighbors : adjacencyList.values()) { + count += neighbors.size(); + } + return count / 2; + } + + +} + + +``` + +```java +class Pair { + private T first; + private U second; + + public Pair(T first, U second) { + this.first = first; + this.second = second; + } + + public T getFirst() { + return first; + } + + public U getSecond() { + return second; + } +} +``` + +```java + public static void main(String[] args) { + Graph graph = new Graph(); + graph.addNode(1); + graph.addNode(2); + graph.addNode(3); + graph.addNode(4); + graph.addNode(5); + graph.addNode(6); + graph.addEdge(1, 2); + graph.addEdge(1, 3); + graph.addEdge(2, 3); + graph.addEdge(3, 4); + graph.addEdge(4, 5); + graph.addEdge(5, 6); + + System.out.print("Nodes: "); + for (int node : graph.getNodes()) { + System.out.print(node + " "); + } + System.out.println(); + + System.out.print("Edges: "); + for (Pair edge : graph.getEdges()) { + System.out.print("(" + edge.getFirst() + ", " + edge.getSecond() + ") "); + } + System.out.println(); + + System.out.print("Neighbors of node 1: "); + for (int neighbor : graph.getNeighbors(1)) { + System.out.print(neighbor + " "); + } + System.out.println(); + + System.out.println("Is node 1 adjacent to node 2? " + graph.isAdjacent(1, 2)); + + graph.removeEdge(1, 2); + graph.removeNode(3); + + System.out.println("After removing some edges and Nodes:"); + + System.out.print("Nodes: "); + for (int node : graph.getNodes()) { + System.out.print(node + " "); + } + System.out.println(); + + System.out.print("Edges: "); + for (Pair edge : graph.getEdges()) { + System.out.print("(" + edge.getFirst() + ", " + edge.getSecond() + ") "); + } + System.out.println(); + } +``` diff --git a/Data-Structures/graph/graph-representations.md b/Data-Structures/graph/graph-representations.md new file mode 100644 index 0000000..c007acc --- /dev/null +++ b/Data-Structures/graph/graph-representations.md @@ -0,0 +1,75 @@ +# Graph Representations + +Graph can be represented in two ways: + +1. Adjacency matrix. +2. Adjacency list. + + + +### Adjacency Matrix + +It is a square matrix where the rows and columns represent the nodes of the graph, and the entries (elements) of the matrix indicate whether there is an edge between the corresponding nodes. + + + +#### Adjacency Matrix for Undirected Graphs + +For an undirected edge between nodes i and j, the corresponding entries in the matrix (A\[i]\[j] and A\[j]\[i]) will have a value of 1, indicating the presence of an edge. If there is no edge between nodes i and j, the matrix entries will have the value of 0. + + + +

Font: Design Guru, 2023a

+ + + +#### Adjacency Matrix for Directed Graphs + +

Font: Design Guru, 2023a

+ + + +### Adjacency list + +In linked list representation, an adjacency list is used to store the graph. In an adjacency list, each nodes is associated with a list of its neighbouring nodes directly connected to it. + + + +#### Representing Undirected Graphs Using Adjacency List + +

Font: Design Guru, 2023a

+ + + +#### Representing Directed Graphs Using Adjacency List + +

Font: Design Guru, 2023a

+ + + +**Java code Example Directed Graphs Using Adjacency List:** + +```java +// ArrayList of linked lists of integers: +ArrayList> adj_list; + +// HashMap of linked lists of integers: +HashMap> adjacencyList; + + +// Initialisation code +// ... + +// A->B, A->C, C->D, D->B +// (0 -> 1), (0 -> 2), (2 -> 3), (3 -> 1) +adj_list.get(0).add(1); +adj_list.get(0).add(2); +adj_list.get(2).add(3); +adj_list.get(3).add(1) +``` + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Graph. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 6 jan. 2024a. diff --git a/Data-Structures/graph/graph-traversal-breadth-first-search-bfs.md b/Data-Structures/graph/graph-traversal-breadth-first-search-bfs.md new file mode 100644 index 0000000..fafba69 --- /dev/null +++ b/Data-Structures/graph/graph-traversal-breadth-first-search-bfs.md @@ -0,0 +1,125 @@ +# Graph Traversal - Breadth First Search (BFS) + +### Graph Traversal + +* All the nodes in the graph are visited during graph traversal, following a specific strategy or order. +* Each node is typically marked as visited during the traversal process. +* The marking of nodes as visited is done to avoid multiple visits to the same node. +* This marking also prevents infinite loops in cyclic graphs. + + + +### Breadth First Search (BFS) + +> Breadth-First Search (BFS) is a graph traversal algorithm that explores a graph's vertices (nodes) level by level. It starts from a selected source node and moves outward to visit all the nodes at the same distance from the source before moving on to nodes at the following distance level. +> +> \- DesignGurus, 2023a + + + +#### Where BFS is Useful? + +BFS is useful for finding the **shortest path** in unweighted graphs and for **systematically exploring graphs**. Also, it can be useful for detecting cycles. + + + +#### BFS Pseudo Code + +1. **Initialisation**: The algorithm starts from a chosen node (source node), and a queue is created to hold the nodes to be visited. The source node is marked as visited and enqueued into the queue. + * The queue follows the First-In-First-Out (FIFO) principle and is responsible to keep track of the nodes to be visited. +2. **Traversal**: While the queue is not empty, a node is dequeued from the front of the queue (current node) and processed. All the unvisited neighbours of the current node are enqueued into the queue and marked as visited. + * The BFS property of breadth graph exploration is guaranteed by using a queue FIFO instead of a stack. +3. **Termination**: The BFS algorithm continues until the queue becomes empty, meaning all nodes reachable from the source node have been visited. + + + +#### DFS Java Code + +```java +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +class Graph { + private int V; // Number of nodes + private ArrayList> adjList; + + public Graph(int nodes) { + V = nodes; + adjList = new ArrayList<>(V); + for (int i = 0; i < V; i++) { + adjList.add(new ArrayList<>()); + } + } + + public void addEdge(int u, int v) { + adjList.get(u).add(v); + adjList.get(v).add(u); // For undirected graph + } + + public void BFS(int startNode) { + boolean[] visited = new boolean[V]; // To keep track of visited nodes + Queue q = new LinkedList<>(); + + visited[startNode] = true; + q.add(startNode); + + while (!q.isEmpty()) { + int currentNoded = q.poll(); + System.out.print(currentNoded + " "); + + // Explore adjacent nodes + for (int neighbor : adjList.get(currentNoded)) { + if (!visited[neighbor]) { + visited[neighbor] = true; + q.add(neighbor); + } + } + } + } +} +``` + +```java +class Solution { + public static void main(String[] args) { + Graph graph = new Graph(6); // Create a graph with 6 nodes + + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(1, 3); + graph.addEdge(2, 4); + graph.addEdge(3, 4); + graph.addEdge(3, 5); + + System.out.println("Breadth-First Traversal starting from Node 0:"); + graph.BFS(0); + } +} +``` + + + +#### BFS Time Complexity + +* Awesome Explanation :link: [Turin Machines - Time Complexity of Depth First Search (DFS) Algorithm](https://www.youtube.com/watch?v=bP3MWJHeohc). +* The time complexity of the BFS algorithm is O(V + E) + * V: Number of nodes. + * E: Number of edges. +* **O(V)**: BFS visits every node once and only once. Each visit takes constant time, so the total time spent on visiting all nodes is proportional to the number of nodes, hence O(V). +* **O(E)** : Additionally, for each node, it is explored all its neighbours once, which takes time O(E) in total (sum of the sizes of all adjacency lists). + * Since each edge is also traversed once and only once, the total time spent on traversing all edges is proportional to the number of edges, hence O(E). + * "It is the _**for loop**_ in both the recursion version or the stack version of the BFS algorithm". + + + +#### BFS Space Complexity + +* The space required to store the graph using an adjacency list representation is O(V + E) , as we need to store each node and its corresponding edges. +* The space required for the queue in BFS is O (V) in the worst case, as all the nodes can be in the queue at once. + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Graph. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 16 jan. 2024a. diff --git a/Data-Structures/graph/graph-traversal-depth-first-search-dfs.md b/Data-Structures/graph/graph-traversal-depth-first-search-dfs.md new file mode 100644 index 0000000..e528181 --- /dev/null +++ b/Data-Structures/graph/graph-traversal-depth-first-search-dfs.md @@ -0,0 +1,197 @@ +# Graph Traversal - Depth First Search (DFS) + +### Graph Traversal + +* All the nodes in the graph are visited during graph traversal, following a specific strategy or order. +* Each node is typically marked as visited during the traversal process. +* The marking of nodes as visited is done to avoid multiple visits to the same node. +* This marking also prevents infinite loops in cyclic graphs. + + + +### Depth-First Search (DFS) + +> Depth-First Search (DFS) is a graph traversal algorithm that explores all the nodes in a graph by systematically visiting as far as possible along each branch before backtracking. +> +> \- Design Guru, 2023a + + + +#### Where DFS is Useful? + +**Path Finding**: DFS can be used to find a path between two given nodes u and v. + +**To Test if a graph is strongly connected**: DFS can be used to find out whether a graph is strongly connected or not. + +* A strongly connected graph is a type of directed graph in which there is a path from each node to every other node, + +**Solving puzzles with only one solution**: DFS can be used to find a solution to a puzzle with only one solution, such as a maze or a sudoku. + + + +#### DFS Pseudo Code + +1. **Initialization**: The algorithm starts from a chosen node (source node), and a data structure ((e.g., an array, a hash set or a stack) is created to keep track of visited nodes. +2. **Visit the Current Node**: The current node is processed. +3. **Recursive Approach**: For each unvisited neighbour of the current node, the DFS function is recursively called with the neighbour as the new current node, which is then marked as visited. +4. **Stack-Based Approach**: The starting node is pushed onto a stack. While the stack is not empty, a node is popped from the stack (current node) and processed. Each unvisited neighbour of the current node is pushed onto the stack and marked as visited. +5. **Backtracking**: If there are no more unvisited neighbours for the current node, the algorithm backtracks by returning from the recursive function or popping nodes from the stack until a node with unvisited neighbours is found. +6. **Termination**: The DFS algorithm terminates when all nodes reachable from the source node have been visited, indicating that all connected components of the graph have been explored. + + + +#### DFS Java Code + +```java +import java.util.ArrayList; +import java.util.Stack; + +class Graph { + private int nodes; + // Using ArrayList instead of HashMap + private ArrayList> adjList; + // private Map> adjacencyList; + + public Graph(int V) { + nodes = V; + adjList = new ArrayList<>(V); + for (int i = 0; i < V; i++) { + adjList.add(new ArrayList<>()); + } + } + + public void addEdge(int u, int v) { + adjList.get(u).add(v); + adjList.get(v).add(u); // For an undirected graph + } + + + + public void DFS(int start) { + boolean[] visited = new boolean[nodes]; + Stack s = new Stack<>(); + + s.push(start); + visited[start] = true; + + while (!s.isEmpty()) { + int curr = s.pop(); + System.out.print(curr + " "); + + for (int neighbor : adjList.get(curr)) { + if (!visited[neighbor]) { + s.push(neighbor); + visited[neighbor] = true; + } + } + } + } +} + +class Solution { + public static void main(String[] args) { + Graph g = new Graph(7); + + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(1, 3); + g.addEdge(1, 4); + g.addEdge(2, 5); + g.addEdge(2, 6); + + System.out.print("DFS Traversal starting from node 0: "); + g.DFS(0); + } +} + +``` + + + +```java +private void dfs(int[][] isConnected, boolean[] visited, int i) { + for (int j = 0; j < isConnected.length; j++) { + if (isConnected[i][j] == 1 && !visited[j]) { + visited[j] = true; + dfs(isConnected, visited, j); // Recursive DFS call + } + } +} + +private void dfsRecursionWay(HashSet visited, HashMap> graph, int node) { + visited.add(node); + var neighbours = graph.get(node); + if (!neighbours.isEmpty()) { + for (int i : neighbours) { + if (!visited.contains(i)) { + dfsRecursionWay(visited, graph, i); + } + } + } + } +``` + + + +```java +private void dfs(int[][] isConnected, boolean[] visited, int start) { + int n = isConnected.length; + Stack stack = new Stack<>(); + stack.push(start); + + while (!stack.isEmpty()) { + int i = stack.pop(); + visited[i] = true; + + for (int j = 0; j < n; j++) { + if (isConnected[i][j] == 1 && !visited[j]) { + stack.push(j); + } + } + } +} + +private void dfsIterativeWay(HashSet visited, HashMap> graph, int node) { + var stack = new Stack(); + + visited.add(node); + stack.add(node); + + while (!stack.empty()) { + var current = stack.pop(); + var adjList = graph.get(current); + + for (Integer neighbour : adjList) { + if (!visited.contains(neighbour)) { + visited.add(neighbour); + stack.add(neighbour); + } + } + } + } +``` + + + +#### DFS Time Complexity + +* Awesome Explanation :link: [Turin Machines - Time Complexity of Depth First Search (DFS) Algorithm](https://www.youtube.com/watch?v=bP3MWJHeohc). +* The time complexity of the Depth-First Search (DFS) algorithm is O(V + E) + * V: Number of nodes. + * E: Number of edges. +* **O(V)**: DFS visits every node once and only once. Each visit takes constant time, so the total time spent on visiting all nodes is proportional to the number of nodes, hence O(V). +* **O(E)**: For each node, DFS explores its adjacent nodes by traversing the corresponding edges. Since each edge is also traversed once and only once, the total time spent on traversing all edges is proportional to the number of edges, hence O(E). + * "It is the _**for loop**_ in both the recursion version or the stack version of the DFS algorithm". + + + +#### DFS Space Complexity + +* It’s worth noting that the space complexity of DFS is also important. In the case of a recursive implementation of DFS, the space complexity is O(V) due to the maximum depth of the recursion stack. +* In the worst case, the maximum depth of the recursion stack (or the maximum number of nodes stored in the stack) is the height of the deepest branch of the graph. For a graph with a single connected component, this height can be (when **all nodes are connected in a straight line**). + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Graph. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 16 jan. 2024a. diff --git a/Data-Structures/hashmap.md b/Data-Structures/hashmap.md new file mode 100644 index 0000000..c1ba589 --- /dev/null +++ b/Data-Structures/hashmap.md @@ -0,0 +1,637 @@ +# HashMap + +* Hashing is the process of converting data — text, numbers, files — into a fixed-length string of letters and numbers. +* The transformation is done using a specific algorithm called a **hash function**. +* The data being transformed is referred to as the **key**, which can be in various formats. +* The **hash function converts the key** into a fixed-length string known as the **hash value**. +* Ideally, each unique key should result in a distinct hash value to ensure uniqueness. + * If two different inputs give the same hash, that's called a **collision**. +* The uniqueness of hash values is crucial for the effectiveness and reliability of hashing. + + + +### Hash Use Cases + +* **Password Security:** Rather than storing actual passwords, systems store their respective hash values. +* **Data Deduplication:** In situations where data storage necessitates the elimination of duplicates, comparing the hashes of data entries becomes an efficient technique. If two data entries share the same hash value, it can be inferred that they represent identical information. +* **Data Integrity Checks:** A hash value for the file may be provided by the site when a file is being downloaded from the web. If there is even a tiny change in the file during the download, a difference will be observed in its hash. Whether the file is exactly as the original, or if it was tampered with during the transfer, can be determined by comparing the hash of the downloaded file with the provided hash. +* **Cryptography**: Some hash functions are used in cryptography to ensure data confidentiality and integrity. +* **Load Balancing**: In big systems serving many users, hashes can be used to decide which server should handle a particular request. +* Hashtable: A hashtable (or hash map), is a data structure that stores data in key-value pairs for efficient retrieval. + * **Keys**** are unique identifiers** for data elements, and **values contain the actual data**. + * The process of hashing applies a hash function to the **key** to generate a numerical index or hash code, which determines the position or bucket within the hashtable where the key-value pair is stored. + * Retrieval involves hashing the key again to locate the corresponding bucket quickly. + * Hashtables offer constant-time average retrieval and insertion, making them efficient for handling large data volumes. + + + +### Hash Table + +* A Hash Table uses a hash function to compute an index into an array of buckets or slots where the desired value is stored. +* **Hash Table has four core elements:** Keys, Values, the Hash Function, and Buckets. + + * **Key:** + * unique identifiers. + * Keys are the inputs feed into the hash function. + * They should be unique. + * If two pieces of data share the same key it is called "collision". + * **Values:** + * Values are the actual data that we store in our Hash Table. + * Using the key, the value can be quickly retrieve from the Hash Table. + * **Hash Function:** + * It's responsible for transforming keys into hash values, which dictate where the data is stored. + * **Bucket:** + * Once the hash function has processed the KEY, it produces a **hash value**. This value corresponds to a specific location or **'bucket'** within the Hash Table. + * Think of buckets as shelves in our library, each one designated to store a specific book (or piece of data). + + + +

Font: RAMACHANDRAN, 2015

+ + + +#### Basic Operations + +* **Insert(key, value) operation:** Calculates the hash index `H(key)` and stores the **key-value** pair in the slot at that index. +* **Search(key) operation:** Computes `H(key)` to find the slot and returns the value associated with the key, or `null` if not present. +* **Delete(key) operation:** Removes the key-value pair stored at index `H(key)`. + + + +### Issues with Hash Table + +#### Collisions + +* A collision in a Hash Table occurs when an insert operation tries to insert an item at a table slot already occupied by another item. + + + +**Overflows** + +* Overflow in a hash table occurs when the number of elements inserted exceeds the fixed capacity allocated for the underlying bucket array. + + + +### Resolving Collisions + +The collision resolution techniques are classified into two types: + +* Open addressing / Closed hashing. +* Chaining / Open hashing. + + + +### Resolving Collisions - Open Addressing (Closed Hashing) + +#### **Linear probing** + +* Linear probing handles collisions by linearly searching consecutive slots for the next empty location. + +

Font: Geeks For Geeks, 2023a

+ +
+ +Searching for a key using linear probing in a hash table involves the following steps + +**1. Calculate the key's hash:** + +* Apply the hash function to the key you want to find. This will give you an index into the hash table. + +**2. Check the initial index:** + +* Look at the element at the index obtained in step 1. + +**3. Compare the key and the element:** + +* If the key matches the element, you've found it! Return "Found". + +**4. Handle collisions:** + +* If the key doesn't match the element, and the element is not empty, there might be a collision (another key occupying the same slot). +* Move to the next index in the table, wrapping around to the beginning if necessary using modulo operation with the table size. + +**5. Repeat steps 3 and 4:** + +* Repeat steps 3 and 4 until one of the following conditions is met: + * The key matches the element at the current index (you found it!). + * You encounter an empty slot (the key is not present in the table). + * You return to the initial index you calculated in step 1 (this indicates you've checked all possible slots without finding the key). + +**6. Check for unsuccessful search:** + +* If you reach the initial index again without finding the key in any slot, the key is not present in the table. Return "Not found". + +
+ +
+ +Problems Related With Linear Probing + +**Primary Clustering:** + +* **What it is:** When multiple keys hash to nearby indices in the hash table, linear probing's sequential search for empty slots can lead to the formation of "clusters" of occupied slots. This creates longer chains of elements that need to be examined during both insertion and searching, degrading performance. +* **Why it happens:** When a collision occurs, linear probing simply checks the next available slot, increasing the likelihood of subsequent collisions in that same area. This creates a snowball effect, where more collisions lead to more clustering and even longer search times. +* **Consequences:** + * Increased search and insertion times, as more probes are needed to find empty slots or target keys. + * Potential for hash table to become "clogged" with clusters, leading to degraded performance even for non-colliding keys. + +\ +**Secondary Clustering:** + +* **What it is:** instead of near the insertion point, probes will cluster around other points. +* **Why it happens:** It's often caused by non-random patterns in the hash values generated by the hash function, or by specific probing sequences that create certain patterns of collisions. +* **Consequences:** + * Exacerbates the performance issues caused by primary clustering, making search and insertion even more time-consuming. + +
+ + + +#### **Quadratic probing** + +* When a collision occurs, the quadratic probing attempts to find an alternative empty slot for the key by using a `quadratic function` to probe the successive possible positions. +* Quadratic probing can help avoid getting locked into the same search pattern as linear probing, which checks slots sequentially. + +

Font: Geeks For Geeks, 2023a

+ +
+ +Searching for a key using quadratic probing in a hash table involves the following steps + + + +**1. Calculate the key's hash:** + +* Apply the hash function to the key you want to find. This will give you an initial index into the hash table. + +**2. Check the initial index:** + +* Look at the element at the index obtained in step 1. + +**3. Compare the key and the element:** + +* If the key matches the element, you've found it! Return "Found". + +**4. Handle collisions:** + +* If the key doesn't match the element, and the element is not empty, there might be a collision (another key occupying the same slot). +* Instead of moving linearly, calculate the next probe index using a quadratic function. A common option is `current_position + (i^2)`, where `i` is an iteration counter starting from 0. Remember to apply modulo with the table size to stay within the table bounds. + +**5. Repeat steps 3 and 4:** + +* Repeat steps 3 and 4 until one of the following conditions is met: + * The key matches the element at the current index (you found it!). + * You encounter an empty slot (the key is not present in the table). + * You have checked all possible slots according to the probing sequence (this indicates you didn't find the key). + +
+ +
+ +Problems Related With Quadratic Probing + + + +**1. Increased search time:** + +* The computation of the probe sequence with squares adds an extra layer of complexity compared to linear probing's simple increments. This can increase the search time, especially for keys that encounter many collisions. + +**2. Secondary clustering:** + +* While primary clustering is reduced, secondary clustering can still occur if the probing sequence creates repetitive patterns based on specific hash values. This can lead to pockets of collisions despite the larger jumps. + +**3. Tuning the probing sequence:** + +* Choosing the right coefficients for the probing sequence (e.g., in `current_position + (i^2)`) can impact performance. An overly aggressive sequence might lead to early exhaustion of the table, while a conservative one might still suffer from clustering. + +**4. Performance on non-random workloads:** + +* Quadratic probing works best when hash values are random and evenly distributed. If the workload leads to predictable patterns in hash values, the probing sequence might become ineffective and lead to clustering. + +**5. Potential for infinite loops:** + +* In rare cases, specific combinations of hash values and probing sequences can create infinite loops where the same slots are repeatedly checked. This requires careful implementation and checks to avoid. + +
+ + + +#### **Double Hashing** + +* It uses two hash functions to determine the next probing location in case of a successive collision. + +

Font: Geeks For Geeks, 2023a

+ +
+ +Searching for a key using Double Hashing probing in a hash table involves the following steps + +1. **Calculate the initial hash values:** + * Apply both hash functions (h1 and h2) to the key you want to find. + * This gives you two hash values: h1(key) and h2(key). +2. **Calculate the initial index:** + * Use the first hash value (h1(key)) as the initial index to probe in the hash table. +3. **Check the initial index:** + * Look at the element at the initial index. + * If the key matches the element, you've found it! Return "Found". +4. **Handle collisions:** + * If the key doesn't match the element, and the element is not empty, there's a collision. + * Use the second hash value (h2(key)) to calculate a step size for probing. + * The next probe index is calculated as: `(initial_index + i * h2(key)) % table_size`, where `i` is an iteration counter starting from 1. +5. **Repeat steps 3 and 4:** + * Keep probing using the calculated indices until one of the following conditions is met: + * The key matches the element at the current index (you found it!). + * You encounter an empty slot (the key is not present in the table). + * You revisit the initial index without finding the key, indicating it's not in the table. +6. **Check for unsuccessful search:** + * If you revisit the initial index without finding the key, it means the key is not present in the table. Return "Not found". + +
+ +
+ +Problems Related With Double Hashing Probing + + + +**1. Dependency on Two Good Hash Functions:** + +* **Effectiveness hinges on both hash functions:** Double hashing relies on two independent hash functions. If either function produces poor distribution or patterns, it can lead to clustering and degrade performance. +* **Careful selection and design:** It's essential to choose hash functions that complement each other and minimize collisions. + +**2. Potential for Clusters:** + +* **Secondary clustering:** Although less severe than in linear or quadratic probing, secondary clustering can still occur if the second hash function generates repetitive step sizes for certain keys. +* **Table size and hash function design:** Mitigate this by choosing a prime table size and ensuring the second hash function produces well-distributed step sizes. + +**3. Deletion Complexity:** + +* **Marking for deletion:** Simply removing an element can disrupt the probing sequence for other keys that might have used it as a step. +* **Special handling:** Typically, deleted elements are marked as "deleted" rather than actually removed to preserve the probing sequence. This can create overhead for tracking deleted slots. + +**4. Rehash Complexity:** + +* **Recalculating probe sequences:** When the table needs to be resized, all elements need to be rehashed with both hash functions to determine their new probe sequences. This can be computationally expensive. +* **Careful planning:** Rehash operations should be minimized by choosing a suitable initial table size and load factor. + +**5. Computational Overhead:** + +* **Two hash calculations:** Double hashing involves calculating two hash values per key, which can add overhead compared to techniques that use a single hash function. +* **Trade-off evaluation:** The potential performance benefits in collision resolution need to be weighed against the computational cost for specific use cases. + +
+ +
+ +Abstract Logic of Double Hashing + + + +1. **Hash the key:** Apply both hash functions to the key to get `hash_value1` and `hash_value2`. +2. **Calculate initial index:** Use `hash_value1` as the first index to probe. +3. **Handle collisions:** If the first index is occupied, use `hash_value2` as the step size to generate subsequent probe indices: + * `index = (hash_value1 + i * hash_value2) % table_size` + * Keep incrementing `i` until an empty slot is found or the entire table has been probed. + +```java + +import java.util.ArrayList; + +public class DoubleHashing { + + public static ArrayList doubleHash(String key, int tableSize, HashFunction hashFunction1, HashFunction hashFunction2) { + /* + * Implements a double hash function for collision resolution. + * + * Args: + * key: The key to be hashed. + * tableSize: The size of the hash table. + * hashFunction1: The first hash function to use. + * hashFunction2: The second hash function to use. + * + * Returns: + * The probe sequence for the key based on the double hash function. + */ + + int hashValue1 = hashFunction1.hash(key, tableSize); + int hashValue2 = hashFunction2.hash(key, tableSize); + + ArrayList probeSequence = new ArrayList<>(); + for (int i = 0; i < tableSize; i++) { + int index = (hashValue1 + i * hashValue2) % tableSize; + probeSequence.add(index); + } + + return probeSequence; + } + + public static void main(String[] args) { + int tableSize = 10; + + HashFunction hashFunction1 = (key, tableSize) -> { + // Example hash function 1: Sum of character ASCII values + int sum = 0; + for (char c : key.toCharArray()) { + sum += c; + } + return sum % tableSize; + }; + + HashFunction hashFunction2 = (key, tableSize) -> { + // Example hash function 2: Length of the key + return key.length() % tableSize; + }; + + String key = "apple"; + ArrayList probeSequence = doubleHash(key, tableSize, hashFunction1, hashFunction2); + + System.out.println("Key: " + key + ", Probe sequence: " + probeSequence); + } +} + +interface HashFunction { + int hash(String key, int tableSize); +} +``` + +
+ + + +### Resolving Collisions - Separate Chaining (Open hashing) + +* Separate chaining each slot in the hash table points to a separate data structure, such as a linked-list. +* This linked-list or "chain" stores multiple elements that **share the same hash index**. +* When a collision occurs, new elements are simply appended to the existing list in the corresponding slot. + +

Font: Design Gurus, 2023a

+ +
+ +Implementation + +```java +import java.util.ArrayList; +import java.util.List; + +class Record { + int Key; + String Title; + String PlacementInfo; + + public Record(int key, String title, String placement_info) { + Key = key; + Title = title; + PlacementInfo = placement_info; + } +} + +class HashTable { + private List> buckets; // List of lists to store the chains + private int max_length; // To store the maximum number of elements a Hash table can store + + public HashTable(int size) { + max_length = size; + buckets = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + buckets.add(new ArrayList<>()); + } + } + + private int H(int key) { + return key % max_length; + } + + public boolean Insert(Record item) { + int index = H(item.Key); + + // Traverse the chain at the index + for (Record record : buckets.get(index)) { + if (record.Key == item.Key) { + return false; // Key already exists in the chain, cannot insert + } + } + + buckets.get(index).add(item); + return true; + } + + public boolean Search(int key, Record returnedItem) { + int index = H(key); + + // Traverse the chain at the index + for (Record record : buckets.get(index)) { + if (record.Key == key) { + returnedItem.Key = record.Key; + returnedItem.Title = record.Title; + returnedItem.PlacementInfo = record.PlacementInfo; + return true; // Return true to indicate the record was found + } + } + + return false; // Record not found + } + + public boolean Delete(int key) { + int index = H(key); + + // Traverse the chain at the index + List chain = buckets.get(index); + for (int i = 0; i < chain.size(); i++) { + Record record = chain.get(i); + if (record.Key == key) { + chain.remove(i); + return true; + } + } + + return false; // The key is not found in the chain + } + + public void ShowTable() { + System.out.println("Index\tValue (Key, Title, PlacementInfo)"); + for (int i = 0; i < max_length; i++) { + System.out.print(i + "\t"); + List chain = buckets.get(i); + if (chain.isEmpty()) { + System.out.println("[EMPTY BUCKET]"); + } else { + for (int j = 0; j < chain.size(); j++) { + Record record = chain.get(j); + if (j > 0) { + System.out.print("--> "); + } + System.out.print("(" + record.Key + ", " + record.Title + ", " + record.PlacementInfo + ")"); + } + System.out.println(); + } + } + } +} + +class Solution { + public static void main(String[] args) { + int tableSize = 11; + HashTable hashTable = new HashTable(tableSize); + + // Insert initial book information + hashTable.Insert(new Record(1701, "Internet of Things", "G1 Shelf")); + hashTable.Insert(new Record(1712, "Statistical Analysis", "G1 Shelf")); + hashTable.Insert(new Record(1718, "Grid Computing", "H2 Shelf")); + hashTable.Insert(new Record(1735, "UML Modeling", "G1 Shelf")); + hashTable.Insert(new Record(1752, "Professional Practices", "G2 Shelf")); + + // Display the hash table after initial insertions + System.out.println("\nHash Table after initial insertions:"); + hashTable.ShowTable(); + + // Insert the following record + hashTable.Insert(new Record(1725, "Deep Learning with Python", "C3 Shelf")); + + // Display the hash table after the last insertion + System.out.println("\nHash Table inserting Book Key 1725:"); + hashTable.ShowTable(); + + // Delete two records + hashTable.Delete(1701); + hashTable.Delete(1718); + + // Display the hash table after deletions + System.out.println("\nHash Table after deleting 1701 and 1718:"); + hashTable.ShowTable(); + } +} +``` + +
+ + + +#### Advantages of Separate Chaining + +* **Dynamic Memory Usage:** Insertions (append new nodes at the chains/linkedlist) and deletions (remove nodes at the chains/linkedlist) can adjust the size of the table based on the number of elements, unlike closed hashing which requires marking deleted items. +* **Simple Implementation:** Implementing separate chaining is straightforward using linked lists. +* **Graceful Handling of Duplicates:** Duplicate keys can be stored and retrieved accurately. + + + +#### Downsides of Separate Chaining: + +* **Increased Memory Overhead:** Additional memory is required to store pointers or references to linked lists, leading to increased memory usage, especially for small data sets. +* **Cache Inefficiency:** Traversing the linked lists can negatively impact cache performance due to non-contiguous memory access, reducing overall efficiency. +* External Fragmentation: Dynamic memory allocation for linked lists can result in external fragmentation, which can affect memory management performance. +* **Worst-Case Time Complexity:** When multiple keys are hashed to the same bucket, forming long linked lists, search, insert, and delete operations can degrade to `O(n)`, making it less suitable for time-critical applications. +* **Memory Allocation Overhead:** Dynamic memory allocation for each new element can introduce overhead and potentially cause performance issues under high memory pressure. + + + +### Handling Overflows + +* Closed hashing techniques experience overflow when entries **fill up the fixed hash table slots**. + * the load-factor `α = n / m` should not cross `0.5`. + * `n` is the number of entries and `m` is table size. +* Open hashing techniques encounters overflow when chain lengths become too long. + * the load-factor `α = n / m` should not cross `0.8` or `0.9`. +* :question:**Why the load-factor should not be crossed**. + * Because the hash table can experiences a **significant increase in collisions**, problems in searching, and degrading performance and integrity of the table operations. +* :question:**How to solve overflow?** + * **Resizing** the hash table can help alleviate the overflow issues. + + + +### Resizing + +* **Resizing** involves increasing the size of a hash table to prevent overflows and maintain a specific **load factor**. +* When the number of elements in the hash table exceeds a certain threshold, resizing ensures that the table can accommodate additional data without compromising performance or causing collisions. +* :question: When resizing, do the old values remain in the same place in the new table? + * **NO**!! As resizing changes the table size, the values must be **Rehashed** to maintain the correctness of the data structure. + + + +### Rehashing + +* Rehashing involves applying a new hash function to all the entries in a hash table to make the table more evenly distributed. +* It is recommended to perform rehashing periodically when the load-factor exceeds thresholds or based on metrics like average chain length. + + + +### Resizing and Rehashing Process + +1. **Load-Factor Threshold Check**: + * The process begins by monitoring the load factor of the hash table. When the load factor exceeds a predefined threshold (often denoted as `α`), it indicates that the table is becoming crowded, and resizing is necessary. +2. **Creating a Larger Hash Table**: + * Upon detecting the need for resizing, a new hash table is created. The capacity of this new table is typically larger than the original one. Common practice involves doubling the size of the existing table. +3. **Element Rehashing**: + * Next, each element from the existing hash table is rehashed into the new table. Rehashing involves recalculating the hash value for each element using the primary hash function, but with the new table size. This step ensures that elements are distributed evenly across the larger table. +4. **Replacing the Old Table**: + * Once all elements have been rehashed, the new hash table replaces the old one. The old table is then deallocated from memory to free up resources. + + + +### Selecting a Hash Function + +#### Characteristics of a good hash function + +* **Uniformity and Distribution** + * It spreads out keys evenly across all slots in the hash table. +* **Collision Reduction** + * Different keys should end up getting mapped to different slots as much as possible. +* **Efficiency** + * Requires minimal processing power and time to compute. + +### Hash function design techniques + +**Division method** + +* The hash code is calculated by taking the remainder obtained by dividing the key by the size of the hash table (the number of buckets). +* Mathematically, the division method is expressed as: `hash_key = key % table_size`. +* :warning: it may not be the best choice if the key distribution is not uniform or the table size is not a prime number, which may lead to clustering. + + + +#### Folding method + +* To calculate the hash code, divide the key into smaller **subkeys** and then combine them. +* **Example of Folding methods:** + 1. **Division method**: + * Split the key into groups of digits, and their sum is taken as the hash code. + * For example, can hash the key `541236` using **digit sum folding** into a hash table of size `5`: + * hash key = `( 5 + 4 + 1 + 2 + 3 + 6 ) % 5` + * hash key = `21 % 5` + * hash key = `1`. + 2. **Reduction**: + * To generate the final hash value, split the key into folds and use reduction with an associative operation such as `XOR` to reduce the folds to a single value. Then, pass this single value through a simple division hash function. + * Example: hash this 12-digit key `593048892357` onto a table of size `11113`. + * split it into 3 parts of digits 4: + * `5930, 4889, 2357`. + * Then XOR the parts and pass through an ordinary hash function as: + * hash key = `(5930`` `**`XOR`**` ``4889`` `**`XOR`**` ``2357) % 11113`. + * hash key = `7041`. +* The **folding method** is an efficient way to handle large keys and provides better key distribution than the division method. +* It is commonly used when dealing with lengthy keys or when **subkeys** need to be created for other purposes. + + + +#### Mid-square Method + +* The mid-square method squares the key, extracts the middle part and uses it as the hash code. +* Process: + * Square the key. + * Extract the K middle digits of the square. + * Apply simple division on these middle digits to get the final hash. +* Example: hash this 4-digit key `3729` onto a table of size `10`. + * Square the key: `3729 * 3729 = 13935241`. + * Extract the middle digits to get the hash value: `935`. + * Calculate the hash: + * hash key = `935 % 10`. + * hash key = `5`. + + + +### Reference + +Geeks For Geeks. Open Addressing Collision Handling technique in Hashing. Geeks For Geeks, \[s.d.]. Disponível em: <[https://www.geeksforgeeks.org/types-of-binary-tree](https://www.geeksforgeeks.org/types-of-binary-tree)>. Acesso em: 11 dez. 2023a. + +Design Gurus. Grokking Data Structures for Coding Interviews: Issues with Hash Tables. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/64b7b84daab5a6129791002b](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/64b7b84daab5a6129791002b)>. Acesso em: 11 dez. 2023a. + +RAMACHANDRAN, Ranjith. _How HashMap works in Java? With Animation!! whats new in java8 tutorial_. \[Videoaula]. YouTube, 2015. Disponível em: [https://www.youtube.com/watch?v=c3RVW3KGIIE](https://www.youtube.com/watch?v=c3RVW3KGIIE). Acesso em: 29 dez. 2023. diff --git a/Data-Structures/queue.md b/Data-Structures/queue.md new file mode 100644 index 0000000..84d3d74 --- /dev/null +++ b/Data-Structures/queue.md @@ -0,0 +1,579 @@ +# Queue + +* A queue in computer science is a type of data structure where the element that enters first is the one that gets accessed first. +* Basic Terminology + * **Enqueue:** when we add an element at the end. + * **Dequeue: R**emoving an element from the front of the Queue. + * **Front:** This is the start of the Queue, where the first element resides. + * **Rear:** This is the end of the Queue, where the last element is placed. + + + +### Types of Queues + +1. **Simple Queue (FIFO)**: In a simple queue, elements are inserted at the rear and removed from the front, adhering to the First-In-First-Out (FIFO) principle. +2. **Deque (Double Ended Queue)**: A deque allows for the addition or removal of elements from both ends of the queue. It provides flexibility in managing elements at either the front or rear. +3. **Circular Queue**: In a circular queue, the last element points to the first, creating a loop. This structure is useful for scenarios where elements need to cycle back to the beginning. +4. **Priority Queue**: A priority queue assigns varying levels of importance to its elements. Some elements are considered more critical and are given priority over others in the queue. + 1. A BST can be used to maintain elements in sorted order. + 2. A HEAP can be used to figure out here an element must be inserted. +5. **Affinity Queue**: In an affinity queue, each element possesses an affinity. Elements with the same affinity are placed together, while those without matching affinities are positioned at the rear of the queue. + +

Font: Design Gurus, 2023a

+ + + +### Simple Queue - Operations + +#### **Enqueue Operation**: + +* The enqueue operation involves adding an element to the **rear** of the queue. +* Prior to adding a new item, it is essential to verify whether the queue is already at full capacity. If the queue is full, we encounter a situation known as **queue overflow**. + +#### **Dequeue Operation**: + +* The dequeue operation focuses on removing an element from the **front** of the queue. +* Before removing an item, it is necessary to check whether there are any items available for removal. +* After removing the item, the front pointer is adjusted to indicate the next item in the queue. + +#### Queue Time Complexity Operations Summary + +

Font: Design Gurus, 2023a

+ + + +### Simple Queue - Implementation + +#### Java Queue Native Implementation + +* Java java.util.Queue (Interface) +* [AbstractQueue](https://docs.oracle.com/javase/8/docs/api/java/util/AbstractQueue.html), [ArrayBlockingQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ArrayBlockingQueue.html), [ArrayDeque](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayDeque.html), [ConcurrentLinkedDeque](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentLinkedDeque.html), [ConcurrentLinkedQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html), [DelayQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/DelayQueue.html), [LinkedBlockingDeque](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/LinkedBlockingDeque.html), [LinkedBlockingQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/LinkedBlockingQueue.html), [LinkedList](https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html), [LinkedTransferQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/LinkedTransferQueue.html), [PriorityBlockingQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/PriorityBlockingQueue.html), [PriorityQueue](https://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html), [SynchronousQueue](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/SynchronousQueue.html). + +#### Queue Implemented using Java + +```java +class Queue { + private Node front, rear; + private int size; + + // Node class for storing data and the reference to the next node + private static class Node { + T data; + Node next; + + Node(T data) { + this.data = data; + this.next = null; + } + } + + public Queue() { + front = rear = null; + size = 0; + } + + // Add an element to the queue + public void enqueue(T data) { + Node newNode = new Node<>(data); + if (rear == null) { + front = rear = newNode; + } else { + rear.next = newNode; + rear = newNode; + } + size++; + } + + // Remove an element from the queue + public T dequeue() { + if (front == null) { + return null; + } + T data = front.data; + front = front.next; + if (front == null) { + rear = null; + } + size--; + return data; + } + + // Check the front element of the queue + public T peek() { + if (front == null) { + return null; + } + return front.data; + } + + // Check if the queue is empty + public boolean isEmpty() { + return size == 0; + } + + // Get the size of the queue + public int size() { + return size; + } +} + +// Example usage +public class Solution { + public static void main(String[] args) { + Queue queue = new Queue<>(); + + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + System.out.println("Front element: " + queue.peek()); + System.out.println("Dequeued: " + queue.dequeue()); + System.out.println("Front element: " + queue.peek()); + System.out.println("Queue size: " + queue.size()); + } +} + +``` + + + +### Circular Queue - Operations + +* In a Circular Queue, the last element points back to the first element making a circular link. +* The operations on a Circular Queue are similar to those of a Simple Queue – Enqueue, Dequeue, Peek, and IsEmpty. +* The **enqueue** operation (Educative.io, 2023a): + + * Check whether the queue is full. A queue is full when the `front` is next to the `rear`. For example, with a queue of size 6, if `front` is 0 and `rear` is 5, or if `front` is 2 and `rear` is 1, it means that the queue is full. + + + +

Font: Educative.io, 2023a

+* The dequeue operation (Educative.io, 2023a): + * If it is empty, then it will display `"Queue is empty"`. + * If the queue is not empty, then check if the queue has only one value (i.e., `front` == `rear`). + * If it does have only one value, set both `rear` and `front` to `-1`; + * if it does not, check if `front` is the last index of the queue and, if so, set `front` to `0`; otherwise, **increment** `front`. + + + +### Circular Queue - Implementation + +#### Design Gurus Implementation (Design Gurus, 2023a) + +* When `FRONT > 0` use this canculation to verify if the `REAR` is imediatly behind the `FRONT` `(rear == (front - 1) % (size - 1)`, if it is true, them the queue is FULL; + +```java +class CircularQueue { + private int[] queue; + private int size; + private int front; + private int rear; + + // Constructor to initialize the queue + public CircularQueue(int size) { + this.size = size; + queue = new int[this.size]; + front = -1; + rear = -1; + } + + // Function to insert an element in the queue + public void enqueue(int element) { + if ((front == 0 && rear == size - 1) || (rear == (front - 1) % (size - 1))) { + System.out.println("Queue is Full"); + } else if (front == -1) { // Insert First Element + front = 0; + rear = 0; + queue[rear] = element; + } else if (rear == size - 1 && front != 0) { + rear = 0; + queue[rear] = element; + } else { + rear = (rear + 1); + queue[rear] = element; + } + } + + // Function to delete an element from the queue + public int dequeue() { + if (front == -1) { + System.out.println("Queue is Empty"); + return Integer.MIN_VALUE; + } + + int data = queue[front]; + queue[front] = -1; + if (front == rear) { + front = -1; + rear = -1; + } else if (front == size - 1) { + front = 0; + } else { + front++; + } + return data; + } + + // Function to display the elements of the queue + public void displayQueue() { + if (front == -1) { + System.out.println("Queue is Empty"); + return; + } + System.out.println("Elements in the Circular Queue are: "); + if (rear >= front) { + for (int i = front; i <= rear; i++) { + System.out.print(queue[i] + " "); + } + } else { + for (int i = front; i < size; i++) { + System.out.print(queue[i] + " "); + } + for (int i = 0; i <= rear; i++) { + System.out.print(queue[i] + " "); + } + } + System.out.println(); + } +} + +public class Solution { + // Main method to test the CircularQueue class + public static void main(String[] args) { + CircularQueue q = new CircularQueue(5); + + // Inserting elements in the queue + q.enqueue(14); + q.enqueue(22); + q.enqueue(13); + q.enqueue(-6); + + // Display elements present in the queue + q.displayQueue(); + + // Deleting elements from the queue + System.out.println("Deleted value = " + q.dequeue()); + System.out.println("Deleted value = " + q.dequeue()); + + q.displayQueue(); + + q.enqueue(9); + q.enqueue(20); + q.enqueue(5); + + q.displayQueue(); + + q.enqueue(20); + } +} + +``` + + + +#### :bulb:Programiz Implementation (Programiz, 2023a) + +* Circularly increase the `REAR` index by 1 (i.e. if the rear reaches the end, next it would be at the start of the queue) + * `rear = (rear + 1) % SIZE` + +```java +// Circular Queue implementation in Java + +public class CQueue { + int SIZE = 5; // Size of Circular Queue + int front, rear; + int items[] = new int[SIZE]; + + CQueue() { + front = -1; + rear = -1; + } + + // Check if the queue is full + boolean isFull() { + if (front == 0 && rear == SIZE - 1) { + return true; + } + if (front == rear + 1) { + return true; + } + return false; + } + + // Check if the queue is empty + boolean isEmpty() { + if (front == -1) + return true; + else + return false; + } + + // Adding an element + void enQueue(int element) { + if (isFull()) { + System.out.println("Queue is full"); + } else { + if (front == -1) + front = 0; + rear = (rear + 1) % SIZE; + items[rear] = element; + System.out.println("Inserted " + element); + } + } + + // Removing an element + int deQueue() { + int element; + if (isEmpty()) { + System.out.println("Queue is empty"); + return (-1); + } else { + element = items[front]; + if (front == rear) { + front = -1; + rear = -1; + } /* Q has only one element, so we reset the queue after deleting it. */ + else { + front = (front + 1) % SIZE; + } + return (element); + } + } + + void display() { + /* Function to display status of Circular Queue */ + int i; + if (isEmpty()) { + System.out.println("Empty Queue"); + } else { + System.out.println("Front -> " + front); + System.out.println("Items -> "); + for (i = front; i != rear; i = (i + 1) % SIZE) + System.out.print(items[i] + " "); + System.out.println(items[i]); + System.out.println("Rear -> " + rear); + } + } + + public static void main(String[] args) { + + CQueue q = new CQueue(); + + // Fails because front = -1 + q.deQueue(); + + q.enQueue(1); + q.enQueue(2); + q.enQueue(3); + q.enQueue(4); + q.enQueue(5); + + // Fails to enqueue because front == 0 && rear == SIZE - 1 + q.enQueue(6); + + q.display(); + + int elem = q.deQueue(); + + if (elem != -1) { + System.out.println("Deleted Element is " + elem); + } + q.display(); + + q.enQueue(7); + + q.display(); + + // Fails to enqueue because front == rear + 1 + q.enQueue(8); + } + +} +``` + + + +### Deque - Operations + +* **Deque (Double Ended Queue)**, also known as a double-ended queue, is a specialized type of queue that allows for the insertion and removal of elements from both the front and the rear. +* Unlike a standard queue that adheres strictly to the First-In-First-Out (FIFO) rule, a deque provides greater flexibility in managing elements by allowing operations at both ends. + + + +### Deque - Implementation + +#### Programiz Implementation (Programiz, 2023b) + +* insertRear: + * If `REAR == size - 1`, reinitialise `REAR = 0` (first index). +* insertFront + * If `FRONT < 1`, reinitialise `FRONT = size - 1` (last index). + +```java +// Deque implementation in Java + +class Deque { + static final int MAX = 100; + int arr[]; + int front; + int rear; + int size; + + public Deque(int size) { + arr = new int[MAX]; + front = -1; + rear = 0; + this.size = size; + } + + boolean isFull() { + return ((front == 0 && rear == size - 1) || front == rear + 1); + } + + boolean isEmpty() { + return (front == -1); + } + + void insertFront(int key) { + if (isFull()) { + System.out.println("Overflow"); + return; + } + + if (front == -1) { + front = 0; + rear = 0; + } + + // If front < 1, reinitialize front = size-1 (last index) + else if (front == 0) + front = size - 1; + + else + front = front - 1; + + arr[front] = key; + } + + void insertRear(int key) { + if (isFull()) { + System.out.println(" Overflow "); + return; + } + + if (front == -1) { + front = 0; + rear = 0; + } + + // If rear == size - 1, reinitialize rear = 0 (first index) + else if (rear == size - 1) + rear = 0; + + else + rear = rear + 1; + + arr[rear] = key; + } + + void deleteFront() { + if (isEmpty()) { + System.out.println("Queue Underflow\n"); + return; + } + + // Deque has only one element + if (front == rear) { + front = -1; + rear = -1; + } else if (front == size - 1) + front = 0; + + else + front = front + 1; + } + + void deleteRear() { + if (isEmpty()) { + System.out.println(" Underflow"); + return; + } + + if (front == rear) { + front = -1; + rear = -1; + } else if (rear == 0) + rear = size - 1; + else + rear = rear - 1; + } + + int getFront() { + if (isEmpty()) { + System.out.println(" Underflow"); + return -1; + } + return arr[front]; + } + + int getRear() { + if (isEmpty() || rear < 0) { + System.out.println(" Underflow\n"); + return -1; + } + return arr[rear]; + } + + public static void main(String[] args) { + + Deque dq = new Deque(4); + + System.out.println("Insert element at rear end : 12 "); + dq.insertrear(12); + + System.out.println("insert element at rear end : 14 "); + dq.insertrear(14); + + System.out.println("get rear element : " + dq.getRear()); + + dq.deleterear(); + System.out.println("After delete rear element new rear become : " + dq.getRear()); + + System.out.println("inserting element at front end"); + dq.insertfront(13); + + System.out.println("get front element: " + dq.getFront()); + + dq.deletefront(); + + System.out.println("After delete front element new front become : " + +dq.getFront()); + + } +} +``` + + + +### **Queues in Programming** + +In programming and data structures, queues serve diverse purposes (Design Gurus, 2023a): + +1. **Breadth-First Search (BFS)**: + * Queues play a pivotal role in the BFS algorithm, facilitating the systematic traversal of nodes within a tree or graph. + * The process starts from a designated node (often the tree’s root or any graph node) and systematically explores neighboring nodes at the current depth level. Only after exhaustively examining the current depth level does the algorithm proceed to nodes at subsequent depth levels. +2. **Caching**: + * Certain caching strategies, specifically those adhering to the FIFO principle, leverage queues. + * In FIFO caching, the oldest item is evicted when the cache reaches its capacity, making room for the insertion of a new item. +3. :warning: :bulb: **Asynchronous Data Transfer**: + * Queues find application in scenarios involving **asynchronous** data transfer between two processes. + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Queue. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6491e0d6cc1ee5e292d494c7](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6491e0d6cc1ee5e292d494c7)>. Acesso em: 11 dez. 2023a. + +Educative.io. How to implement a circular queue in C++. Educative.io, \[s.d]. Disponível em: <[https://www.educative.io/answers/how-to-implement-a-circular-queue-in-cpp](https://www.educative.io/answers/how-to-implement-a-circular-queue-in-cpp)>. Acesso em: 11 dez. 2023a. + +Programiz. Circular Queue Data Structure. Programiz, \[s.d]. Disponível em: <[https://www.programiz.com/dsa/circular-queue](https://www.programiz.com/dsa/circular-queue)>. Acesso em: 11 dez. 2023a. + diff --git a/Data-Structures/stack.md b/Data-Structures/stack.md new file mode 100644 index 0000000..5f601ee --- /dev/null +++ b/Data-Structures/stack.md @@ -0,0 +1,230 @@ +# Stack + +* In the world of data structures, a stack is a linear data structure that follows a particular order of operation. This order can either be **Last In First Out (LIFO)** or **First In Last Out (FILO)**. +* **Real-world Examples of Stacks:** + * **Web Browser History**: Whenever a new webpage is visited, it is added to the top of the history stack. When the back button is pressed, pages are “popped” off the top of the stack. + * **Undo Function in Software Applications**: In software applications, a stack is used to remember actions. The most recent action is placed on top and will be the first one to be undone. + + + +### LIFO + +Stacks in data structures operate on the Last-In, First-Out (LIFO) principle. This means that the last item added to the stack is the first one that gets taken out. + + + +### Key Operations + +1. **Push**: An element is added to the stack. The element is always added to the top. +2. **Pop**: An element is removed from the stack. The element removed is always from the top. +3. **Peek** or **Top**: This operation allows us to see the element on the top of the stack without removing it. +4. **IsEmpty**: This operation checks if the stack is empty. + + + +#### Stack Time Complexity Operations Summary + +

Font: Design Gurus, 2023a

+ + + +### Stack Implementation and Usage in Programming + +* **Stack implementation in programming** can be achieved in various ways. **Two common methods** involve using an array or a linked list. Additionally, depending on the programming language being used, there **might be built-in functions** that facilitate stack creation. + +#### **Application of Stack** + +* **Expression evaluation and syntax parsing**: Stacks are employed by compilers and parsers to evaluate expressions and verify syntax. +* **Backtracking**: Whenever an algorithm requires backtracking (e.g., in maze problems), a stack serves as a useful tool for remembering previous steps. +* **Function calls**: Each time a function is invoked, the computer must “remember” the location it needs to return to after executing the function. This memory is maintained on a call stack. +* **Memory management**: Stacks play a crucial role in memory allocation and deallocation. +* **Undo Mechanism in Software Applications:** In software applications, the ‘undo’ feature relies on stacks: actions are pushed onto a stack, and when ‘undo’ is triggered, the most recent action is popped and reversed, providing an elegant solution to a common problem. + + + +#### Backtracking + +**Backtracking algorithms** address problems by **experimenting with solutions** and **reverting them** if they **do not lead to a solution**. This approach is **commonly employed** in puzzles such as **Sudoku**, the **Eight Queens problem**, and the **Knight’s Tour problem**. + +In these scenarios, **stacks** are **utilized** to **store the intermediate stages** of the problem. When an attempted solution **does not succeed**, the algorithm can **“pop” back** to a **previous state** and **explore an alternative path**. It’s akin to having a **“save game” feature** when **tackling a challenging puzzle** + + + +#### DFS + +**Depth-First Search (DFS)** is a graph algorithm that **employs stacks**. It explores a graph by **visiting a node** and **recursively investigating** all its unvisited neighbors. The algorithm **relies on a stack** to **keep track of which nodes** to visit next **after completing a path**. + +By **“pushing” unvisited nodes** onto the stack and **“popping” them** once visited, DFS **systematically explores** every node in the graph. This method **finds application** in **network routing**, **AI behavior in games**, and **detecting cycles** within a graph. + + + +### Stack Common Errors/Exceptions (**Stack overflow and Stack Underflow)** + +**Stack overflow and underflow** are two situations that **can be encountered** when working with stacks. **Stack overflow** **occurs** when an attempt is made to push an element onto a stack that is already full, while **stack underflow** **happens** when an attempt is made to pop an element from an empty stack. + + + +### Java Stack + +#### Java Util Stack + +```java +import java.util.Stack; +import java.util.EmptyStackException; + +public class MyStack { + // A Stack object to store the elements. + private Stack stack = new Stack<>(); + + // Method to check if the stack is empty. + public boolean isEmpty() { + return stack.empty(); // Returns true if the stack is empty, false otherwise. + } + + // Method to add an element to the top of the stack. + public void push(T data) { + stack.push(data); + } + + // Method to remove and return the top element of the stack. + public T pop() { + if (isEmpty()) { + throw new EmptyStackException(); // Throws an exception if the stack is empty. + } + return stack.pop(); // Returns and removes the top element of the stack. + } + + // Method to return the top element of the stack without removing it. + public T peek() { + if (isEmpty()) { + throw new EmptyStackException(); // Throws an exception if the stack is empty. + } + return stack.peek(); // Returns the top element of the stack without removing it. + } +} +``` + + + +#### Java Stack Implementation (Array) + +```java +import java.util.EmptyStackException; + +public class Stack { + private Object[] stack; // An array to store the elements of the stack + private int top; // An integer to keep track of the top element's index + + // Constructor to initialize the stack with a specified size + public Stack(int size) { + stack = new Object[size]; // Create a new array of objects with the given size + top = -1; // Initialize the top index to -1, indicating an empty stack + } + + // Method to push an item onto the stack + public void push(T item) { + if (top == stack.length - 1) { + throw new IndexOutOfBoundsException("Stack is full"); // Check if the stack is full and throw an exception if it is + } + stack[++top] = item; // Increment the top index and add the item to the stack + } + + // Method to pop and remove the top item from the stack + public T pop() { + if (isEmpty()) { + throw new EmptyStackException(); // Check if the stack is empty and throw an exception if it is + } + T item = (T) stack[top]; // Retrieve the top item from the stack + stack[top--] = null; // Set the top element to null and decrement the top index + return item; // Return the removed item + } + + // Method to peek at the top item without removing it + public T peek() { + if (isEmpty()) { + throw new EmptyStackException(); // Check if the stack is empty and throw an exception if it is + } + return (T) stack[top]; // Return the top item without removing it + } + + // Method to check if the stack is empty + public boolean isEmpty() { + return top == -1; // Return true if the top index is -1, indicating an empty stack + } +} + +``` + + + +#### Java Stack Implementation (Linked List) + +```java +import java.util.EmptyStackException; + +public class Stack { + // Private inner class representing a Node in the stack + private static class Node { + private T data; // Data stored in the node + private Node next; // Reference to the next node in the stack + + // Constructor to create a new node with the given data + private Node(T data) { + this.data = data; + } + } + + private Node top; // Reference to the top node of the stack + + // Pop operation: Removes and returns the top element of the stack + public T pop() { + // Check if the stack is empty + if (top == null) { + throw new EmptyStackException(); // Throw an exception if it's empty + } + T item = top.data; // Get the data from the top node + top = top.next; // Move the top reference to the next node + return item; // Return the removed item + } + + // Push operation: Pushes a new item onto the top of the stack + public void push(T item) { + Node t = new Node(item); // Create a new node with the given data + t.next = top; // Set the new node's next reference to the current top + top = t; // Update the top reference to the new node + } + + // Peek operation: Returns the top element of the stack without removing it + public T peek() { + // Check if the stack is empty + if (top == null) { + throw new EmptyStackException(); // Throw an exception if it's empty + } + return top.data; // Return the data of the top node + } + + // Check if the stack is empty + public boolean isEmpty() { + return top == null; + } +} + +``` + + + +### Insight Problem Solving with Stack + +* Manipulação de elementos levando em consideração os elementos adjacentes. + * [https://leetcode.com/submissions/detail/1119872765/](https://leetcode.com/submissions/detail/1119872765/) + * [https://leetcode.com/submissions/detail/1119832765/](https://leetcode.com/submissions/detail/1119832765/) + * [https://leetcode.com/submissions/detail/1119814445/](https://leetcode.com/submissions/detail/1119814445/) +* TBD + * [https://leetcode.com/submissions/detail/1117482038/](https://leetcode.com/submissions/detail/1117482038/) + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Stack. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/647fd18147afdb7576809cc7](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/647fd18147afdb7576809cc7)>. Acesso em: 11 dez. 2023a. + diff --git a/Data-Structures/tree/README.md b/Data-Structures/tree/README.md new file mode 100644 index 0000000..5440f6b --- /dev/null +++ b/Data-Structures/tree/README.md @@ -0,0 +1,2 @@ +# Tree + diff --git a/Data-Structures/tree/binary-search-tree-bts.md b/Data-Structures/tree/binary-search-tree-bts.md new file mode 100644 index 0000000..8d6aa49 --- /dev/null +++ b/Data-Structures/tree/binary-search-tree-bts.md @@ -0,0 +1,304 @@ +# Binary Search Tree (BTS) + +A Binary Search Tree (BST) is a type of binary tree where each node can have a maximum of two children, known as the left and right child. The unique characteristic of a BST is that for any particular node, the values of all nodes in its left subtree are less than or equal to the node's value, while the values of all nodes in its right subtree are greater than the node's value (Design Gurus, 2023a). + + + +#### Properties and Application of BST + +* **Quick Searches**: BSTs provide fast searching capabilities with an average **Time Complexity** of `O(log n)` for balanced trees. This makes them suitable for applications that require quick data retrieval based on a key, such as database indexing and dictionary implementations. +* **Ordered Data**: BSTs keep data in order. They are useful when you need to keep things sorted or get them in a certain order. +* **BSTs in Databases**: Databases leverage BSTs to create indexes, which speed up data retrieval based on specific fields. This allows databases to efficiently manage large datasets and complex queries. +* **BSTs in File Systems**: File systems use BSTs to organize directory structures. This aligns well with the hierarchical structure of directories, leading to efficient file retrieval. + + + +* A binary tree with height `h` contains at most: . + * This is where we'll do a simple induction. A tree with only 1 layer has only 1 node. A tree of 2 layers has 1+2 nodes. 3 layers 1+2+4 nodes etc. The pattern is clear: A tree with h layers has exactly: `2^h-1`, +* In other word, a binary tree with `N` nodes and height `h`: +* That is: +* The number of nodes in the tree doubles, the depth increases by 1. +* See this [Stackoverflow](https://stackoverflow.com/questions/14426790/why-lookup-in-a-binary-search-tree-is-ologn). + + + +### Traversing a Binary Search Tree (BST) + +

Font: RAI, 2023

+ + + +#### In order Traversal + +* left subtree -> the current node -> right subtree. +* results in the elements being visited in ascending order. +* > Traversing in order in BST is same as traversing a sorted array. + +```java +private void inOrderHelper(Node node) { + if (node != null) { + inOrderHelper(node.left); + System.out.print(node.data + " "); + inOrderHelper(node.right); + } +} + +public void inOrder() { + inOrderHelper(root); + System.out.println(); +} +``` + + + +#### Pre-order Traversal + +* current node -> the left subtree -> right subtree. + +```java +private void preOrderHelper(Node node) { + if (node != null) { + System.out.print(node.data + " "); + preOrderHelper(node.left); + preOrderHelper(node.right); + } +} + +public void preOrder() { + preOrderHelper(root); + System.out.println(); +} +``` + + + +#### Post-order Traversal + +* the left subtree -> the right subtree -> current node. + +```java +private void postOrderHelper(Node node) { + if (node != null) { + postOrderHelper(node.left); + postOrderHelper(node.right); + System.out.print(node.data + " "); + } +} + +public void postOrder() { + postOrderHelper(root); + System.out.println(); +} +``` + + + +### BST Implementation + +#### Node Class of a BST - Implementation + +```java +class Node { + public T data; + public Node left; + public Node right; + + public Node(T value) { + data = value; + left = null; + right = null; + } +} +``` + + + +#### Insert Node Operation BST - Implementation + +```java +public void insert(T value) { + Node newNode = new Node<>(value); + + if (root == null) { + root = newNode; + } else { + Node current = root; + Node parent = null; + + while (current != null) { + parent = current; + // We must ensure that the left subtree contains nodes with values less than or equal to the current node's value, and the right subtree contains nodes with values greater than the current node's value. + if (value.compareTo(current.data) < 0) { + current = current.left; + } else { + current = current.right; + } + } + + if (value.compareTo(parent.data) < 0) { + parent.left = newNode; + } else { + parent.right = newNode; + } + } +} +``` + + + +#### Delete Node Operation BST - Implementation + +```java +// It starts from the given node and traverses the left children until it reaches the leftmost node, which contains the smallest value in the subtree. It returns the pointer to this minimum node +private Node findMin(Node node) { + if (node.left == null) { + return node; + } + return findMin(node.left); +} + +private Node deleteNode(Node root, T value) { + if (root == null) { + return root; + } + + if (value.compareTo(root.data) < 0) { + root.left = deleteNode(root.left, value); + } else if (value.compareTo(root.data) > 0) { + root.right = deleteNode(root.right, value); + } else { + // The node has no children or only one child (left or right). In this case, the function simply removes the node and links its parent to its child, if any. + if (root.left == null) { + return root.right; + } else if (root.right == null) { + return root.left; + } + + // The node has two children. In this case, the function finds the inorder successor of the node (the minimum node in its right subtree). The value of the inorder successor replaces the value of the node to be deleted, and the function is then recursively called to delete the inorder successor node. + Node temp = findMin(root.right); + root.data = temp.data; + root.right = deleteNode(root.right, temp.data); + } + return root; +} + +public void deleteMethod(T value) { + root = deleteNode(root, value); +} +``` + + + +#### Searching Node Operation BST - Implementation + +```java +public boolean search(T value) { + Node current = root; + while (current != null) { + if (value.compareTo(current.data) == 0) { + return true; + } else if (value.compareTo(current.data) < 0) { + current = current.left; + } else { + current = current.right; + } + } + return false; +} +``` + +### Time and Space Complexity of Binary Search Trees (BST) + +#### Best Case Time Complexity for Searching - `O(log n)` + +* The best-case time complexity for searching in a BST occurs when the tree is balanced. +* In a balanced BST, each level approximately halves the search space. +* Requires `O(log n)` operations to traverse through all nodes in the BST. + + + +#### Worst Case Time Complexity for Searching - `O(n)` (for unbalanced trees) + +* The worst-case time complexity for searching occurs when the tree is completely unbalanced, resembling a linked list. In this scenario, each node has only one child, and the search becomes linear, requiring `O(n)` operations to traverse through all nodes in the BST. + + + +#### Best Case Time Complexity for Insertion/Deletion - `O(log n)` + +* In a balanced BST, each level approximately halves the search space. +* As a result, the time complexity for searching is logarithmic `O(log n)` with respect to the number of nodes (n) in the BST. + + + +#### Worst Case Time Complexity for Insertion/Deletion - `O(n)` (for unbalanced trees) + +* The worst-case time complexity for searching in a BST occurs when the tree is completely unbalanced ("linked list"). +* In this scenario, each node has only one child, and the search becomes linear, requiring `O(n)` operations to traverse through all nodes in the BST. + + + +### Issues with BSTs + +1. **Unbalanced BSTs**: + * Unbalanced BSTs occur when elements are inserted in a specific order, leading to poor tree structure. + * If elements are inserted in a **sorted or nearly sorted order**, the BST can degenerate into a **linked list**. + * Unbalanced BSTs result in **poor time complexities** for search, insertion, and deletion operations, approaching **linear time (`O(n)`)** instead of the optimal **logarithmic time (`O(log n)`)**. +2. **Degenerate Trees**: + * Degenerate trees are extreme cases of unbalanced BSTs where each node has only one child. + * These trees essentially form a **linked list**, resulting in **very poor time complexities** for all operations. + * The advantages of using BSTs are **negated** in such cases. +3. **Performance Issues**: + * Unbalanced and degenerate BSTs lead to significantly **degraded performance** for common operations. + * In the worst-case scenario (when the tree is degenerate), operations can take **linear time (`O(n)`)**. + * This undermines the primary benefit of using a BST. +4. **Complex Balancing**: + * Ensuring a BST remains balanced after insertion and deletion requires **complex balancing algorithms**. + * Self-balancing BSTs like **AVL trees** and **Red-Black trees** exist but add **overhead and complexity** to the code. +5. **Lack of Unique Keys**: + * BSTs generally **do not support duplicate keys**. + * Behavior varies when attempting to insert a duplicate key: + * some implementations **overwrite** the existing value, + * while others **reject** the insertion. +6. **Memory Overhead**: + * Each node in a BST requires additional memory for **storing pointers** to the left and right children. + * Memory overhead can be significant for **large datasets**, especially if the tree is poorly balanced. +7. **Dynamic Datasets**: + * BSTs are **not well-suited** for datasets that frequently change in size. + * **Insertions and deletions** can lead to **imbalanced trees**, necessitating additional **balancing operations**. + * These operations can be **computationally expensive**. +8. **Search Performance for Equal Keys**: + + * While BSTs provide efficient search times for **unique keys**, searching for the **next greater or lesser element** for equal keys requires **additional operations**. + * This may result in **less efficient** search performance. + + + +
+ +Expanding "8. searching for the next greater or lesser element for equal keys requires additional operations" + +When we talk about **Binary Search Trees (BSTs)**, each node has a key associated with it. In the case of equal keys (where multiple nodes have the same key value), searching for the **next greater or lesser element** becomes a bit more intricate. + +1. **Next Greater Element**: + * Suppose we want to find the next greater element after a given key. + * If the key is unique (i.e., no duplicate keys), we can efficiently traverse the tree by comparing the key values. + * However, when there are **equal keys**, we need to consider additional factors: + * If the current node has equal keys, we must explore its **right subtree** to find the next greater element. + * If the current node has distinct keys, we can directly move to the **right child** of the current node. +2. **Next Lesser Element**: + * Similarly, finding the next lesser element involves similar considerations. + * If the key is unique, we can traverse the tree by comparing key values. + * For equal keys: + * If the current node has equal keys, we explore its **left subtree** to find the next lesser element. + * If the current node has distinct keys, we move to the **left child** of the current node. + +
+ +\ + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Queue. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6491e0d6cc1ee5e292d494c7](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6491e0d6cc1ee5e292d494c7)>. Acesso em: 11 dez. 2023a. + +RAI, **Vartika.** Tree Traversal: Inorder, Preorder, Postorder, and Level-order. Interview Kickstart, 2023. Disponível em: <[https://www.interviewkickstart.com/learn/tree-traversals-inorder-preorder-and-postorder](https://www.interviewkickstart.com/learn/tree-traversals-inorder-preorder-and-postorder)>. Acesso em: 11 dez. 2023a. diff --git a/Data-Structures/tree/tree-introduction.md b/Data-Structures/tree/tree-introduction.md new file mode 100644 index 0000000..3b5ca2e --- /dev/null +++ b/Data-Structures/tree/tree-introduction.md @@ -0,0 +1,83 @@ +# Tree Introduction + +In the realms of computer science and data structures, trees are constituted by nodes that are interconnected by edges. The common usage of these structures is found in the representation of data and its hierarchical organization. + + + +> A tree is made up of **nodes** that are arranged in a hierarchical structure. At the top of the hierarchy is the **root** node, which acts as the **starting point**. All other **nodes are connected** through **edges**. The **nodes are grouped into levels**, and the **maximum level** of any node in the tree is referred to as the **depth**. +> +> \ +> \- Design Gurus, 2023a. + + + +### Fundamentals Concepts + +* Root Node: This is the uppermost node in the tree, serving as the origin point for the entire tree. It is also the starting point for any tree traversal operation. +* Nodes: These are the individual elements that make up the tree, including the root. Each node has a unique value and may be connected to child nodes. +* Parent Node: This is a node that has one or more nodes, known as child nodes, linked to it. + + Child Node: These are nodes that have a direct connection to a parent node. +* Sibling Nodes: These are nodes that have the same parent node. +* Ancestor Nodes: These are all the nodes that lie along the path from a given node up to the root node. +* Descendant Nodes: These are all the nodes that can be reached from a specific node, extending down to the leaf nodes. +* Leaf Node: These are the nodes in the tree that do not have any child nodes. +* Subtree: This is a smaller tree that exists within the main tree, composed of a node and all its descendant nodes. +* Tree Height: The height of a tree is the number of edges on the longest path from the root node to the leaf node (It represents the **depth** of the tree from the **root**). +* Node Depth: the depth of a specific node in the tree is the number of edges **from the root node to that particular node**. +* Levels in Trees: Levels in a tree are defined based on the distance from the root node. The root node is at level 0; its children are at level 1, and so on. + +

Font: Design Gurus, 2023a

+ + + +### Types of Tress + +#### Binary Trees + +* Binary trees are a type of tree where each node can have at most two children. + + + +#### Full Trees + +* In a full tree, every node has either zero children (leaf node) or two children. +* Also known as **proper binary trees**. + + + +#### Complete Tree + +* A complete tree is a binary tree in which all levels are filled, except possibly the last level. The last level must strictly be filled from left to right. +* **Properties:** + + * The number of nodes at depth **d** is $$2^d$$ . + * The height of a complete tree is $$log(n+1)$$ (where, `n` is the number of nodes). + + + +#### Balanced Tree + +* Balanced trees are binary trees where the difference in height between the left and right subtrees of any node in the tree is not more than 1. + +

Font: Geeks For Geeks, [s.d.]

+ + + +#### Multi-way Trees + +Unlike binary trees, multi-way trees allow nodes to have more than two children. + + + +### Binary Search Tree (BST) + +[binary-search-tree-bts.md](binary-search-tree-bts.md "mention") + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Queue. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6491e0d6cc1ee5e292d494c7](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6491e0d6cc1ee5e292d494c7)>. Acesso em: 11 dez. 2023a. + +Geeks For Geeks. Types of Binary Tree. Geeks For Geeks, \[s.d.]. Disponível em: <[https://www.geeksforgeeks.org/types-of-binary-tree](https://www.geeksforgeeks.org/types-of-binary-tree)>. Acesso em: 11 dez. 2023a. diff --git a/Data-Structures/trie-prefix-tree/README.md b/Data-Structures/trie-prefix-tree/README.md new file mode 100644 index 0000000..29e97ef --- /dev/null +++ b/Data-Structures/trie-prefix-tree/README.md @@ -0,0 +1,2 @@ +# Trie (Prefix Tree) + diff --git a/Data-Structures/trie-prefix-tree/trie-introduction.md b/Data-Structures/trie-prefix-tree/trie-introduction.md new file mode 100644 index 0000000..3e0f14a --- /dev/null +++ b/Data-Structures/trie-prefix-tree/trie-introduction.md @@ -0,0 +1,58 @@ +# Trie Introduction + +* A Trie, also known as a prefix tree, is a specialized tree-based **data structure used for efficient storage, searching, and retrieval of strings**. +* It is particularly useful when managing large collections of strings and **performing pattern-matching operations**. +* The Trie represents a set of strings: + * Each **node** in the tree corresponds to a **single character of a string.** + * The **path** from the root to a specific node represents the characters of a particular string. + * This characteristic allows Tries to effectively **share common prefixes** among strings, leading to efficient storage and retrieval. + + + +### Need for Trie Data Structure? + +Tries are commonly used in applications such as spell checking, autocomplete suggestions, and searching within dictionaries or databases. They outperform other data structures like binary search trees by minimizing search complexity in proportion to the length of the target string. + + + +### Tries Advantages + +* Fast pattern matching. +* Common prefix sharing for efficient memory utilisation. +* Efficient insertion and deletion operations. +* Flexibility in handling various alphabets. +* The ability to store additional information at nodes, such as word frequency. + +In comparison to binary search trees, Tries offer the advantage of search time linearly dependent on the length of the string being searched, resulting in optimized search operations, especially for large datasets. + + + +### Trie Properties + +* Every Trie has a s**ingle root node** that serves as the starting point for all stored strings. +* In a Trie, each node represents a string, and the path from the root to that node represents the entire string. +* The **edges** connecting nodes in a Trie correspond to **individual characters**, and traversing an edge adds a character to the string. +* Nodes in a Trie typically contain **hashmaps or arrays of pointers, where each position corresponds to a character**. +* Nodes also have a **flag** indicating if a string concludes at that node. +* Tries are primarily designed to handle lowercase English alphabets (a-z), with each node having 26 pointers representing the characters 'a' to 'z'. +* In a Trie, **tracing any path** from the **root** node to another **node** represents a **word** or a string, facilitating easy identification and retrieval of strings. + + + +#### TL;DR + +The properties of the Trie data structure include having a single root node, nodes symbolizing strings, edges representing characters, node structure with arrays or hashmaps of pointers, limitation to lowercase English alphabets, and the ability to identify and retrieve strings by tracing paths from the root node. + + + +### Trie Example + +

Font: Design Gurus, 2023a

+ +In the above Trie, `car` and `cat` shares the common prefix, and `apple` and `ant` shares the common prefix. + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Trie. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 21 jan. 2024. diff --git a/Data-Structures/trie-prefix-tree/trie-operations.md b/Data-Structures/trie-prefix-tree/trie-operations.md new file mode 100644 index 0000000..4efde9e --- /dev/null +++ b/Data-Structures/trie-prefix-tree/trie-operations.md @@ -0,0 +1,183 @@ +# Trie Operations + +### Trie Operations + +* delete +* insert +* search +* startWith + +### Trie + +```java +public class Trie { + public TrieNode root; + + public Trie() { + root = new TrieNode(""); + } + + private boolean delete(TrieNode current, String word, int index) { + // Base case: If the word's end is reached + if (index == word.length()) { + // If the word exists, unmark it and check if the node can be deleted + if (current.isEndOfWord) { + current.isEndOfWord = false; + // Check if all children are null + for (TrieNode child : current.children) { + if (child != null) false; // Return false if any child exists + } + return true; // Return true if all children are null + } + return false; + } + + char ch = word.charAt(index); + TrieNode node = current.children[ch - 'a']; + + if (node == null) false; // Word not found + + + boolean shouldDeleteChild = delete(node, word, index + 1); + + // If true is returned, delete the child reference of the current TrieNode + if (shouldDeleteChild) { + current.children[ch - 'a'] = null; + // Check if all children are null + for (TrieNode child : current.children) { + if (child != null) return false; // Return false if any child exists + } + return !current.isEndOfWord;// Return true if all children are null + } + + return false; + } + + // Function to delete a word from the Trie + public void deleteWord(String word) { + delete(root, word, 0); + } + + + // Function to insert a word into the Trie + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + int index = word.charAt(i) - 'a'; // Convert character to index + if (node.children[index] == null) + node.children[index] = new TrieNode(String.valueOf(word.charAt(i))); // Create a new node if it doesn't exist + node = node.children[index]; + } + node.isEndOfWord = true; // Mark the end of the word + } + + + // Function to search a word in the Trie + public boolean search(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + int index = word.charAt(i) - 'a'; + if (node.children[index] == null) return false; // Word not found + node = node.children[index]; + } + return node.isEndOfWord; // Return true if word exists, false otherwise + } + + + // Returns if there is any word in the trie that starts with the given prefix. + public boolean startsWith(String prefix) { + TrieNode node = root; + for (char c : prefix.toCharArray()) { + if (node.children[c - 'a'] == null) return false; + node = node.children[c - 'a']; + } + return true; + } + + public static void main(String[] args) { + var trie = new Trie(); + trie.insert("augusto"); + trie.insert("teste"); + var result = trie.search("teste"); + System.out.println(result); + } +} +``` + +### Trie (Map) + +```java + +import java.util.HashMap; +import java.util.Map; + +public class TrieHash { + TrieNodeHash root; + + public TrieHash() { + root = new TrieNodeHash(); + } + + + private boolean delete(String word) { + TrieNodeHash node = root; + for (Character currentChar : word.toCharArray()) { + if (!node.children.containsKey(currentChar)) + return true; + node = node.children.get(currentChar); + } + + if (node.isEndOfWord) { + node.isEndOfWord = false; + return true; + } + return false; + } + + + public void insert(String word) { + TrieNodeHash node = root; + for (Character currentChar : word.toCharArray()) { + if (!node.children.containsKey(currentChar)) { + node.children.put(currentChar, new TrieNodeHash()); + } + node = node.children.get(currentChar); + } + node.isEndOfWord = true; + } + + public boolean search(String word) { + TrieNodeHash node = root; + for (Character currentChar : word.toCharArray()) { + if (!node.children.containsKey(currentChar)) + return false; + node = node.children.get(currentChar); + } + return node.isEndOfWord; + } + + public boolean startsWith(String prefix) { + TrieNodeHash node = root; + for (char c : prefix.toCharArray()) { + if (!node.children.containsKey(c)) return false; + node = node.children.get(c); + } + return true; + } + + public static void main(String[] args) { + var trie = new TrieHash(); + trie.insert("ap"); + trie.insert("au"); + + System.out.println(trie.search("ap")); + System.out.println(trie.search("au")); + + System.out.println("result: " + trie.delete("ap")); + + System.out.println(trie.search("au")); + System.out.println(trie.search("ap")); + } +} + +``` diff --git a/Data-Structures/trie-prefix-tree/trie-representations.md b/Data-Structures/trie-prefix-tree/trie-representations.md new file mode 100644 index 0000000..14b41c4 --- /dev/null +++ b/Data-Structures/trie-prefix-tree/trie-representations.md @@ -0,0 +1,47 @@ +# Trie Representations + +* A Trie node encompasses an array or list, which serves as the children nodes. +* The size of this array or list is typically 26, a representation of the English lowercase alphabets (a-z). +* An additional feature of the Trie node is a boolean flag, termed as `isEndOfWord`. +* This flag serves to indicate whether the current node signifies the termination of a word in the Trie. + +

Font: Design Gurus, 2023

+ +```java +class TrieNode { + TrieNode[] children = new TrieNode[26]; // Children nodes + + boolean isEndOfWord; // Flag to represent the end of a word + + String letter; + + public TrieNode(String letter) { + isEndOfWord = false; + + for (int i = 0; i < 26; i++) + children[i] = null; + + this.letter = letter; + } +} +``` + + + +```java +public class TrieNodeHash { + public Map children; + public boolean isEndOfWord; // Flag to represent the end of a word + + public TrieNodeHash() { + this.isEndOfWord = false; + this.children = new TreeMap<>(); + } +} +``` + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Trie. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/650eb465d8da406a4d935d33)>. Acesso em: 21 jan. 2024. diff --git a/Extra-Materials-Design-Analysis-of-Algorithms/README.md b/Extra-Materials-Design-Analysis-of-Algorithms/README.md deleted file mode 100644 index 378ef95..0000000 --- a/Extra-Materials-Design-Analysis-of-Algorithms/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## Materials From Universities and Colleges - -- [University-of-Auckland - Algorithms & Data Structures](https://www.cs.auckland.ac.nz/courses/compsci220s1t/lectures/lecturenotes/GG-lectures/) - -- [Georgia Tech College - Design & Analysis of Algorithms](Georgia-Tech) \ No newline at end of file diff --git a/Extra-Materials-Design-Analysis-of-Algorithms/Time-complexity-and-BigOh-Notation/README.md b/Extra-Materials-Design-Analysis-of-Algorithms/Time-complexity-and-BigOh-Notation/README.md deleted file mode 100644 index d96a03f..0000000 --- a/Extra-Materials-Design-Analysis-of-Algorithms/Time-complexity-and-BigOh-Notation/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -- [University-of-Auckland - Algorithms & Data Structures](https://www.cs.auckland.ac.nz/courses/compsci220s1t/lectures/lecturenotes/GG-lectures/) - -- [Georgia Tech College - Design & Analysis of Algorithms](Georgia-Tech) - -- [Asymptotic notation Examples - CLRS](https://walkccc.github.io/CLRS/Chap03/3.1/) - -- [Big O notation: definition and examples](https://yourbasic.org/algorithms/big-o-notation-explained/) - diff --git a/README.md b/README.md new file mode 100644 index 0000000..4bf2867 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Algorithms + diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 0000000..1cd8bf1 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,118 @@ +# Table of contents + +* [Algorithms](README.md) + * [Big O Algorithm Complexity](algorithms/big-o-algorithm-complexity.md) + * [TEMP](algorithms/temp.md) + * [Backtracking](Algorithms/Backtracking/README.md) + * [Maze](algorithms/Backtracking/Maze.md) + * [Sorting Algorithms](algorithms/Sorting-Algorithms/README.md) + * [HeapSort](algorithms/Sorting-Algorithms/HeapSort.md) + * [Insertion Sort Algorithm](algorithms/Sorting-Algorithms/InsertionSort.md) + * [Mergesort Algorithm](algorithms/Sorting-Algorithms/MergeSort.md) + * [Greedy-Algorithms](algorithms/Greedy-Algorithms/README.md) + * [Greedy Algorithms Introduction](algorithms/Greedy-Algorithms/greedy-algorithms-introduction.md) + * [Dijkstra’s Algorithm](algorithms/Greedy-Algorithms/Dijkstras-Algorithm.md) + * [Job Sequencing Problem and Scheduling Priority Tasks](algorithms/Greedy-Algorithms/Job-Sequencing-Problem-and-Scheduling-Priority-Tasks.md) + * [Search-Algorithms](algorithms/Search-Algorithms/README.md) + * [BinarySearch](algorithms/Search-Algorithms/BinarySearch.md) + * [Depth First Search](algorithms/Search-Algorithms/Depth-First-Search.md) +* [Data-Structures](Data-Structures/README.md) + * [Array](Data-Structures/Array/README.md) + * [Matrix](data-structures/matrix.md) + * [Linked List](data-structures/linked-list.md) + * [Stack](Data-Structures/stack.md) + * [Queue](Data-Structures/queue.md) + * [Tree](Data-Structures/tree/README.md) + * [Tree Introduction](Data-Structures/tree/tree-introduction.md) + * [Binary Search Tree (BTS)](Data-Structures/tree/binary-search-tree-bts.md) + * [HashSets](data-structures/hashsets.md) + * [HashMap](Data-Structures/hashmap.md) + * [Heap](Data-Structures/Heap/README.md) + * [Graph](Data-Structures/graph/README.md) + * [Graph Introduction](Data-Structures/graph/graph-introduction.md) + * [Graph Representations](Data-Structures/graph/graph-representations.md) + * [Graph Operations](Data-Structures/graph/graph-operations.md) + * [Graph Traversal - Depth First Search (DFS)](Data-Structures/graph/graph-traversal-depth-first-search-dfs.md) + * [Graph Traversal - Breadth First Search (BFS)](Data-Structures/graph/graph-traversal-breadth-first-search-bfs.md) + * [Graph Knowledge to Solve Problems](Data-Structures/graph/graph-knowledge-to-solve-problems.md) + * [Trie (Prefix Tree)](Data-Structures/trie-prefix-tree/README.md) + * [Trie Introduction](Data-Structures/trie-prefix-tree/trie-introduction.md) + * [Trie Representations](Data-Structures/trie-prefix-tree/trie-representations.md) + * [Trie Operations](Data-Structures/trie-prefix-tree/trie-operations.md) +* [Materials From Universities and Colleges](extra-materials-design-analysis-of-algorithms/README.md) + * [Solving-and-Finding-Recurrences](extra-materials-design-analysis-of-algorithms/Solving-and-Finding-Recurrences.md) + * [Sorting-Searching-Hashing](extra-materials-design-analysis-of-algorithms/Sorting-Searching-Hashing.md) + * [Time-complexity-and-BigOh-Notation](extra-materials-design-analysis-of-algorithms/Time-complexity-and-BigOh-Notation.md) +* [LeetCode-Problems](leetcode-problems/README.md) + * [1342 Number of Steps to Reduce a Number to Zero](leetcode-problems/1342-Number-Steps-Reduce-Zero.md) + * [1480-Running-Sum-1D-Array](leetcode-problems/1480-Running-Sum-1D-Array.md) + * [1672. Richest Customer Wealth](leetcode-problems/1672-Richest-Customer-Wealth.md) + * [383 Ransom Note](leetcode-problems/383-Ransom-Note.md) + * [412 Fizz Buzz](leetcode-problems/412-FizzBuzz.md) + * [485 Max Consecutive Ones](leetcode-problems/485-Max-Consecutive-Ones.md) + * [876 Middle Linked List](leetcode-problems/876-Middle-Linked-List.md) + * [88. Merge Sorted Array](leetcode-problems/88-Merge-Sorted-Array.md) + * [977. Squares of a Sorted Array](leetcode-problems/977-Squares-Sorted-Array.md) +* [MONGAN-et-al-Programming-Int-Exposed-Coding-Exercises](mongan-et-al-programming-int-exposed-coding-exercises/README.md) + * [5. Chapter - Linked Lists](mongan-et-al-programming-int-exposed-coding-exercises/5-Linked-List.md) + * [6. Chapter - Trees and Graphs](mongan-et-al-programming-int-exposed-coding-exercises/6-Trees.md) +* [USP](usp/README.md) + * [Analysis-of-Algorithms-and-Data-Structures](usp/Analysis-of-Algorithms-and-Data-Structures/README.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200817.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 2020/08/24](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200824.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 2020/08/31](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200831.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 2020/09/07](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200907.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 2020/09/07](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200914.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 2020/09/21](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200921.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 20201005](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201005.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 2020/10/12](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201012.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 20201019](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201019.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 20201026](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201026.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 20201102](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201102.md) + * [SIN5013 - Análise de Algoritmos e Estruturas de Dados 20201102](usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201109.md) + * [resources](usp/Analysis-of-Algorithms-and-Data-Structures/resources/README.md) + * [Atividades](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/README.md) + * [Atividade\_10](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_10/README.md) + * [Problema - Jogo Gruntz](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_10/atividade\_10-q1.md) + * [Atividade\_11](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_11/README.md) + * [Atividade\_11](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_11/atividade\_11.md) + * [Atividade\_12](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_12/README.md) + * [Atividade\_12](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_12/atividade\_12.md) + * [Atividade\_13](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_13/README.md) + * [Atividade\_13-Q1](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_13/atividade\_13-q1.md) + * [Atividade\_14](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_14/README.md) + * [Atividade\_14-Q1](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_14/atividade\_14-q1.md) + * [Atividade\_2](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_2/README.md) + * [Answer Q2 and Q3](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_2/atividade\_2-q2-q3.md) + * [Atividade\_4](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_4/README.md) + * [Atividade 4](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_4/atividade\_4-q1-q2-q3-q4-q5.md) + * [Atividade\_8](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_8/README.md) + * [Q1](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_8/q1.md) + * [Atividade\_9](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_9/README.md) + * [Answer Q1](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade\_9/atividade\_9-q1.md) + * [P1](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/README.md) + * [Q2\_Q3\_Q4\_Q5\_Q6\_Q7](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/q2\_q3\_q4\_q5\_q6\_q7.md) + * [P2](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/README.md) + * [1245-Lost-Boots](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1245-Lost-Boots.md) + * [1790-Bridge-Detecting-Graph](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1790-Bridge-Detecting-Graph.md) + * [2026-Christmas-Tree-Backpack-Dynamic-Programming](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2026-Christmas-Tree-Backpack-Dynamic-Programming.md) + * [2115-Ekaterimburgo-Production](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2115-Ekaterimburgo-Production.md) + * [2237-Container](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2237-Container.md) + * [2720-Big-Gift-Sorting](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2720-Big-Gift-Sorting.md) + * [Canceled-1354-Big-Square-Backtracking](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-1354-Big-Square-Backtracking.md) + * [Canceled-3095-Bills-vs-MajinBoo-Greedy](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3095-Bills-vs-MajinBoo-Greedy.md) + * [Canceled-3107-Frog-Shortest-Path](usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3107-Frog-Shortest-Path.md) +* [Stanford-Algorithms-Specialization](stanford-algorithms-specialization/README.md) + * [DivideConquer-Sorting-Searching-Randomized-Algorithms](stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/README.md) + * [week-1](stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-1.md) + * [The Master Method](stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-2.md) + +## System Design + +* [Load Balancing](system-design/load-balancing.md) +* [API Gateway](system-design/api-gateway.md) +* [Key Characteristics of Distributed Systems](system-design/key-characteristics-of-distributed-systems/README.md) + * [Scalability](system-design/key-characteristics-of-distributed-systems/scalability.md) + * [Availability](system-design/key-characteristics-of-distributed-systems/availability.md) + * [Latency and Performance](system-design/key-characteristics-of-distributed-systems/latency-and-performance.md) + * [Page](system-design/key-characteristics-of-distributed-systems/page.md) diff --git a/Algorithms/Backtracking/Maze/README.md b/algorithms/Backtracking/Maze.md similarity index 100% rename from Algorithms/Backtracking/Maze/README.md rename to algorithms/Backtracking/Maze.md diff --git a/Algorithms/Greedy-Algorithms/Dijkstras-Algorithm/README.md b/algorithms/Greedy-Algorithms/Dijkstras-Algorithm.md similarity index 100% rename from Algorithms/Greedy-Algorithms/Dijkstras-Algorithm/README.md rename to algorithms/Greedy-Algorithms/Dijkstras-Algorithm.md diff --git a/Algorithms/Greedy-Algorithms/Job-Sequencing-Problem-and-Scheduling-Priority-Tasks/README.md b/algorithms/Greedy-Algorithms/Job-Sequencing-Problem-and-Scheduling-Priority-Tasks.md similarity index 100% rename from Algorithms/Greedy-Algorithms/Job-Sequencing-Problem-and-Scheduling-Priority-Tasks/README.md rename to algorithms/Greedy-Algorithms/Job-Sequencing-Problem-and-Scheduling-Priority-Tasks.md diff --git a/algorithms/Greedy-Algorithms/README.md b/algorithms/Greedy-Algorithms/README.md new file mode 100644 index 0000000..120397c --- /dev/null +++ b/algorithms/Greedy-Algorithms/README.md @@ -0,0 +1,2 @@ +# Greedy-Algorithms + diff --git a/algorithms/Greedy-Algorithms/greedy-algorithms-introduction.md b/algorithms/Greedy-Algorithms/greedy-algorithms-introduction.md new file mode 100644 index 0000000..7336fba --- /dev/null +++ b/algorithms/Greedy-Algorithms/greedy-algorithms-introduction.md @@ -0,0 +1,98 @@ +# Greedy Algorithms Introduction + +* **When we are using Greedy Algorithms?** + * A problem that requires a solution that uses the minimum amount/cost of a given resource or the maximum amount/cost of a given resource. + * In order words, greedy algorithms is applied to solve optimisation problems. +* Greedy approach focuses on immediate decisions. +* A **greedy algorithm** makes decisions at each step based on the **current best option**, without considering future consequences. +* A Greedy Algorithm is a problem-solving approach that constructs a solution step by step. It always selects the next step that provides the most immediate benefit (best "local" choice). It selects the best option at each stage. +* This kind of algorithm assumes that by choosing a local optimum solution will lead to the determination of a global optimum solution. + + + +### Video Explanation about Greedy Algorithm + +* [Abdul Bari - Greedy Method - Introduction](https://www.youtube.com/watch?v=ARvQcqJ\_-NY\&list=PLfFeAJ-vQopt\_S5XlayyvDFL\_mi2pGJE3) + + + +### When It is Suitable to Apply Greedy Algorithms? + +Two properties can indicate the use of greedy algorithms to solve a problem. + +* **Greedy Choice Property**: A global optimum is led to by the local optimal choices, meaning the best overall solution is led to by the best solution in each small step. +* **Optimal Substructure**: If the optimal solutions to its sub-problems are contained in an optimal solution to the entire problem, then a problem is said to have an optimal substructure. + + + +### **Characteristics of Greedy Method** + +Greedy algorithms share these characteristics: + +* Local optimisation: A choice that seems the best at that moment is made by the algorithm at every step, with the aim of achieving local. +* Irrevocability: Once a decision has been made, it is irrevocable and cannot be revisited. + + + +### Greedy Algorithm Solution Steps + +> 1. Candidate set. +> 2. Feasibility function. :star: +> 3. Objetive Function. +> 4. Solution Function. + +At each step, there will be a set of choices available in the **candidate set**. The **selection function** will then choose the most promising option. The **feasibility function** will evaluate the result to ensure that the candidate can contribute to a solution without violating any problem constraints. The **objective function** assesses the value or quality of the solution at each step. The s**olution function** then determines whether a complete solution has been achieved. + +```kotlin +// a = [a1, a2, a3, a4, a5] +// n = 5 // size of the list + +fun greedy(a: List<*>, n: Int): Result { + var solution: Resut? = null + for (i: int = 0; i < n; i++) { + var x = selectFun(a[i]) + if (feasibleFun(x)) { + solution = solution + x + } + } +} +``` + + + +### NP-Complete + +**Set-Covering Problem:** Given a set of elements (called the universe) and a collection of subsets whose union equals the universe, the set cover problem is to identify the smallest sub-collection of subsets whose union equals the universe. It is a known NP-complete problem and there is no polynomial time solution available for this problem. + +* > Suppose you’re starting a radio show. You want to reach listeners in all 50 states. You have to decide what stations to play on to reach all those listeners. It costs money to be on each station, so you’re trying to minimize the number of stations you play on. You have a list of stations. Each station covers a region, and there’s overlap. **How do you figure out the smallest set of stations you can play on to cover all 50 states?** + > + > + > + > \\- Grokking Algorithms: An Illustrated Guide for Programmers and Other Curious People + +**Traveling Salesperson Problem (TSP):** A salesperson is given a list of cities, and must determine the shortest route that allows them to visit each city once and return to their original location. It is an NP-complete problem in combinatorial optimization, important in theoretical computer science and operations research. + + + +> (1) Problem that requires calculations to determine the shortest route from point A to point B +> +> **VERSUS** +> +> (2) Problem that requires the discovery of the shortest path connecting multiple points. + +The problem (2) is a NP-complete problem. + +Determining whether a problem is NP-complete is not a straightforward task. These include: However, there are some indicators that can help identify such problems: + +* The algorithm performs efficiently with a small number of items, but its performance significantly decreases as the number of items increases. +* The phrase 'All combinations of X' typically indicates an NP-complete problem. +* If it is not possible to break down the problem into smaller sub-problems, it may be NP-complete. +* If your problem involves a sequence, such as a sequence of cities in the case of a traveling salesperson, and is difficult to solve, it may be NP-complete. +* If a problem involves a set, such as a set of radio stations, and is difficult to solve, it may be NP-complete. +* Restating the problem as the set-covering problem or the traveling-salesperson problem confirms that it is NP-complete. + + + +### Reference + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Greedy Algorithm. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/656f0374b25e10bfbdc3bb17](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/656f0374b25e10bfbdc3bb17)>. Acesso em: 29 fev. 2024. diff --git a/Algorithms/Search-Algorithms/BinarySearch/README.md b/algorithms/Search-Algorithms/BinarySearch.md similarity index 100% rename from Algorithms/Search-Algorithms/BinarySearch/README.md rename to algorithms/Search-Algorithms/BinarySearch.md diff --git a/Algorithms/Search-Algorithms/Depth-First-Search/README.md b/algorithms/Search-Algorithms/Depth-First-Search.md similarity index 100% rename from Algorithms/Search-Algorithms/Depth-First-Search/README.md rename to algorithms/Search-Algorithms/Depth-First-Search.md diff --git a/algorithms/Search-Algorithms/README.md b/algorithms/Search-Algorithms/README.md new file mode 100644 index 0000000..6c5f2e1 --- /dev/null +++ b/algorithms/Search-Algorithms/README.md @@ -0,0 +1,2 @@ +# Search-Algorithms + diff --git a/Algorithms/Sorting-Algorithms/HeapSort/README.md b/algorithms/Sorting-Algorithms/HeapSort.md similarity index 100% rename from Algorithms/Sorting-Algorithms/HeapSort/README.md rename to algorithms/Sorting-Algorithms/HeapSort.md diff --git a/Algorithms/Sorting-Algorithms/InsertionSort/README.md b/algorithms/Sorting-Algorithms/InsertionSort.md similarity index 100% rename from Algorithms/Sorting-Algorithms/InsertionSort/README.md rename to algorithms/Sorting-Algorithms/InsertionSort.md diff --git a/Algorithms/Sorting-Algorithms/MergeSort/README.md b/algorithms/Sorting-Algorithms/MergeSort.md similarity index 100% rename from Algorithms/Sorting-Algorithms/MergeSort/README.md rename to algorithms/Sorting-Algorithms/MergeSort.md diff --git a/Algorithms/Sorting-Algorithms/README.md b/algorithms/Sorting-Algorithms/README.md similarity index 100% rename from Algorithms/Sorting-Algorithms/README.md rename to algorithms/Sorting-Algorithms/README.md diff --git a/algorithms/big-o-algorithm-complexity.md b/algorithms/big-o-algorithm-complexity.md new file mode 100644 index 0000000..0761fcb --- /dev/null +++ b/algorithms/big-o-algorithm-complexity.md @@ -0,0 +1,3 @@ +# Big O Algorithm Complexity + +* :link: [Big-O Cheat Sheet](https://www.bigocheatsheet.com/) diff --git a/Algorithms/TEMP.md b/algorithms/temp.md similarity index 100% rename from Algorithms/TEMP.md rename to algorithms/temp.md diff --git a/data-structures/hashsets.md b/data-structures/hashsets.md new file mode 100644 index 0000000..7ca7e05 --- /dev/null +++ b/data-structures/hashsets.md @@ -0,0 +1,11 @@ +# HashSets + +* A **HashSet** is a collection of **unique** elements that does not allow duplicates and permits nulls. + +### HashTable vs HashSet + +A **HashTable** is a data structure that **stores key-value** pairs and uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found. + +A **HashSet** is a collection of **unique** elements that does not allow duplicates and permits nulls. It is one of the fundamental data structures in the Java Collections API. + +In summary, HashTable is a data structure that stores key-value pairs, while HashSet is a collection of unique elements. diff --git a/data-structures/linked-list.md b/data-structures/linked-list.md new file mode 100644 index 0000000..c516756 --- /dev/null +++ b/data-structures/linked-list.md @@ -0,0 +1,237 @@ +# Linked List + +* A **linked list** is a linear data structure where elements are stored in nodes, and each node points to the next one in the sequence, forming a chain-like structure. +* **Dynamic Size**: Easily grows and shrinks in size. +* **Efficient Insertions/Deletions**: Quick at the beginning and middle of the list. + + + +### Types of Linked List + +1. Singly Linked List + * **Definition**: Each node points to the next node. + * **Use Case**: A music playlist where each song plays after the previous one. +2. Doubly Linked List + * **Definition**: Each node has pointers to both the next and the previous nodes. + * **Use Case**: A web browser's history, enabling forward and backward navigation. +3. Circular Linked List + * **Definition**: The last node in the list points back to the first node. + * **Use Case**: A multiplayer board game where play returns to the first player after the last. + + + +### Singly Linked List - Operations + +#### Insert + +* **At the Beginning - O(1)**: Add a new node before the current head of the list. +* **At the End - O(n)**: Traverse the list to the last node and add the new node after it. +* **After a Given Node - O(n)**: Traverse the list to the desired node and insert the new node after it. + +#### Delete + +* **From the Beginning - O(1)**: Set the second node as the new head. +* **From the End - O(n)**: Traverse the list and remove the reference to the last node. +* **A Given Node - O(n)**: Traverse to the node before the one to delete, then remove the reference to the node-to-delete. + +#### Search + +* **Search - O(n):** Traverse the list from the head, comparing each node's data with the search value until a match is found or the end of the list is reached. + + + +### Singly Linked List - Implementation + +```java +// Class to represent a Node in the linked list +class Node { + int data; // Data of the node + Node next; // Reference to the next node in the list + // Constructor to initialize the node with data and set the next reference to null + Node(int d) { data = d; next = null; } +} + +// Class to represent a Singly Linked List and perform various operations +class Solution { + Node head; // head of the list, initially null + + // Inserts a new Node at the front of the list. + void insert(int data) { + Node newNode = new Node(data); // Create a new node with the given data + newNode.next = head; // Set the next reference of the new node to the current head + head = newNode; // Update the head of the list to the new node + } + + // Inserts a new node after the given prev_node. + void insertAfter(Node prev_node, int data) { + // Check if the given prev_node is null + if (prev_node == null) { + System.out.println("The given previous node cannot be null"); + return; + } + Node newNode = new Node(data); // Create a new node with the given data + newNode.next = prev_node.next; // Set the next reference of the new node to the next node of prev_node + prev_node.next = newNode; // Update the next reference of prev_node to the new node + } + + // Deletes the first occurrence of the specified key in the list + void delete(int key) { + Node temp = head, prev = null; // Initialize temp to head and prev to null + // Check if head node itself holds the key to be deleted + if (temp != null && temp.data == key) { + head = temp.next; // Update the head to the next node + return; + } + // Search for the key to be deleted + while (temp != null && temp.data != key) { + prev = temp; // Update prev to the current node + temp = temp.next; // Move to the next node + } + // If key was not present in the list + if (temp == null) return; + // Unlink the node from the list + prev.next = temp.next; + } + + // Searches for the key in the linked list and returns true if found, otherwise false + boolean search(int key) { + Node current = head; // Initialize current to head + while (current != null) { + if (current.data == key) // If the key is found, return true + return true; + current = current.next; // Move to the next node + } + return false; // Key not found, return false + } + + // Main method to test the linked list operations + public static void main(String[] args) { + Solution list = new Solution(); // Create an empty list + + // Insert nodes into the list + list.insert(1); + list.insert(2); + list.insert(3); + + // Search for a key in the list + System.out.println("Search 2: " + list.search(2)); // true + + // Delete a node from the list by key + list.delete(2); + + // Check if the key is still present in the list + System.out.println("Search 2: " + list.search(2)); // false + } +} + +``` + + + +### Doubly Linked List - Operations + +#### **Insertion** + +* **Addition at the Beginning**: A new node can be inserted at the beginning of the DLL. +* **Addition at the End**: A new node can be appended to the end of the list. +* **Addition at a Specific Position**: Inserting a node after a specified position is also possible. + +#### **Deletion** + +* **Removal by Data**: A node containing specific data can be deleted from the list. + +#### **Search** + +* The search operation involves locating a node with a given data value. +* If the target node is found, the search returns **true**; otherwise, it returns **false**. + + + +### Doubly Linked List - Implementation + +```java +class Node { + int data; + Node prev; + Node next; + + Node(int d) { + data = d; + prev = next = null; + } +} + +class Solution { + Node head; + + // Inserts a new Node at front of the list. + void insert(int data) { + Node newNode = new Node(data); + newNode.next = head; + if (head != null) + head.prev = newNode; + head = newNode; + } + + // Inserts a new node after the given prev_node. + void insertAfter(Node prev_node, int data) { + if (prev_node == null) { + System.out.println("The given previous node cannot be null"); + return; + } + Node newNode = new Node(data); + newNode.next = prev_node.next; + prev_node.next = newNode; + newNode.prev = prev_node; + if (newNode.next != null) + newNode.next.prev = newNode; + } + + // Deletes the node with the given data. + void delete(int key) { + Node temp = head; + while (temp != null) { + if (temp.data == key) { + if (temp.prev != null) + temp.prev.next = temp.next; + else + head = temp.next; + if (temp.next != null) + temp.next.prev = temp.prev; + return; + } + temp = temp.next; + } + } + + // Searches for the node with the given data. + boolean search(int key) { + Node current = head; + while (current != null) { + if (current.data == key) + return true; + current = current.next; + } + return false; + } + + public static void main(String[] args) { + Solution dll = new Solution(); + dll.insert(1); + dll.insert(2); + dll.insert(3); + + System.out.println("Search 2: " + dll.search(2)); // true + dll.delete(2); + System.out.println("Search 2: " + dll.search(2)); // false + } +} + +``` + +\ + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to LinkedList. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6510093477fec8050b719fce](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6510093477fec8050b719fce)>. Acesso em: 11 dez. 2023a. diff --git a/data-structures/matrix.md b/data-structures/matrix.md new file mode 100644 index 0000000..2a78eba --- /dev/null +++ b/data-structures/matrix.md @@ -0,0 +1,15 @@ +# Matrix + +A matrix is most commonly represented as a **two-dimensional array** in programming. Essentially, this means that a **matrix is** depicted as **an array of arrays**, where each sub-array represents a row containing multiple column elements. Thus, the primary array holds all the rows, making it possible to visualize the data in a grid-like structure reminiscent of a mathematical matrix. + +``` +A = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]] +``` + + + +### References + +Design Gurus. Grokking Data Structures for Coding Interviews: Introduction to Matrix. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6465cce0468851553fab6fdc](https://www.designgurus.io/course-play/grokking-data-structures-for-coding-interviews/doc/6465cce0468851553fab6fdc)>. Acesso em: 10 dez. 2023a. diff --git a/extra-materials-design-analysis-of-algorithms/README.md b/extra-materials-design-analysis-of-algorithms/README.md new file mode 100644 index 0000000..4dfe00b --- /dev/null +++ b/extra-materials-design-analysis-of-algorithms/README.md @@ -0,0 +1,4 @@ +# Materials From Universities and Colleges + +* [University-of-Auckland - Algorithms & Data Structures](https://www.cs.auckland.ac.nz/courses/compsci220s1t/lectures/lecturenotes/GG-lectures/) +* [Georgia Tech College - Design & Analysis of Algorithms](../Extra-Materials-Design-Analysis-of-Algorithms/Georgia-Tech/) diff --git a/Extra-Materials-Design-Analysis-of-Algorithms/Solving-and-Finding-Recurrences/README.md b/extra-materials-design-analysis-of-algorithms/Solving-and-Finding-Recurrences.md similarity index 100% rename from Extra-Materials-Design-Analysis-of-Algorithms/Solving-and-Finding-Recurrences/README.md rename to extra-materials-design-analysis-of-algorithms/Solving-and-Finding-Recurrences.md diff --git a/Extra-Materials-Design-Analysis-of-Algorithms/Sorting-Searching-Hashing/README.md b/extra-materials-design-analysis-of-algorithms/Sorting-Searching-Hashing.md similarity index 100% rename from Extra-Materials-Design-Analysis-of-Algorithms/Sorting-Searching-Hashing/README.md rename to extra-materials-design-analysis-of-algorithms/Sorting-Searching-Hashing.md diff --git a/extra-materials-design-analysis-of-algorithms/Time-complexity-and-BigOh-Notation.md b/extra-materials-design-analysis-of-algorithms/Time-complexity-and-BigOh-Notation.md new file mode 100644 index 0000000..a116f33 --- /dev/null +++ b/extra-materials-design-analysis-of-algorithms/Time-complexity-and-BigOh-Notation.md @@ -0,0 +1,6 @@ +# Time-complexity-and-BigOh-Notation + +* [University-of-Auckland - Algorithms & Data Structures](https://www.cs.auckland.ac.nz/courses/compsci220s1t/lectures/lecturenotes/GG-lectures/) +* [Georgia Tech College - Design & Analysis of Algorithms](../Extra-Materials-Design-Analysis-of-Algorithms/Time-complexity-and-BigOh-Notation/Georgia-Tech/) +* [Asymptotic notation Examples - CLRS](https://walkccc.github.io/CLRS/Chap03/3.1/) +* [Big O notation: definition and examples](https://yourbasic.org/algorithms/big-o-notation-explained/) diff --git a/LeetCode-Problems/1342-Number-Steps-Reduce-Zero/README.md b/leetcode-problems/1342-Number-Steps-Reduce-Zero.md similarity index 100% rename from LeetCode-Problems/1342-Number-Steps-Reduce-Zero/README.md rename to leetcode-problems/1342-Number-Steps-Reduce-Zero.md diff --git a/LeetCode-Problems/1480-Running-Sum-1D-Array/README.md b/leetcode-problems/1480-Running-Sum-1D-Array.md similarity index 100% rename from LeetCode-Problems/1480-Running-Sum-1D-Array/README.md rename to leetcode-problems/1480-Running-Sum-1D-Array.md diff --git a/LeetCode-Problems/1672-Richest-Customer-Wealth/README.md b/leetcode-problems/1672-Richest-Customer-Wealth.md similarity index 100% rename from LeetCode-Problems/1672-Richest-Customer-Wealth/README.md rename to leetcode-problems/1672-Richest-Customer-Wealth.md diff --git a/LeetCode-Problems/383-Ransom-Note/README.md b/leetcode-problems/383-Ransom-Note.md similarity index 100% rename from LeetCode-Problems/383-Ransom-Note/README.md rename to leetcode-problems/383-Ransom-Note.md diff --git a/LeetCode-Problems/412-FizzBuzz/README.md b/leetcode-problems/412-FizzBuzz.md similarity index 100% rename from LeetCode-Problems/412-FizzBuzz/README.md rename to leetcode-problems/412-FizzBuzz.md diff --git a/LeetCode-Problems/485-Max-Consecutive-Ones/README.md b/leetcode-problems/485-Max-Consecutive-Ones.md similarity index 100% rename from LeetCode-Problems/485-Max-Consecutive-Ones/README.md rename to leetcode-problems/485-Max-Consecutive-Ones.md diff --git a/LeetCode-Problems/876-Middle-Linked-List/README.md b/leetcode-problems/876-Middle-Linked-List.md similarity index 100% rename from LeetCode-Problems/876-Middle-Linked-List/README.md rename to leetcode-problems/876-Middle-Linked-List.md diff --git a/LeetCode-Problems/88-Merge-Sorted-Array/README.md b/leetcode-problems/88-Merge-Sorted-Array.md similarity index 100% rename from LeetCode-Problems/88-Merge-Sorted-Array/README.md rename to leetcode-problems/88-Merge-Sorted-Array.md diff --git a/LeetCode-Problems/977-Squares-Sorted-Array/README.md b/leetcode-problems/977-Squares-Sorted-Array.md similarity index 100% rename from LeetCode-Problems/977-Squares-Sorted-Array/README.md rename to leetcode-problems/977-Squares-Sorted-Array.md diff --git a/leetcode-problems/README.md b/leetcode-problems/README.md new file mode 100644 index 0000000..79206ff --- /dev/null +++ b/leetcode-problems/README.md @@ -0,0 +1,2 @@ +# LeetCode-Problems + diff --git a/MONGAN-et-al-Programming-Int-Exposed-Coding-Exercises/5-Linked-List/README.md b/mongan-et-al-programming-int-exposed-coding-exercises/5-Linked-List.md similarity index 100% rename from MONGAN-et-al-Programming-Int-Exposed-Coding-Exercises/5-Linked-List/README.md rename to mongan-et-al-programming-int-exposed-coding-exercises/5-Linked-List.md diff --git a/MONGAN-et-al-Programming-Int-Exposed-Coding-Exercises/6-Trees/README.md b/mongan-et-al-programming-int-exposed-coding-exercises/6-Trees.md similarity index 100% rename from MONGAN-et-al-Programming-Int-Exposed-Coding-Exercises/6-Trees/README.md rename to mongan-et-al-programming-int-exposed-coding-exercises/6-Trees.md diff --git a/mongan-et-al-programming-int-exposed-coding-exercises/README.md b/mongan-et-al-programming-int-exposed-coding-exercises/README.md new file mode 100644 index 0000000..597ca0c --- /dev/null +++ b/mongan-et-al-programming-int-exposed-coding-exercises/README.md @@ -0,0 +1,2 @@ +# MONGAN-et-al-Programming-Int-Exposed-Coding-Exercises + diff --git a/stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/README.md b/stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/README.md new file mode 100644 index 0000000..19b87fb --- /dev/null +++ b/stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/README.md @@ -0,0 +1,2 @@ +# DivideConquer-Sorting-Searching-Randomized-Algorithms + diff --git a/Stanford-Algorithms-Specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-1/README.md b/stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-1.md similarity index 100% rename from Stanford-Algorithms-Specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-1/README.md rename to stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-1.md diff --git a/Stanford-Algorithms-Specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-2/README.md b/stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-2.md similarity index 100% rename from Stanford-Algorithms-Specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-2/README.md rename to stanford-algorithms-specialization/DivideConquer-Sorting-Searching-Randomized-Algorithms/week-2.md diff --git a/stanford-algorithms-specialization/README.md b/stanford-algorithms-specialization/README.md new file mode 100644 index 0000000..404aecc --- /dev/null +++ b/stanford-algorithms-specialization/README.md @@ -0,0 +1,2 @@ +# Stanford-Algorithms-Specialization + diff --git a/system-design/api-gateway.md b/system-design/api-gateway.md new file mode 100644 index 0000000..423e3c4 --- /dev/null +++ b/system-design/api-gateway.md @@ -0,0 +1,80 @@ +# API Gateway + + + +* API Gateway is an **intermediary (midleware)** between clients (such as web browsers, mobile apps, or other services) and backend services, microservices, or APIs. +* **Main purpose:** to provide a single entry-point for external consumers to access the services and functionalities of the backend system. +* Request trajectory: + 1. API Gateway receives client requests. + 2. Forwards them to the appropriate backend service. + 3. Returns the server’s response to the client. + +

Font: Design Gurus, 2023a

+ + + +### API Gateway Vs. Load Balancer + +* API Gateway: focused on **routing** requests to the appropriate backend service based on specific URLs. +* Load Balancer: focused on **distributing** requests _evenly_ across a group of backend servers. + +

Font: Design Gurus, 2023a

+ + + +### Usage of API gateway + +* **Routing** is facilitated by API gateways, which receive and direct client requests to the appropriate services, simplifying system design. +* **Rate limiting** and throttling are enabled by API gateways to prevent malicious behavior and denial of service attacks. +* **Performance** is enhanced by API gateways through caching responses, reducing the number of forwarded requests. +* **Authentication** and **authorization** are enforced by API gateways, which authenticate clients and ensure authorized access only. +* **Monitoring** capabilities are provided by API gateways, collecting metrics and data on requests and responses to aid in problem identification and system reliability improvement. +* **Data transformation** is facilitated by API gateways, converting formats or aggregating data from multiple services into a single response for client convenience. +* **Request and response validation** are ensured by API gateways, adhering to expected formats and structures to prevent errors and maintain service functionality. +* **The circuit breaker pattern** can be implemented by API gateways, monitoring service health and automatically switching to backup services if needed to prevent system failure. +* **Service discovery** is enabled by API gateways, allowing clients to access services without specific addresses, facilitating the addition or modification of services without affecting clients. +* API versioning is supported by API gateways, allowing developers to introduce new features or changes without disrupting existing clients. +* Consistent error handling and generation of error responses are provided by API gateways, even when backend services are unavailable or return unexpected results. +* Font: BUENO, 2023 is supported by API gateways, combining responses from multiple backend services into a single response for clients, simplifying integration and reducing client requests. +* Protection against common web-based threats is offered by API gateways through the incorporation of a **Web Application Firewall (WAF)**. +* **API documentation** based on standardized formats, such as Swagger or OpenAPI, can be generated and served by API gateways, enhancing developer understanding and facilitating API usage. + + + +### Advantages and Disadvantages + +#### Advantages of using an API Gateway + +* Improved performance through caching, rate limiting, and optimized communication. +* Simplified system design with a single entry point for API requests. +* Enhanced security through authentication and authorization enforcement. +* Improved scalability by distributing requests among multiple microservice instances. +* Better monitoring and visibility with collected metrics and data. +* Simplified client integration by providing a consistent interface. +* Protocol and data format transformation for flexible communication. +* API versioning and backward compatibility for smooth transitions. +* Enhanced error handling for a better user experience. +* Load balancing and fault tolerance for improved performance. + +#### Disadvantages of using an API Gateway + +* Additional complexity in the architecture. +* Single point of failure if not configured properly. +* Potential latency introduced in the request-response path. +* Vendor lock-in when using a specific provider. +* Increased cost for infrastructure and services. +* Maintenance overhead for monitoring and updates. +* Configuration complexity, especially in large-scale deployments. + + + +### API Gateway Summary + +

Font: BUENO, 2023

+ +

Font: BUENO, 2023

+ +### References + +Design Gurus. Grokking System Design Fundamentals: API Gateway. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641ed36e12e1f4e2a46ca14d](https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641ed36e12e1f4e2a46ca14d)>. Acesso em: 12 dez. 2023a. + diff --git a/system-design/key-characteristics-of-distributed-systems/README.md b/system-design/key-characteristics-of-distributed-systems/README.md new file mode 100644 index 0000000..7591752 --- /dev/null +++ b/system-design/key-characteristics-of-distributed-systems/README.md @@ -0,0 +1,16 @@ +--- +layout: + title: + visible: true + description: + visible: true + tableOfContents: + visible: true + outline: + visible: true + pagination: + visible: true +--- + +# Key Characteristics of Distributed Systems + diff --git a/system-design/key-characteristics-of-distributed-systems/availability.md b/system-design/key-characteristics-of-distributed-systems/availability.md new file mode 100644 index 0000000..1d67ea7 --- /dev/null +++ b/system-design/key-characteristics-of-distributed-systems/availability.md @@ -0,0 +1,123 @@ +# Availability + +### Availability + +Disponibilidade é relacionada à frequência com que o sistema está online, em execução e provendo serviços e funcionalidade aos seus usuários (INDRASIRI; SUHOTHAYAN, 2021 e NEWMAN, 2021). + +* High Availability encompasses: + * running (online) + * system can handle increased load and traffic without compromising its performance. + +High availability is often **measured** in terms of **uptime**, which is the ratio of time that a system is operational to the total time it is supposed to be operational. + +Achieving high availability involves **minimizing** planned and _unplanned downtime, eliminating single points of failure, and implementing redundant systems and processes_. + + + +### Strategies for Achieving High Availability + +#### High Availability through Redundancy and Replication + +* Duplicates critical components or entire systems for seamless takeover by the **redundant** **server** if one fails. +* Creates multiple copies of data to ensure availability (**replication**). +* Commonly used in data centers where multiple servers handle the workload. + * In the event of a hardware failure or system crash, the **redundant** server takes over, ensuring uninterrupted service for users. + +#### Availability through Load Balancing + +* Distributes workloads across multiple servers to prevent any single server from being overwhelmed. +* Optimizes **resource utilization** and prevents bottlenecks (all this enhances availability). +* Particularly useful in web applications with a large number of simultaneous users. + +#### Availability through Distributed Data Storage + +* Stores data across **multiple locations** or data centers to **reduce the risk of data loss or corruption**. +* **Replicates** data across **geographically** diverse locations to ensure availability even if one site experiences an outage. +* Crucial for organizations dealing with large volumes of data. + +#### Availability and Consistency Models (Strong, Weak, Eventual) + +* **Consistency Models** defines how a distributed system maintains a coherent and up-to-date view of its data across all replicas. +* Different models provide different trade-offs between availability, performance, and data correctness. + * **Strong Consistency**: This model ensures that all replicas have identical data at all times. However, this comes at the expense of decreased availability and performance. + * **Weak Consistency**: This model allows for temporary discrepancies between replicas, which in turn enhances availability and performance. + * **Eventual Consistency**: This model guarantees that all replicas will ultimately align to display the same data, striking a balance between consistency, availability, and performance. + +#### Availability through Health Monitoring and Alerts + +* Implements robust health monitoring systems to proactively **identify** and address potential **issues**. +* Real-time monitoring and automated alerts enable timely response and rapid resolution of problems. +* Continuously monitors system performance, resource utilisation, and various metrics to detect anomalies or potential issues. + +#### Availability through Geographic Distribution + +* Involves deploying system components across multiple locations or data centers. +* Ensures system access even if one region or data center experiences an outage. +* Particularly important for organizations with a global presence or those that heavily rely on cloud infrastructure. +* By strategically placing system components in different geographical areas, uninterrupted system access is ensured for users from various locations, regardless of localized incidents or natural disasters. + + + +### Fault Tolerance vs. High Availability + +**Consistência** é o atributo de qualidade pela qual obtém-se a mesma resposta ao consultar todas as réplicas de um componente que estão executando em máquinas diferentes; **disponibilidade** é o atributo de qualidade que significa que cada requisição realizada para um componente do sistema recebe uma resposta; **tolerância** de partição é a qualidade do sistema que expressa a capacidade de lidar com situações onde não é possível estabelecer comunicação entre componentes em determinados momentos (NEWMAN, 2021). + + + +#### Fault Tolerance + +**Fault tolerance** is defined as the uninterrupted operation of a system, even when one or more of its components fail. The design of fault-tolerant systems is such that hardware, software, and network failures are handled seamlessly (Design Gurus, 2023a). + + + +According to Design Gurus (2023a), a system that is fault tolerant has the following characteristics: + +* **Redundancy:** It helps avoid single point of failure. +* **Automatic Failover**: Automatically switches to a redundant or standby system upon the failure of a system component. +* **No Data Loss**: Ensures that no data is lost in the event of a failure. +* **Cost**: Generally more expensive due to the need for redundant components. + + + +#### High Availability + +High Availability is characterized by the system's capability to stay operational and accessible for a very high percentage of time, with downtime being minimized as much as possible (Design Gurus, 2023a). + + + +A system that is highly available has the following characteristics (Design Gurus, 2023a): + +* **Uptime Guarantee**: Designed to ensure a high level of operational performance and uptime (often quantified in terms of “nines” – for example, 99.999% availability). +* **Load Balancing and Redundancy**: load balancing, redundant systems are some of the techniques that are applied in order to achieve high availability. +* **Rapid Recovery**: The system should be designed in a way that allows for quick restoration of service after a failure, although a brief disruption may be acceptable. + + + +#### Key differences - Fault Tolerance vs. High Availability + +* Goal: + * Fault Tolerance: The design is such that it can handle failures without any service interruption or data loss (\~ no downtime). + * High Availability: The aim is to ensure that a system is usually available, with **minimal downtime**. +* Approach: + * Fault Tolerance: Redundancy and automatic failover mechanisms are involved. + * High Availability: Prevent downtime through redundant resources and rapid recovery strategies. +* Downtime: + * Fault Tolerance: No downtime even during failure. + * High Availability: There is minimal downtime, but brief interruptions are acceptable +* Cost and Complexity: + * Fault Tolerance: It is more expensive and complex due to the need for exact replicas and seamless failover. + * High Availability: It is more cost-effective, balancing the level of availability with associated costs. +* Data Integrity: + * Fault Tolerance: Data integrity is maintained even in failure scenarios. + * High Availability: System uptime is prioritized, with potential for minimal data loss in certain failure conditions. + * Se dois componentes em um sistema distribuído não puderem se comunicar, as atualizações não são propagadas para todos. Os sistemas que **cedem consistência** para manter a tolerância e a disponibilidade de partição são **eventualmente consistentes** (NEWMAN, 2021). + + + +### References + +Design Gurus. Grokking System Design Fundamentals. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-system-design-fundamentals/](https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641ed36e12e1f4e2a46ca14d)>. Acesso em: 12 dez. 2023a. + +NEWMAN, Sam. Building Microservices. 2nd ed. Sebastopol: O'Reilly Media, 2021. 612 p. ISBN: 978-1-492-03402-5. + +INDRASIRI, Kasun; SUHOTHAYAN, Sriskandarajah. Design Patterns for Cloud Native Applications. 1st ed. Sebastopol: O'Reilly Media, 2021. 311 p. ISBN: 978-1-492-09071-7. diff --git a/system-design/key-characteristics-of-distributed-systems/latency-and-performance.md b/system-design/key-characteristics-of-distributed-systems/latency-and-performance.md new file mode 100644 index 0000000..c4c8868 --- /dev/null +++ b/system-design/key-characteristics-of-distributed-systems/latency-and-performance.md @@ -0,0 +1,26 @@ +# Latency and Performance + +Performance está relacionada com a rapidez e eficiência que um sistema ou aplicação executa uma determinada operação sob uma determinada carga de trabalho. Dentre as principais grandezas para avaliar performance estão as restrições envolvendo limites de tempo e espaço, como cargas de trabalho, tempo de resposta, taxa de transferência e espaço de armazenamento disponível (CHUNG; LEITE, 2009). + + + +A latência pode ser definida como o tempo necessário para que dados se movam de um local para outro através da rede (RICHARDS; FORD, 2020). + + + +In distributed systems, optimizing latency and performance involves considering factors such as data locality, load balancing, and caching strategies. + + + +* **Data locality** is referred to as the minimization of data transfer between nodes through the organization and distribution of data. This is achieved by storing related data close together or near the nodes that frequently access it, resulting in reduced latency and improved performance. Data partitioning, sharding, and data replication are techniques used to achieve data locality. +* **Caching strategies** involve the temporary storage of frequently accessed data or computed results. This allows the system to quickly retrieve the data from the cache instead of recalculating or fetching it from the primary data source, significantly reducing latency and improving the performance of the distributed system. In-memory caching, distributed caching, and content delivery networks (CDNs) are common caching strategies. + + + +### References + +Design Gurus. Grokking System Design Fundamentals. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-system-design-fundamentals/](https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641ed36e12e1f4e2a46ca14d)>. Acesso em: 12 dez. 2023a. + +CHUNG, Lawrence; LEITE, Julio. On Non-Functional Requirements in Software Engineering. Mylopoulos Festschrift, LNCS 5600, p. 363–379, 2009. + +RICHARDS, Mark; FORD, Neal. Fundamentals of Software Architecture. 1st ed. Sebastopol: O'Reilly Media, 2020. 419 p. ISBN: 978-1-492-04345-4. diff --git a/system-design/key-characteristics-of-distributed-systems/page.md b/system-design/key-characteristics-of-distributed-systems/page.md new file mode 100644 index 0000000..5c4b4d5 --- /dev/null +++ b/system-design/key-characteristics-of-distributed-systems/page.md @@ -0,0 +1,2 @@ +# Page + diff --git a/system-design/key-characteristics-of-distributed-systems/scalability.md b/system-design/key-characteristics-of-distributed-systems/scalability.md new file mode 100644 index 0000000..8d533ed --- /dev/null +++ b/system-design/key-characteristics-of-distributed-systems/scalability.md @@ -0,0 +1,39 @@ +# Scalability + +**Escalabilidade** é a capacidade de suportar cargas crescentes sem impactar a performance. Um possível exemplo de escalabilidade é a capacidade de expandir componentes da infraestrutura, como aumentar o número de instâncias de um microsserviço para atender um aumento do número de usuários simultâneos (NEWMAN, 2021). + +It is possible to scale a system by adding more resources (scaling out/horizontal scaling), or by updating the capacity of the existing resources (scaling up). + + + +### Horizontal Scaling + +* It involves adding more machines or nodes to a system to distribute the workload evenly. +* dimensionamento elástico (capacidade de adicionar ou remover servidores dependendo da carga de trabalho) é um exemplo dessa dinamicidade (BUENO, 2023). + + + +### Vertical Scaling + +* Achieved by upgrading the hardware, such as adding more CPU, memory, or storage. +* This approach has limitations, as there is a physical limit to the amount of resources that can be added to a single machine. + + + +### Horizontal Scaling vs. Vertical Scaling + +* **Horizontal Scaling**: + * Easier to scale dynamically by adding more machines into the existing pool. + * Good examples: Cassandra and MongoDB, which allow easy horizontal scaling to meet growing needs. +* **Vertical Scaling**: + * Usually limited to the capacity of a single server. + * Scaling beyond that capacity often involves downtime and comes with an upper limit. + * Good example: MySQL, which allows easy vertical scaling by switching from smaller to bigger machines, but often involves downtime. + + + +### References + +Design Gurus. Grokking System Design Fundamentals. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-system-design-fundamentals/](https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641ed36e12e1f4e2a46ca14d)>. Acesso em: 12 dez. 2023a. + +NEWMAN, Sam. Building Microservices. 2nd ed. Sebastopol: O'Reilly Media, 2021. 612 p. ISBN: 978-1-492-03402-5. diff --git a/system-design/load-balancing.md b/system-design/load-balancing.md new file mode 100644 index 0000000..99ed82e --- /dev/null +++ b/system-design/load-balancing.md @@ -0,0 +1,253 @@ +# Load Balancing + +* Load balancing is a technique used to distribute workloads evenly across multiple computing resources. +* **Goal:** LB ensures, resource optimisation, high availability, reliability, and performance by avoiding overloading a single server and avoiding downtime. +* To achieve full scalability and redundancy, load balancers can be strategically placed at three key locations within the system: + * **Between the user and the web server.** + * **Between web servers and an internal platform layer** (such as application servers or cache servers). + * **Between the internal platform layer and the database**. + +Load balancers play a crucial role in optimizing system performance and ensuring robustness. + +

Font: Design Gurus, 2023a

+ +### How Load Balancer Work? + +1. The load balancer **receives a request** from a client or user. +2. It **evaluates the incoming request** based on factors like server capacity, response time, active connections, and geographic location. +3. The load balancer **forwards the traffic** to the selected server or resource. +4. The server or resource **processes the request** and sends a response back to the load balancer. +5. Finally, the load balancer **sends the response** to the client or user who made the request. + + + +### Uses of Load Balancing + +* Load balancing is used to **distribute workloads** evenly across multiple computing resources. +* Load balancing improves website **performance** by distributing web traffic among multiple servers. +* It ensures **high availability and reliability** by redirecting traffic to available servers in case of failure. +* Load balancing enables **scalability** by adding servers to handle increased demand. +* **Redundancy** is achieved by maintaining redundant copies of data and services across servers. +* Load balancing **optimizes network traffic** by distributing it across multiple paths or links. +* **Geographic distribution** directs users to the nearest data center, reducing latency. +* It optimizes application performance by allocating resources to specific applications or services. +* Load balancers help protect against DDoS attacks by distributing traffic across multiple servers. +* **Cost savings** are achieved by optimizing resource usage and reducing infrastructure costs. +* Some load balancers can **cache** static content, reducing the load on servers and improving response times. + + + +### Load Balancing Algorithms + +#### Round Robin + +* The Round Robin algorithm distributes incoming requests sequentially to available servers in a circular order. +* **Pros:** + * Works well when servers have similar capacities; +* **Cons:** + * May not perform optimally when servers have different capacities or varying workloads. + * No consideration for server health or response time. + + + +#### Least Connections + +* The Least Connections algorithm directs incoming requests to the server with the lowest number of active connections. This approach accounts for the varying workloads of servers. +* **Pros:** + * Adapts to differing server capacities and workloads. + * Balances load more effectively when dealing with requests that take a variable amount of time to process. +* **Cons:** + * Requires tracking the number of active connections for each server, which can increase complexity. + * May not factor in server response time or health. + + + +#### Weighted Round Robin + +* The Weighted Round Robin algorithm is an extension of the Round Robin algorithm that assigns different weights to servers based on their capacities. +* The load balancer distributes requests proportionally to these weights. +* **Pros:** + * Accounts for different server capacities, balancing load more effectively. +* **Cons:** + * Weights must be assigned and maintained manually. + * No consideration for server health or response time. + + + +#### Weight Least Connections + +The Weighted Least Connections algorithm combines the Least Connections and Weighted Round Robin algorithms. + +* **Pros:** + * Balances load effectively, accounting for both server capacities and active connections. + * Adapts to varying server workloads and capacities. +* **Cons:** + * Requires tracking active connections and maintaining server weights. + * May not factor in server response time or health. + + + +#### IP Hash + +The IP Hash algorithm determines the server to which a request should be sent based on the source and/or destination IP address. **This method maintains session persistence**, **ensuring** that **requests from a specific user are directed to the same server**. + +* **Pros:** + * Maintains session persistence, which can be useful for applications requiring a continuous connection with a specific server. + * Can distribute load evenly when using a well-designed hash function. +* **Cons:** + * May not balance load effectively when dealing with a small number of clients with many requests. + * No consideration for server health, response time, or varying capacities. + + + +#### Least Response Time + +The Least Response Time algorithm directs incoming requests to the server with the lowest response time and the fewest active connections. This method helps to optimize the user experience by prioritizing faster-performing servers. + +* **Pros:** + * Accounts for server response times, improving user experience. + * Considers both active connections and response times, providing effective load balancing. +* **Cons:** + * Requires monitoring and tracking server response times and active connections, adding complexity. + * May not factor in server health or varying capacities. + +#### Custom Load + +* Custom Load algorithm: Allows administrators to create personalized load balancing algorithms based on specific requirements, considering factors like server health, location, and capacity. + + + +#### Random + +* Random algorithm: Selects servers randomly for load distribution, making it simple to implement but lacking considerations for factors like server health and response times. + + + +#### Least Bandwidth + +* Least Bandwidth algorithm: Directs requests to servers with the least bandwidth usage, managing network resources effectively but requiring monitoring and potentially neglecting other factors like server health and response times. + + + +### Load Balancer Types + +* A load balancing type **refers to the method** or approach used to distribute incoming network traffic across multiple servers or resources. +* **There are various load balancing methods such as** hardware load balancing, software load balancing, cloud-based load balancing, DNS load balancing, and Layer 4 and Layer 7 load balancing. + +#### DNS Load Balancing + +**DNS (Domain Name System) load balancing** relies on the DNS infrastructure to **distribute incoming traffic among multiple servers or resources**. It **works by resolving a domain name to multiple IP addresses**, effectively directing clients to different servers based on various policies. + +* **Pros**: + * **Relatively simple to implement**, as it doesn’t require specialized hardware or software. + * Provides **basic load balancing and failover capabilities**. + * Can **distribute traffic across geographically distributed servers**, improving performance for users in different regions. +* **Cons**: + * **Limited to DNS resolution time**, which can be slow to update when compared to other load balancing techniques. + * **No consideration for server health, response time, or resource utilization**. + + + +#### Layer 4 Load Balancing + +* **Layer 4 load balancing**, also referred to as **transport layer load balancing**, **operates at the transport layer of the OSI model (the fourth layer)**. +* **Incoming traffic is distributed** based on information from the **TCP or UDP header**, including **source and destination IP addresses** and **port numbers**. +* **Pros**: + * **Fast and efficient**: It makes decisions based on **limited information from the transport layer**. + * **Versatility**: It can handle a **wide variety of protocols and traffic types**. +* **Cons:** + * **Lack of awareness of application-level information**: This may limit its effectiveness in some scenarios. + * No consideration for server health, response time, or resource utilization. + * May not be suitable for applications requiring session persistence or fine-grained load distribution. + + + +#### Layer 7 Load Balancing + +* **Layer 7 load balancing**, also referred to as **application layer load balancing**, **operates at the application layer of the OSI model (the seventh layer)**. +* It takes into account application-specific information, such as HTTP headers, cookies, and URL paths, to make more informed decisions about how to distribute incoming traffic. +* **Pros**: + 1. **Intelligent and fine-grained load balancing**: It considers application-level details. + 2. **Support for advanced features**: Such as **session persistence**, **content-based routing**, and **SSL offloading**. +* **Cons:** + 1. **Slower and more resource-intensive**: Compared to **Layer 4 load balancing**, it requires **deeper inspection** of incoming traffic. +* **Example:** Consider a **web application with multiple microservices**. It utilizes **Layer 7 load balancing** to **route incoming API requests based on the URL path**, ensuring that each microservice receives only the requests it is responsible for handling. + +### Statekess vs Stateful Load Balancing + +**Stateless load balancing** operates without storing session information and makes routing decisions based on incoming request data. It efficiently distributes traffic without considering client history. Conversely, **stateful load balancing** preserves session information and directs subsequent requests from the same client to the same server, making it suitable for applications that depend on session data. + + + +### High Availability and Fault Tolerance For Load Balancers + +#### Redundancy and failover strategies for load balancers + +* Active-passive configuration: One load balancer handles traffic while the other remains on standby. If the active load balancer fails, the passive instance takes over. +* Active-active configuration: Multiple load balancer instances process traffic simultaneously, distributing load and providing increased fault tolerance. + +

Design Guru, 2023b

+ + + +#### Health checks and monitoring for load balancers + +* Health checks: Periodic tests performed by the load balancer to determine backend server availability and performance, allowing the removal of unhealthy servers from the pool. +* Load balancer monitoring: Tracking performance metrics, such as response times and resource utilization, to detect potential issues and take corrective action. + + + +#### Synchronization and State Sharing among load balancers + +* Centralized configuration management: Using a centralized store to maintain and distribute configuration data among load balancer instances for consistency. +* State sharing and replication: Ensuring synchronization of session data and state information across load balancer instances through mechanisms like database replication or distributed caching systems. + + + +### Scalability and Performance + +#### Horizontal and vertical scaling of load balancers + +* Horizontal scaling: Adding more load balancer instances to distribute traffic among them. +* Vertical scaling: Increasing the resources (e.g., CPU, memory, and network capacity) of existing load balancer instance(s) to handle increased traffic. + + + +#### Connection and request rate limits + +* Implementing rate limiting and connection limits at the load balancer level to prevent overloading and ensure consistent performance. +* Rate limits can be enforced based on criteria like IP addresses, client domains, or URL patterns. These limits can also help mitigate the impact of Denial of Service (DoS) attacks and prevent individual clients from monopolizing resources. + + + +#### Caching and content optimization + +* Load balancers can cache static content, such as images, CSS, and JavaScript files, and support content optimization features like compression or minification to improve performance and reduce load on backend servers. + + + +#### Impact of load balancers on latency + +* Load balancers introduce an additional network hop, potentially increasing latency. +* Strategies to optimize load balancer performance include geographical distribution, connection reuse (which reduce the overhead of establishing new connections between the load balancer and backend servers for each request), and protocol optimizations like HTTP/2 or QUIC. + + + +### Common Issues Associated with Load Balancers + +1. **Single Point of Failure:** Load balancers can become a single point of failure if not designed with redundancy and failover mechanisms. +2. **Configuration Complexity:** Load balancers have various configuration options, and misconfigurations can lead to poor performance or service outages. +3. **Scalability Limitations:** Load balancers themselves can become performance bottlenecks if not configured to handle increased traffic. +4. **Latency:** Introducing a load balancer adds an extra network hop, potentially increasing latency. +5. **Sticky Sessions:** Load balancers need to support session persistence for applications that require maintaining user context, but it can lead to uneven load distribution. +6. **Cost:** Deploying and managing load balancers can add to infrastructure costs, including hardware, software licensing, or managed services fees. +7. **Health Checks and Monitoring:** Inadequate health checks can result in directing traffic to unhealthy servers, impacting user experience. + +### References + +Design Gurus. Grokking System Design Fundamentals: Load Balance. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641da6bad2bb4146954f1130](https://www.designgurus.io/course-play/grokking-system-design-fundamentals/doc/641da6bad2bb4146954f1130)>. Acesso em: 10 dez. 2023a. + + + +Design Gurus. Grokking the System Design Interview: Load Balance. Design Gurus, 2023. Disponível em: <[https://www.designgurus.io/course-play/grokking-the-system-design-interview/doc/638c0b7aac93e7ae59a1b0ad](https://www.designgurus.io/course-play/grokking-the-system-design-interview/doc/638c0b7aac93e7ae59a1b0ad)>. Acesso em: 12 dez. 2023b. + diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/README.md new file mode 100644 index 0000000..dad9896 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/README.md @@ -0,0 +1,2 @@ +# Analysis-of-Algorithms-and-Data-Structures + diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/README.md new file mode 100644 index 0000000..a31af7b --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/README.md @@ -0,0 +1,2 @@ +# Atividade\_10 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/Atividade_10-Q1.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/atividade_10-q1.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/Atividade_10-Q1.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_10/atividade_10-q1.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/README.md new file mode 100644 index 0000000..9494926 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/README.md @@ -0,0 +1,2 @@ +# Atividade\_11 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/Atividade_11.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/atividade_11.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/Atividade_11.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_11/atividade_11.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/README.md new file mode 100644 index 0000000..91fb8e2 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/README.md @@ -0,0 +1,2 @@ +# Atividade\_12 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/Atividade_12.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/atividade_12.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/Atividade_12.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_12/atividade_12.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/README.md new file mode 100644 index 0000000..db7ecec --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/README.md @@ -0,0 +1,2 @@ +# Atividade\_13 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/Atividade_13-Q1.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/atividade_13-q1.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/Atividade_13-Q1.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_13/atividade_13-q1.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/README.md new file mode 100644 index 0000000..bd1e9c6 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/README.md @@ -0,0 +1,2 @@ +# Atividade\_14 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/Atividade_14-Q1.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/atividade_14-q1.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/Atividade_14-Q1.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_14/atividade_14-q1.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/README.md new file mode 100644 index 0000000..d39cc6d --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/README.md @@ -0,0 +1,2 @@ +# Atividade\_2 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/Atividade_2-Q2-Q3.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/atividade_2-q2-q3.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/Atividade_2-Q2-Q3.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_2/atividade_2-q2-q3.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/README.md new file mode 100644 index 0000000..a750d72 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/README.md @@ -0,0 +1,2 @@ +# Atividade\_4 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/Atividade_4-Q1-Q2-Q3-Q4-Q5.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/atividade_4-q1-q2-q3-q4-q5.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/Atividade_4-Q1-Q2-Q3-Q4-Q5.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_4/atividade_4-q1-q2-q3-q4-q5.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/README.md new file mode 100644 index 0000000..675e73a --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/README.md @@ -0,0 +1,2 @@ +# Atividade\_8 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/Q1.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/q1.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/Q1.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_8/q1.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/README.md new file mode 100644 index 0000000..f997d99 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/README.md @@ -0,0 +1,2 @@ +# Atividade\_9 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/Atividade_9-Q1.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/atividade_9-q1.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/Atividade_9-Q1.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/Atividade_9/atividade_9-q1.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/README.md new file mode 100644 index 0000000..3c8e7f7 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/README.md @@ -0,0 +1,2 @@ +# P1 + diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/Q2_Q3_Q4_Q5_Q6_Q7.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/q2_q3_q4_q5_q6_q7.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/Q2_Q3_Q4_Q5_Q6_Q7.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P1/q2_q3_q4_q5_q6_q7.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1245-Lost-Boots/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1245-Lost-Boots.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1245-Lost-Boots/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1245-Lost-Boots.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1790-Bridge-Detecting-Graph/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1790-Bridge-Detecting-Graph.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1790-Bridge-Detecting-Graph/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/1790-Bridge-Detecting-Graph.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2026-Christmas-Tree-Backpack-Dynamic-Programming/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2026-Christmas-Tree-Backpack-Dynamic-Programming.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2026-Christmas-Tree-Backpack-Dynamic-Programming/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2026-Christmas-Tree-Backpack-Dynamic-Programming.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2115-Ekaterimburgo-Production/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2115-Ekaterimburgo-Production.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2115-Ekaterimburgo-Production/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2115-Ekaterimburgo-Production.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2237-Container/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2237-Container.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2237-Container/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2237-Container.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2720-Big-Gift-Sorting/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2720-Big-Gift-Sorting.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2720-Big-Gift-Sorting/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/2720-Big-Gift-Sorting.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-1354-Big-Square-Backtracking/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-1354-Big-Square-Backtracking.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-1354-Big-Square-Backtracking/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-1354-Big-Square-Backtracking.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3095-Bills-vs-MajinBoo-Greedy/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3095-Bills-vs-MajinBoo-Greedy.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3095-Bills-vs-MajinBoo-Greedy/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3095-Bills-vs-MajinBoo-Greedy.md diff --git a/USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3107-Frog-Shortest-Path/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3107-Frog-Shortest-Path.md similarity index 100% rename from USP/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3107-Frog-Shortest-Path/README.md rename to usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/Canceled-3107-Frog-Shortest-Path.md diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/README.md new file mode 100644 index 0000000..87b0da1 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/P2/README.md @@ -0,0 +1,2 @@ +# P2 + diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/README.md new file mode 100644 index 0000000..93bf904 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/Atividades/README.md @@ -0,0 +1,2 @@ +# Atividades + diff --git a/usp/Analysis-of-Algorithms-and-Data-Structures/resources/README.md b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/README.md new file mode 100644 index 0000000..dc65347 --- /dev/null +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/resources/README.md @@ -0,0 +1,2 @@ +# resources + diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200817.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200817.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200817.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200817.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200824.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200824.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200824.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200824.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200831.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200831.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200831.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200831.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200907.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200907.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200907.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200907.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200914.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200914.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200914.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200914.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200921.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200921.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20200921.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20200921.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201005.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201005.md similarity index 54% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201005.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201005.md index e6796a4..75396cc 100644 --- "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201005.md" +++ b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201005.md @@ -1,60 +1,70 @@ # SIN5013 - Análise de Algoritmos e Estruturas de Dados 20201005 ## A estrutura de dados Heap + Heap é uma estrutura de dados que pode ser visualizada como uma **árvore binária quase completa**. Cada nó da árvore é ocupado por um elemento e temos as seguintes propriedades: -- A árvore é completa até o **penúltimo nível** -- No último nível as folhas **estão o mais à esquerda** possível -- O conteúdo de um nó é **maior ou igual** que o conteúdo dos nós na subárvore enraizada nele **(max-heap)** -- O conteúdo de um nó é **Menor ou igual** que o conteúdo dos nós na subárvore enraizada nele **(min-heap)** +* A árvore é completa até o **penúltimo nível** +* No último nível as folhas **estão o mais à esquerda** possível +* O conteúdo de um nó é **maior ou igual** que o conteúdo dos nós na subárvore enraizada nele **(max-heap)** +* O conteúdo de um nó é **Menor ou igual** que o conteúdo dos nós na subárvore enraizada nele **(min-heap)** **As propriedades acima garantem que os valores do heap podem ser armazenados em um array** ## Por que precisamos de algo como Heaps? + Heaps é usado principalmente para obter o valor mínimo ou máximo presente em um heap no tempo O (1). Aqui está a complexidade de tempo de várias operações realizadas em um heap com n elementos: -- Acesso ao valor min/max: O(1) -- Inserir elemento: O(log n) -- Removendo um elemento: O(log n) + +* Acesso ao valor min/max: O(1) +* Inserir elemento: O(log n) +* Removendo um elemento: O(log n) Os Heaps tornam muito rápido o acesso aos elementos de nível de prioridade. A estrutura de dados Priority Queue é implementada usando Heaps. Casos de uso reais de Heaps: -- O sistema operacional usa heaps para agendar jobs com prioridade. 2. -- O modelo produtor-consumidor pode ser implementado usando heaps para permitir que o consumidor acesse primeiro os elementos de maior prioridade. É usado na implementação da [Blocking Priority Queue](https://www.geeksforgeeks.org/priorityblockingqueue-class-in-java/). + +* O sistema operacional usa heaps para agendar jobs com prioridade. 2. +* O modelo produtor-consumidor pode ser implementado usando heaps para permitir que o consumidor acesse primeiro os elementos de maior prioridade. É usado na implementação da [Blocking Priority Queue](https://www.geeksforgeeks.org/priorityblockingqueue-class-in-java/). ## Representação do Heap no Vetor -Para qualquer nó i -- `2i` é o filho esquerdo de i -- `2i + 1` é o filho direito de i - ![enter image description here](heap-no-array-exemplo.png) -- `|_ i/2 _|` é o pai de i -- MAX-HEAP - - `A[|_ i/2 _|]` >= A[i] - Garantem que o elemento max está na rais -- Número de nós no nível `p` - - 2^p -- Altura do maior de um nó `i` é o maior comprimento de um caminho de `i` até a folha -- Altura de um nó `i`: - - h = `|_log(m/i)` - - i = número do nó - - m = número total de nós + +Para qualquer nó i + +* `2i` é o filho esquerdo de i +* `2i + 1` é o filho direito de i ![enter image description here](../../USP/Analysis-of-Algorithms-and-Data-Structures/heap-no-array-exemplo.png) +* `|_ i/2 _|` é o pai de i +* MAX-HEAP + * `A[|_ i/2 _|]` >= A\[i] - Garantem que o elemento max está na rais +* Número de nós no nível `p` + * 2^p +* Altura do maior de um nó `i` é o maior comprimento de um caminho de `i` até a folha +* Altura de um nó `i`: + * h = `|_log(m/i)` + * i = número do nó + * m = número total de nós ## Manutenção da Propriedade de Heap + ``` ``` ### Equação de Recorrência -Seja h a altura do nó `i` e T(h) o consumo de tempo no pior caso + +Seja h a altura do nó `i` e T(h) o consumo de tempo no pior caso + ``` ``` -- **Pior dos casos:** No pior dos casos, o elemento que estamos tentando ajustar para manter a propriedade do HEAP, descerá até o ultimo nível da àrvore, ou seja, a complexidade está relacionada com a altura da àrvore. +* **Pior dos casos:** No pior dos casos, o elemento que estamos tentando ajustar para manter a propriedade do HEAP, descerá até o ultimo nível da àrvore, ou seja, a complexidade está relacionada com a altura da àrvore. ### Prova Consumo de Tempo - `O(log(m))` -![consumo-tempo-heap-manutencao](consumo-tempo-heap-manutencao.png) + +![consumo-tempo-heap-manutencao](../../USP/Analysis-of-Algorithms-and-Data-Structures/consumo-tempo-heap-manutencao.png) ## Construção de um Max-Heap ## References --[Heap JS](https://blog.bitsrc.io/implementing-heaps-in-javascript-c3fbf1cb2e65) + +\-[Heap JS](https://blog.bitsrc.io/implementing-heaps-in-javascript-c3fbf1cb2e65) diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201012.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201012.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201012.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201012.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201019.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201019.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201019.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201019.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201026.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201026.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201026.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201026.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201102.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201102.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201102.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201102.md diff --git "a/USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201109.md" b/usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201109.md similarity index 100% rename from "USP/Analysis-of-Algorithms-and-Data-Structures/SIN5013 - An\303\241lise de Algoritmos e Estruturas de Dados 20201109.md" rename to usp/Analysis-of-Algorithms-and-Data-Structures/sin5013-analise-de-algoritmos-e-estruturas-de-dados-20201109.md diff --git a/usp/README.md b/usp/README.md new file mode 100644 index 0000000..2e97b5d --- /dev/null +++ b/usp/README.md @@ -0,0 +1,2 @@ +# USP +