From 8ee6007bbfb34dda9d6785dcd041622b4a14201f Mon Sep 17 00:00:00 2001 From: mankalavaishnavi Date: Sat, 22 Jun 2024 21:17:42 +0530 Subject: [PATCH 1/3] added deque and updated index.md --- contrib/ds-algorithms/deque.md | 108 +++++++++++++++++++++++++++++++++ contrib/ds-algorithms/index.md | 1 + 2 files changed, 109 insertions(+) create mode 100644 contrib/ds-algorithms/deque.md diff --git a/contrib/ds-algorithms/deque.md b/contrib/ds-algorithms/deque.md new file mode 100644 index 0000000..459ac04 --- /dev/null +++ b/contrib/ds-algorithms/deque.md @@ -0,0 +1,108 @@ +## Double-Ended Queue (Deque) + +A double-ended queue (deque) supports insertion and deletion from both ends, making it a more versatile queue implementation. + +### Input-Restricted Deque + +In an input-restricted deque, elements can only be inserted from one end while deletions can occur from both ends. + +### Output-Restricted Deque + +An output-restricted deque allows elements to be deleted from one end only, while insertions can be made from both ends. + +## Real Life Examples of Deques + +### Task Scheduling + +Deques are useful in task scheduling algorithms where tasks can be added to either end and processed accordingly based on priority or other scheduling criteria. + +### Sliding Window Problems + +Algorithms solving sliding window problems often use deques to efficiently manage and query elements in the current window. + +### Implementations in Python + +Python provides a built-in `collections.deque` which supports efficient append and pop operations from both ends. It's ideal for scenarios requiring a simple and efficient double-ended queue. + +## Operations on a Deque + +- **isEmpty**: Checks if the deque is empty. +- **appendLeft**: Adds an element to the left end of the deque. +- **appendRight**: Adds an element to the right end of the deque. +- **popLeft**: Removes and returns the element from the left end of the deque. +- **popRight**: Removes and returns the element from the right end of the deque. +- **peekLeft**: Returns the element from the left end without removing it. +- **peekRight**: Returns the element from the right end without removing it. +- **clear**: Removes all elements from the deque. + +## Implementation of Deque in Python + +Python's `collections.deque` provides an efficient implementation of a deque. + +```python +from collections import deque + +# Creating a deque +dq = deque() + +# Adding elements to the deque +dq.append(1) +dq.append(2) +dq.append(3) + +# Removing elements from the deque +dq.popleft() # Removes and returns 1 +dq.pop() # Removes and returns 3 + +# Peeking elements +print("Left end peek:", dq[0]) +print("Right end peek:", dq[-1]) + +# Displaying elements in the deque +print("Deque:", list(dq)) +``` + +## Example: Sliding Window Maximum + +In this example, we'll use a deque to efficiently find the maximum element in sliding windows of a list. + +```python +from collections import deque + +def sliding_window_maximum(nums, k): + if not nums: + return [] + + n = len(nums) + result = [] + dq = deque() + + for i in range(n): + # Remove elements from the deque that are out of the current window + while dq and dq[0] <= i - k: + dq.popleft() + + # Remove elements from the deque that are less than the current element + while dq and nums[dq[-1]] <= nums[i]: + dq.pop() + + # Add the current element index to the deque + dq.append(i) + + # Add the maximum of the current window to the result + if i >= k - 1: + result.append(nums[dq[0]]) + + return result + +# Example usage: +nums = [1, 3, -1, -3, 5, 3, 6, 7] +k = 3 +print("Sliding Window Maximum:", sliding_window_maximum(nums, k)) +``` + +## Conclusion + +Queues and deques are fundamental data structures that facilitate efficient data processing and +management in various applications. Understanding their principles and implementations is crucial +for developing robust software solutions. \ No newline at end of file diff --git a/contrib/ds-algorithms/index.md b/contrib/ds-algorithms/index.md index 07fd98a..b156468 100644 --- a/contrib/ds-algorithms/index.md +++ b/contrib/ds-algorithms/index.md @@ -22,3 +22,4 @@ - [AVL Trees](avl-trees.md) - [Splay Trees](splay-trees.md) - [Dijkstra's Algorithm](dijkstra.md) +- [Deque](deque.md) \ No newline at end of file From fd466af7e0544ed31f8fc5d6d0c2529863ec0d32 Mon Sep 17 00:00:00 2001 From: mankalavaishnavi Date: Mon, 24 Jun 2024 13:27:00 +0530 Subject: [PATCH 2/3] added deque --- contrib/ds-algorithms/deque.md | 228 +++++++++++++++++++++------------ 1 file changed, 144 insertions(+), 84 deletions(-) diff --git a/contrib/ds-algorithms/deque.md b/contrib/ds-algorithms/deque.md index 459ac04..db489a8 100644 --- a/contrib/ds-algorithms/deque.md +++ b/contrib/ds-algorithms/deque.md @@ -1,108 +1,168 @@ -## Double-Ended Queue (Deque) +# Deque in Python -A double-ended queue (deque) supports insertion and deletion from both ends, making it a more versatile queue implementation. +## Definition +A deque, short for double-ended queue, is an ordered collection of items that allows rapid insertion and deletion at both ends. -### Input-Restricted Deque +## Syntax +In Python, deques are implemented in the collections module: -In an input-restricted deque, elements can only be inserted from one end while deletions can occur from both ends. - -### Output-Restricted Deque - -An output-restricted deque allows elements to be deleted from one end only, while insertions can be made from both ends. - -## Real Life Examples of Deques - -### Task Scheduling - -Deques are useful in task scheduling algorithms where tasks can be added to either end and processed accordingly based on priority or other scheduling criteria. - -### Sliding Window Problems - -Algorithms solving sliding window problems often use deques to efficiently manage and query elements in the current window. - -### Implementations in Python - -Python provides a built-in `collections.deque` which supports efficient append and pop operations from both ends. It's ideal for scenarios requiring a simple and efficient double-ended queue. - -## Operations on a Deque - -- **isEmpty**: Checks if the deque is empty. -- **appendLeft**: Adds an element to the left end of the deque. -- **appendRight**: Adds an element to the right end of the deque. -- **popLeft**: Removes and returns the element from the left end of the deque. -- **popRight**: Removes and returns the element from the right end of the deque. -- **peekLeft**: Returns the element from the left end without removing it. -- **peekRight**: Returns the element from the right end without removing it. -- **clear**: Removes all elements from the deque. - -## Implementation of Deque in Python - -Python's `collections.deque` provides an efficient implementation of a deque. - -```python +```py from collections import deque # Creating a deque -dq = deque() - -# Adding elements to the deque -dq.append(1) -dq.append(2) -dq.append(3) - -# Removing elements from the deque -dq.popleft() # Removes and returns 1 -dq.pop() # Removes and returns 3 - -# Peeking elements -print("Left end peek:", dq[0]) -print("Right end peek:", dq[-1]) - -# Displaying elements in the deque -print("Deque:", list(dq)) +d = deque(iterable) # Create deque from iterable (optional) ``` -## Example: Sliding Window Maximum +## Operations +1. **Appending Elements**: -In this example, we'll use a deque to efficiently find the maximum element in sliding windows of a list. + - append(x): Adds element x to the right end of the deque. + - appendleft(x): Adds element x to the left end of the deque. -```python +2. **Removing Elements**: + + - pop(): Removes and returns the rightmost element. + - popleft(): Removes and returns the leftmost element. + +3. **Accessing Elements**: + + - deque[index]: Accesses element at index. + +4. **Other Operations**: + + - extend(iterable): Extends deque by appending elements from iterable. + - extendleft(iterable): Extends deque by appending elements from iterable to the left. + - rotate(n): Rotates deque n steps to the right (negative n rotates left). + +## Example + +### 1. showing all the operations +```py from collections import deque -def sliding_window_maximum(nums, k): +# Initialize a deque +d = deque([1, 2, 3, 4, 5]) +print("Initial deque:", d) + +# Append elements +d.append(6) +print("After append(6):", d) + +# Append left +d.appendleft(0) +print("After appendleft(0):", d) + +# Pop from the right end +rightmost = d.pop() +print("Popped from right end:", rightmost) +print("Deque after pop():", d) + +# Pop from the left end +leftmost = d.popleft() +print("Popped from left end:", leftmost) +print("Deque after popleft():", d) + +# Accessing elements +print("Element at index 2:", d[2]) + +# Extend deque +d.extend([6, 7, 8]) +print("After extend([6, 7, 8]):", d) + +# Extend left +d.extendleft([-1, 0]) +print("After extendleft([-1, 0]):", d) + +# Rotate deque +d.rotate(2) +print("After rotate(2):", d) + +# Rotate left +d.rotate(-3) +print("After rotate(-3):", d) +``` +Output +```py +Initial deque: deque([1, 2, 3, 4, 5]) +After append(6): deque([1, 2, 3, 4, 5, 6]) +After appendleft(0): deque([0, 1, 2, 3, 4, 5, 6]) +Popped from right end: 6 +Deque after pop(): deque([0, 1, 2, 3, 4, 5]) +Popped from left end: 0 +Deque after popleft(): deque([1, 2, 3, 4, 5]) +Element at index 2: 3 +After extend([6, 7, 8]): deque([1, 2, 3, 4, 5, 6, 7, 8]) +After extendleft([-1, 0]): deque([0, -1, 1, 2, 3, 4, 5, 6, 7, 8]) +After rotate(2): deque([7, 8, 0, -1, 1, 2, 3, 4, 5, 6]) +After rotate(-3): deque([1, 2, 3, 4, 5, 6, 7, 8, 0, -1]) + +``` + +### 2. Finding Maximum in Sliding Window +```py +from collections import deque + +def max_sliding_window(nums, k): if not nums: return [] - - n = len(nums) + + d = deque() result = [] - dq = deque() - - for i in range(n): - # Remove elements from the deque that are out of the current window - while dq and dq[0] <= i - k: - dq.popleft() - - # Remove elements from the deque that are less than the current element - while dq and nums[dq[-1]] <= nums[i]: - dq.pop() - - # Add the current element index to the deque - dq.append(i) - - # Add the maximum of the current window to the result + + for i, num in enumerate(nums): + # Remove elements from deque that are out of the current window + if d and d[0] <= i - k: + d.popleft() + + # Remove elements from deque smaller than the current element + while d and nums[d[-1]] <= num: + d.pop() + + d.append(i) + + # Add maximum for current window if i >= k - 1: - result.append(nums[dq[0]]) - + result.append(nums[d[0]]) + return result # Example usage: nums = [1, 3, -1, -3, 5, 3, 6, 7] k = 3 -print("Sliding Window Maximum:", sliding_window_maximum(nums, k)) +print("Maximums in sliding window of size", k, "are:", max_sliding_window(nums, k)) + ``` -## Conclusion +Output +```py +Maximums in sliding window of size 3 are: [3, 3, 5, 5, 6, 7] +``` -Queues and deques are fundamental data structures that facilitate efficient data processing and -management in various applications. Understanding their principles and implementations is crucial -for developing robust software solutions. \ No newline at end of file + +## Applications +- **Efficient Queues and Stacks**: Deques allow fast O(1) append and pop operations from both ends, +making them ideal for implementing queues and stacks. +- **Sliding Window Maximum/Minimum**: Used in algorithms that require efficient windowed +computations. + + +## Advantages +- Efficiency: O(1) time complexity for append and pop operations from both ends. +- Versatility: Can function both as a queue and as a stack. +- Flexible: Supports rotation and slicing operations efficiently. + + +## Disadvantages +- Memory Usage: Requires more memory compared to simple lists due to overhead in managing linked +nodes. + +## Conclusion +- Deques in Python, provided by the collections.deque module, offer efficient double-ended queue +operations with O(1) time complexity for append and pop operations on both ends. They are versatile +data structures suitable for implementing queues, stacks, and more complex algorithms requiring +efficient manipulation of elements at both ends. + +- While deques excel in scenarios requiring fast append and pop operations from either end, they do +consume more memory compared to simple lists due to their implementation using doubly-linked lists. +However, their flexibility and efficiency make them invaluable for various programming tasks and +algorithmic solutions. \ No newline at end of file From 1954374803a806c58c96c192b1d0621176bb257a Mon Sep 17 00:00:00 2001 From: mankalavaishnavi Date: Thu, 27 Jun 2024 20:00:20 +0530 Subject: [PATCH 3/3] changes as per request --- contrib/ds-algorithms/deque.md | 174 +++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 63 deletions(-) diff --git a/contrib/ds-algorithms/deque.md b/contrib/ds-algorithms/deque.md index db489a8..2a5a77d 100644 --- a/contrib/ds-algorithms/deque.md +++ b/contrib/ds-algorithms/deque.md @@ -19,86 +19,134 @@ d = deque(iterable) # Create deque from iterable (optional) - append(x): Adds element x to the right end of the deque. - appendleft(x): Adds element x to the left end of the deque. + ### Program + ```py + from collections import deque + + # Initialize a deque + d = deque([1, 2, 3, 4, 5]) + print("Initial deque:", d) + + # Append elements + d.append(6) + print("After append(6):", d) + + # Append left + d.appendleft(0) + print("After appendleft(0):", d) + + ``` + ### Output + ```py + Initial deque: deque([1, 2, 3, 4, 5]) + After append(6): deque([1, 2, 3, 4, 5, 6]) + After appendleft(0): deque([0, 1, 2, 3, 4, 5, 6]) + ``` + 2. **Removing Elements**: - pop(): Removes and returns the rightmost element. - popleft(): Removes and returns the leftmost element. + ### Program + ```py + from collections import deque + + # Initialize a deque + d = deque([1, 2, 3, 4, 5]) + print("Initial deque:", d) + + # Pop from the right end + rightmost = d.pop() + print("Popped from right end:", rightmost) + print("Deque after pop():", d) + + # Pop from the left end + leftmost = d.popleft() + print("Popped from left end:", leftmost) + print("Deque after popleft():", d) + + ``` + + ### Output + ```py + Initial deque: deque([1, 2, 3, 4, 5]) + Popped from right end: 5 + Deque after pop(): deque([1, 2, 3, 4]) + Popped from left end: 1 + Deque after popleft(): deque([2, 3, 4]) + ``` + 3. **Accessing Elements**: - deque[index]: Accesses element at index. + ### Program + ```py + from collections import deque + + # Initialize a deque + d = deque([1, 2, 3, 4, 5]) + print("Initial deque:", d) + + # Accessing elements + print("Element at index 2:", d[2]) + + ``` + + ### Output + ```py + Initial deque: deque([1, 2, 3, 4, 5]) + Element at index 2: 3 + + ``` + 4. **Other Operations**: - extend(iterable): Extends deque by appending elements from iterable. - extendleft(iterable): Extends deque by appending elements from iterable to the left. - rotate(n): Rotates deque n steps to the right (negative n rotates left). + ### Program + ```py + from collections import deque + + # Initialize a deque + d = deque([1, 2, 3, 4, 5]) + print("Initial deque:", d) + + # Extend deque + d.extend([6, 7, 8]) + print("After extend([6, 7, 8]):", d) + + # Extend left + d.extendleft([-1, 0]) + print("After extendleft([-1, 0]):", d) + + # Rotate deque + d.rotate(2) + print("After rotate(2):", d) + + # Rotate left + d.rotate(-3) + print("After rotate(-3):", d) + + ``` + + ### Output + ```py + Initial deque: deque([1, 2, 3, 4, 5]) + After extend([6, 7, 8]): deque([1, 2, 3, 4, 5, 6, 7, 8]) + After extendleft([-1, 0]): deque([0, -1, 1, 2, 3, 4, 5, 6, 7, 8]) + After rotate(2): deque([7, 8, 0, -1, 1, 2, 3, 4, 5, 6]) + After rotate(-3): deque([1, 2, 3, 4, 5, 6, 7, 8, 0, -1]) + + ``` + + ## Example -### 1. showing all the operations -```py -from collections import deque - -# Initialize a deque -d = deque([1, 2, 3, 4, 5]) -print("Initial deque:", d) - -# Append elements -d.append(6) -print("After append(6):", d) - -# Append left -d.appendleft(0) -print("After appendleft(0):", d) - -# Pop from the right end -rightmost = d.pop() -print("Popped from right end:", rightmost) -print("Deque after pop():", d) - -# Pop from the left end -leftmost = d.popleft() -print("Popped from left end:", leftmost) -print("Deque after popleft():", d) - -# Accessing elements -print("Element at index 2:", d[2]) - -# Extend deque -d.extend([6, 7, 8]) -print("After extend([6, 7, 8]):", d) - -# Extend left -d.extendleft([-1, 0]) -print("After extendleft([-1, 0]):", d) - -# Rotate deque -d.rotate(2) -print("After rotate(2):", d) - -# Rotate left -d.rotate(-3) -print("After rotate(-3):", d) -``` -Output -```py -Initial deque: deque([1, 2, 3, 4, 5]) -After append(6): deque([1, 2, 3, 4, 5, 6]) -After appendleft(0): deque([0, 1, 2, 3, 4, 5, 6]) -Popped from right end: 6 -Deque after pop(): deque([0, 1, 2, 3, 4, 5]) -Popped from left end: 0 -Deque after popleft(): deque([1, 2, 3, 4, 5]) -Element at index 2: 3 -After extend([6, 7, 8]): deque([1, 2, 3, 4, 5, 6, 7, 8]) -After extendleft([-1, 0]): deque([0, -1, 1, 2, 3, 4, 5, 6, 7, 8]) -After rotate(2): deque([7, 8, 0, -1, 1, 2, 3, 4, 5, 6]) -After rotate(-3): deque([1, 2, 3, 4, 5, 6, 7, 8, 0, -1]) - -``` - -### 2. Finding Maximum in Sliding Window +### 1. Finding Maximum in Sliding Window ```py from collections import deque