diff --git a/Algorithms.Tests/Other/KadanesAlgorithmTests.cs b/Algorithms.Tests/Other/KadanesAlgorithmTests.cs
new file mode 100644
index 00000000..9a3170d0
--- /dev/null
+++ b/Algorithms.Tests/Other/KadanesAlgorithmTests.cs
@@ -0,0 +1,216 @@
+using Algorithms.Other;
+using NUnit.Framework;
+using System;
+
+namespace Algorithms.Tests.Other;
+
+///
+/// Comprehensive test suite for Kadane's Algorithm implementation.
+/// Tests cover various scenarios including:
+/// - Arrays with all positive numbers
+/// - Arrays with mixed positive and negative numbers
+/// - Arrays with all negative numbers
+/// - Edge cases (single element, empty array, null array)
+/// - Index tracking functionality
+/// - Long integer support for large numbers
+///
+public static class KadanesAlgorithmTests
+{
+ [Test]
+ public static void FindMaximumSubarraySum_WithPositiveNumbers_ReturnsCorrectSum()
+ {
+ // Arrange: When all numbers are positive, the entire array is the maximum subarray
+ int[] array = { 1, 2, 3, 4, 5 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Sum of all elements = 1 + 2 + 3 + 4 + 5 = 15
+ Assert.That(result, Is.EqualTo(15));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithMixedNumbers_ReturnsCorrectSum()
+ {
+ // Arrange: Classic example with mixed positive and negative numbers
+ // The maximum subarray is [4, -1, 2, 1] starting at index 3
+ int[] array = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Maximum sum is 4 + (-1) + 2 + 1 = 6
+ Assert.That(result, Is.EqualTo(6)); // Subarray [4, -1, 2, 1]
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithAllNegativeNumbers_ReturnsLargestNegative()
+ {
+ // Arrange: When all numbers are negative, the algorithm returns the least negative number
+ // This represents a subarray of length 1 containing the largest (least negative) element
+ int[] array = { -5, -2, -8, -1, -4 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: -1 is the largest (least negative) number in the array
+ Assert.That(result, Is.EqualTo(-1));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithSingleElement_ReturnsThatElement()
+ {
+ // Arrange: Edge case with only one element
+ // The only possible subarray is the element itself
+ int[] array = { 42 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: The single element is both the subarray and its sum
+ Assert.That(result, Is.EqualTo(42));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithNullArray_ThrowsArgumentException()
+ {
+ // Arrange: Test defensive programming - null input validation
+ int[]? array = null;
+
+ // Act & Assert: Should throw ArgumentException for null input
+ Assert.Throws(() => KadanesAlgorithm.FindMaximumSubarraySum(array!));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithEmptyArray_ThrowsArgumentException()
+ {
+ // Arrange
+ int[] array = Array.Empty();
+
+ // Act & Assert
+ Assert.Throws(() => KadanesAlgorithm.FindMaximumSubarraySum(array));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithAlternatingNumbers_ReturnsCorrectSum()
+ {
+ // Arrange: Alternating positive and negative numbers
+ // Despite negative values, the entire array gives the maximum sum
+ int[] array = { 5, -3, 5, -3, 5 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Sum of entire array = 5 - 3 + 5 - 3 + 5 = 9
+ Assert.That(result, Is.EqualTo(9)); // Entire array
+ }
+
+ [Test]
+ public static void FindMaximumSubarrayWithIndices_ReturnsCorrectIndices()
+ {
+ // Arrange: Test the variant that returns indices of the maximum subarray
+ // Array: [-2, 1, -3, 4, -1, 2, 1, -5, 4]
+ // Index: 0 1 2 3 4 5 6 7 8
+ int[] array = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
+
+ // Act
+ var (maxSum, startIndex, endIndex) = KadanesAlgorithm.FindMaximumSubarrayWithIndices(array);
+
+ // Assert: Maximum subarray is [4, -1, 2, 1] from index 3 to 6
+ Assert.That(maxSum, Is.EqualTo(6));
+ Assert.That(startIndex, Is.EqualTo(3));
+ Assert.That(endIndex, Is.EqualTo(6));
+ }
+
+ [Test]
+ public static void FindMaximumSubarrayWithIndices_WithSingleElement_ReturnsZeroIndices()
+ {
+ // Arrange
+ int[] array = { 10 };
+
+ // Act
+ var (maxSum, startIndex, endIndex) = KadanesAlgorithm.FindMaximumSubarrayWithIndices(array);
+
+ // Assert
+ Assert.That(maxSum, Is.EqualTo(10));
+ Assert.That(startIndex, Is.EqualTo(0));
+ Assert.That(endIndex, Is.EqualTo(0));
+ }
+
+ [Test]
+ public static void FindMaximumSubarrayWithIndices_WithNullArray_ThrowsArgumentException()
+ {
+ // Arrange
+ int[]? array = null;
+
+ // Act & Assert
+ Assert.Throws(() => KadanesAlgorithm.FindMaximumSubarrayWithIndices(array!));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithLongArray_ReturnsCorrectSum()
+ {
+ // Arrange: Test the long integer overload with same values as int test
+ // Verifies that the algorithm works correctly with long data type
+ long[] array = { -2L, 1L, -3L, 4L, -1L, 2L, 1L, -5L, 4L };
+
+ // Act
+ long result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Should produce same result as int version
+ Assert.That(result, Is.EqualTo(6L));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithLargeLongNumbers_ReturnsCorrectSum()
+ {
+ // Arrange: Test with large numbers that would overflow int type
+ // This demonstrates why the long overload is necessary
+ // Sum would be 1,500,000,000 which fits in long but is near int.MaxValue
+ long[] array = { 1000000000L, -500000000L, 1000000000L };
+
+ // Act
+ long result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Entire array sum = 1,000,000,000 - 500,000,000 + 1,000,000,000 = 1,500,000,000
+ Assert.That(result, Is.EqualTo(1500000000L));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithLongNullArray_ThrowsArgumentException()
+ {
+ // Arrange
+ long[]? array = null;
+
+ // Act & Assert
+ Assert.Throws(() => KadanesAlgorithm.FindMaximumSubarraySum(array!));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithZeros_ReturnsZero()
+ {
+ // Arrange: Edge case with all zeros
+ // Any subarray will have sum of 0
+ int[] array = { 0, 0, 0, 0 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Maximum sum is 0
+ Assert.That(result, Is.EqualTo(0));
+ }
+
+ [Test]
+ public static void FindMaximumSubarraySum_WithMixedZerosAndNegatives_ReturnsZero()
+ {
+ // Arrange: Mix of zeros and negative numbers
+ // The best subarray is any single zero (or multiple zeros)
+ int[] array = { -5, 0, -3, 0, -2 };
+
+ // Act
+ int result = KadanesAlgorithm.FindMaximumSubarraySum(array);
+
+ // Assert: Zero is better than any negative number
+ Assert.That(result, Is.EqualTo(0));
+ }
+}
diff --git a/Algorithms/Other/KadanesAlgorithm.cs b/Algorithms/Other/KadanesAlgorithm.cs
new file mode 100644
index 00000000..67287d27
--- /dev/null
+++ b/Algorithms/Other/KadanesAlgorithm.cs
@@ -0,0 +1,147 @@
+namespace Algorithms.Other;
+
+///
+/// Kadane's Algorithm is used to find the maximum sum of a contiguous subarray
+/// within a one-dimensional array of numbers. It has a time complexity of O(n).
+/// This algorithm is a classic example of dynamic programming.
+/// Reference: "Introduction to Algorithms" by Cormen, Leiserson, Rivest, and Stein (CLRS).
+///
+public static class KadanesAlgorithm
+{
+ ///
+ /// Finds the maximum sum of a contiguous subarray using Kadane's Algorithm.
+ /// The algorithm works by maintaining two variables:
+ /// - maxSoFar: The maximum sum found so far (global maximum)
+ /// - maxEndingHere: The maximum sum of subarray ending at current position (local maximum)
+ /// At each position, we decide whether to extend the existing subarray or start a new one.
+ ///
+ /// The input array of integers.
+ /// The maximum sum of a contiguous subarray.
+ /// Thrown when the input array is null or empty.
+ ///
+ /// Input: [-2, 1, -3, 4, -1, 2, 1, -5, 4].
+ /// Output: 6 (subarray [4, -1, 2, 1]).
+ ///
+ public static int FindMaximumSubarraySum(int[] array)
+ {
+ // Validate input to ensure array is not null or empty
+ if (array == null || array.Length == 0)
+ {
+ throw new ArgumentException("Array cannot be null or empty.", nameof(array));
+ }
+
+ // Initialize both variables with the first element
+ // maxSoFar tracks the best sum we've seen across all subarrays
+ int maxSoFar = array[0];
+
+ // maxEndingHere tracks the best sum ending at the current position
+ int maxEndingHere = array[0];
+
+ // Iterate through the array starting from the second element
+ for (int i = 1; i < array.Length; i++)
+ {
+ // Key decision: Either extend the current subarray or start fresh
+ // If adding current element to existing sum is worse than the element alone,
+ // it's better to start a new subarray from current element
+ maxEndingHere = Math.Max(array[i], maxEndingHere + array[i]);
+
+ // Update the global maximum if current subarray sum is better
+ maxSoFar = Math.Max(maxSoFar, maxEndingHere);
+ }
+
+ return maxSoFar;
+ }
+
+ ///
+ /// Finds the maximum sum of a contiguous subarray and returns the start and end indices.
+ /// This variant tracks the indices of the maximum subarray in addition to the sum.
+ /// Useful when you need to know which elements form the maximum subarray.
+ ///
+ /// The input array of integers.
+ /// A tuple containing the maximum sum, start index, and end index.
+ /// Thrown when the input array is null or empty.
+ ///
+ /// Input: [-2, 1, -3, 4, -1, 2, 1, -5, 4].
+ /// Output: (MaxSum: 6, StartIndex: 3, EndIndex: 6).
+ /// The subarray is [4, -1, 2, 1].
+ ///
+ public static (int MaxSum, int StartIndex, int EndIndex) FindMaximumSubarrayWithIndices(int[] array)
+ {
+ // Validate input
+ if (array == null || array.Length == 0)
+ {
+ throw new ArgumentException("Array cannot be null or empty.", nameof(array));
+ }
+
+ // Initialize tracking variables
+ int maxSoFar = array[0]; // Global maximum sum
+ int maxEndingHere = array[0]; // Local maximum sum ending at current position
+ int start = 0; // Start index of the maximum subarray
+ int end = 0; // End index of the maximum subarray
+ int tempStart = 0; // Temporary start index for current subarray
+
+ // Process each element starting from index 1
+ for (int i = 1; i < array.Length; i++)
+ {
+ // Decide whether to extend current subarray or start a new one
+ if (array[i] > maxEndingHere + array[i])
+ {
+ // Starting fresh from current element is better
+ maxEndingHere = array[i];
+ tempStart = i; // Mark this as potential start of new subarray
+ }
+ else
+ {
+ // Extending the current subarray is better
+ maxEndingHere = maxEndingHere + array[i];
+ }
+
+ // Update global maximum and indices if we found a better subarray
+ if (maxEndingHere > maxSoFar)
+ {
+ maxSoFar = maxEndingHere;
+ start = tempStart; // Commit the start index
+ end = i; // Current position is the end
+ }
+ }
+
+ return (maxSoFar, start, end);
+ }
+
+ ///
+ /// Finds the maximum sum of a contiguous subarray using Kadane's Algorithm for long integers.
+ /// This overload handles larger numbers that exceed int range (up to 2^63 - 1).
+ /// The algorithm logic is identical to the int version but uses long arithmetic.
+ ///
+ /// The input array of long integers.
+ /// The maximum sum of a contiguous subarray.
+ /// Thrown when the input array is null or empty.
+ ///
+ /// Input: [1000000000L, -500000000L, 1000000000L].
+ /// Output: 1500000000L (entire array).
+ ///
+ public static long FindMaximumSubarraySum(long[] array)
+ {
+ // Validate input
+ if (array == null || array.Length == 0)
+ {
+ throw new ArgumentException("Array cannot be null or empty.", nameof(array));
+ }
+
+ // Initialize with first element (using long arithmetic)
+ long maxSoFar = array[0];
+ long maxEndingHere = array[0];
+
+ // Apply Kadane's algorithm with long values
+ for (int i = 1; i < array.Length; i++)
+ {
+ // Decide: extend current subarray or start new one
+ maxEndingHere = Math.Max(array[i], maxEndingHere + array[i]);
+
+ // Update global maximum
+ maxSoFar = Math.Max(maxSoFar, maxEndingHere);
+ }
+
+ return maxSoFar;
+ }
+}
diff --git a/DataStructures.Tests/Deque/DequeTests.cs b/DataStructures.Tests/Deque/DequeTests.cs
new file mode 100644
index 00000000..1652d7d9
--- /dev/null
+++ b/DataStructures.Tests/Deque/DequeTests.cs
@@ -0,0 +1,383 @@
+using DataStructures.Deque;
+using NUnit.Framework;
+using System;
+using System.Linq;
+
+namespace DataStructures.Tests.Deque;
+
+///
+/// Comprehensive test suite for the Deque (Double-Ended Queue) data structure.
+/// Tests cover:
+/// - Constructor validation and initialization
+/// - Basic operations (AddFront, AddRear, RemoveFront, RemoveRear)
+/// - Peek operations (non-destructive reads)
+/// - Edge cases (empty deque, single element, capacity overflow)
+/// - Type flexibility (int, string, tuples)
+/// - Circular array behavior and automatic resizing
+/// - Mixed operations maintaining correct order
+///
+public static class DequeTests
+{
+ [Test]
+ public static void Constructor_WithDefaultCapacity_CreatesEmptyDeque()
+ {
+ // Arrange & Act: Create deque with default capacity (16)
+ var deque = new Deque();
+
+ // Assert: Should be empty initially
+ Assert.That(deque.Count, Is.EqualTo(0));
+ Assert.That(deque.IsEmpty, Is.True);
+ }
+
+ [Test]
+ public static void Constructor_WithSpecifiedCapacity_CreatesEmptyDeque()
+ {
+ // Arrange & Act
+ var deque = new Deque(10);
+
+ // Assert
+ Assert.That(deque.Count, Is.EqualTo(0));
+ Assert.That(deque.IsEmpty, Is.True);
+ }
+
+ [Test]
+ public static void Constructor_WithInvalidCapacity_ThrowsArgumentException()
+ {
+ // Arrange, Act & Assert: Capacity must be at least 1
+ // Zero capacity should throw
+ Assert.Throws(() => new Deque(0));
+ // Negative capacity should throw
+ Assert.Throws(() => new Deque(-1));
+ }
+
+ [Test]
+ public static void AddFront_AddsElementToFront()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act: Add elements to front (each becomes new front)
+ deque.AddFront(1); // Deque: [1]
+ deque.AddFront(2); // Deque: [2, 1]
+ deque.AddFront(3); // Deque: [3, 2, 1]
+
+ // Assert: Most recently added element should be at front
+ Assert.That(deque.Count, Is.EqualTo(3));
+ Assert.That(deque.PeekFront(), Is.EqualTo(3));
+ }
+
+ [Test]
+ public static void AddRear_AddsElementToRear()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Assert
+ Assert.That(deque.Count, Is.EqualTo(3));
+ Assert.That(deque.PeekRear(), Is.EqualTo(3));
+ }
+
+ [Test]
+ public static void RemoveFront_RemovesAndReturnsElementFromFront()
+ {
+ // Arrange: Build deque [1, 2, 3]
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Act: Remove front element
+ int result = deque.RemoveFront();
+
+ // Assert: Should return 1 and deque becomes [2, 3]
+ Assert.That(result, Is.EqualTo(1));
+ Assert.That(deque.Count, Is.EqualTo(2));
+ Assert.That(deque.PeekFront(), Is.EqualTo(2));
+ }
+
+ [Test]
+ public static void RemoveRear_RemovesAndReturnsElementFromRear()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Act
+ int result = deque.RemoveRear();
+
+ // Assert
+ Assert.That(result, Is.EqualTo(3));
+ Assert.That(deque.Count, Is.EqualTo(2));
+ Assert.That(deque.PeekRear(), Is.EqualTo(2));
+ }
+
+ [Test]
+ public static void RemoveFront_OnEmptyDeque_ThrowsInvalidOperationException()
+ {
+ // Arrange: Create empty deque
+ var deque = new Deque();
+
+ // Act & Assert: Cannot remove from empty deque
+ Assert.Throws(() => deque.RemoveFront());
+ }
+
+ [Test]
+ public static void RemoveRear_OnEmptyDeque_ThrowsInvalidOperationException()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act & Assert
+ Assert.Throws(() => deque.RemoveRear());
+ }
+
+ [Test]
+ public static void PeekFront_ReturnsElementWithoutRemoving()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+
+ // Act
+ int result = deque.PeekFront();
+
+ // Assert
+ Assert.That(result, Is.EqualTo(1));
+ Assert.That(deque.Count, Is.EqualTo(2));
+ }
+
+ [Test]
+ public static void PeekRear_ReturnsElementWithoutRemoving()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+
+ // Act
+ int result = deque.PeekRear();
+
+ // Assert
+ Assert.That(result, Is.EqualTo(2));
+ Assert.That(deque.Count, Is.EqualTo(2));
+ }
+
+ [Test]
+ public static void PeekFront_OnEmptyDeque_ThrowsInvalidOperationException()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act & Assert
+ Assert.Throws(() => deque.PeekFront());
+ }
+
+ [Test]
+ public static void PeekRear_OnEmptyDeque_ThrowsInvalidOperationException()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act & Assert
+ Assert.Throws(() => deque.PeekRear());
+ }
+
+ [Test]
+ public static void Clear_RemovesAllElements()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Act
+ deque.Clear();
+
+ // Assert
+ Assert.That(deque.Count, Is.EqualTo(0));
+ Assert.That(deque.IsEmpty, Is.True);
+ }
+
+ [Test]
+ public static void ToArray_ReturnsElementsInCorrectOrder()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Act
+ int[] result = deque.ToArray();
+
+ // Assert
+ Assert.That(result, Is.EqualTo(new[] { 1, 2, 3 }));
+ }
+
+ [Test]
+ public static void ToArray_WithMixedOperations_ReturnsCorrectOrder()
+ {
+ // Arrange: Build deque using both front and rear operations
+ var deque = new Deque();
+ deque.AddFront(2); // Deque: [2]
+ deque.AddFront(1); // Deque: [1, 2]
+ deque.AddRear(3); // Deque: [1, 2, 3]
+ deque.AddRear(4); // Deque: [1, 2, 3, 4]
+
+ // Act
+ int[] result = deque.ToArray();
+
+ // Assert: Array should maintain front-to-rear order
+ Assert.That(result, Is.EqualTo(new[] { 1, 2, 3, 4 }));
+ }
+
+ [Test]
+ public static void Contains_WithExistingElement_ReturnsTrue()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Act
+ bool result = deque.Contains(2);
+
+ // Assert
+ Assert.That(result, Is.True);
+ }
+
+ [Test]
+ public static void Contains_WithNonExistingElement_ReturnsFalse()
+ {
+ // Arrange
+ var deque = new Deque();
+ deque.AddRear(1);
+ deque.AddRear(2);
+ deque.AddRear(3);
+
+ // Act
+ bool result = deque.Contains(5);
+
+ // Assert
+ Assert.That(result, Is.False);
+ }
+
+ [Test]
+ public static void Deque_WithStringType_WorksCorrectly()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act
+ deque.AddRear("Hello");
+ deque.AddFront("World");
+ deque.AddRear("!");
+
+ // Assert
+ Assert.That(deque.Count, Is.EqualTo(3));
+ Assert.That(deque.PeekFront(), Is.EqualTo("World"));
+ Assert.That(deque.PeekRear(), Is.EqualTo("!"));
+ }
+
+ [Test]
+ public static void Deque_AutomaticallyResizes_WhenCapacityExceeded()
+ {
+ // Arrange: Create deque with small capacity of 2
+ var deque = new Deque(2);
+
+ // Act: Add more elements than initial capacity
+ deque.AddRear(1); // Capacity: 2, Count: 1
+ deque.AddRear(2); // Capacity: 2, Count: 2 (full)
+ deque.AddRear(3); // Should trigger resize to capacity 4, Count: 3
+ deque.AddRear(4); // Capacity: 4, Count: 4
+
+ // Assert: All elements should be present in correct order
+ Assert.That(deque.Count, Is.EqualTo(4));
+ Assert.That(deque.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4 }));
+ }
+
+ [Test]
+ public static void Deque_MixedOperations_MaintainsCorrectOrder()
+ {
+ // Arrange
+ var deque = new Deque();
+
+ // Act: Perform complex sequence of operations
+ deque.AddRear(3); // Deque: [3]
+ deque.AddFront(2); // Deque: [2, 3]
+ deque.AddFront(1); // Deque: [1, 2, 3]
+ deque.AddRear(4); // Deque: [1, 2, 3, 4]
+ deque.RemoveFront(); // Deque: [2, 3, 4] (removed 1)
+ deque.RemoveRear(); // Deque: [2, 3] (removed 4)
+ deque.AddRear(5); // Deque: [2, 3, 5]
+
+ // Assert: Final order should be correct after all operations
+ Assert.That(deque.ToArray(), Is.EqualTo(new[] { 2, 3, 5 }));
+ }
+
+ [Test]
+ public static void Deque_WithComplexType_WorksCorrectly()
+ {
+ // Arrange
+ var deque = new Deque<(int, string)>();
+
+ // Act
+ deque.AddRear((1, "One"));
+ deque.AddRear((2, "Two"));
+ deque.AddFront((0, "Zero"));
+
+ // Assert
+ Assert.That(deque.Count, Is.EqualTo(3));
+ Assert.That(deque.PeekFront(), Is.EqualTo((0, "Zero")));
+ Assert.That(deque.PeekRear(), Is.EqualTo((2, "Two")));
+ }
+
+ [Test]
+ public static void Deque_AfterMultipleResizes_MaintainsIntegrity()
+ {
+ // Arrange: Start with very small capacity
+ var deque = new Deque(2);
+
+ // Act: Add many elements to trigger multiple resizes
+ // Capacity progression: 2 -> 4 -> 8 -> 16 -> 32 -> 64 -> 128
+ for (int i = 0; i < 100; i++)
+ {
+ deque.AddRear(i);
+ }
+
+ // Assert: All elements should be intact after multiple resizes
+ Assert.That(deque.Count, Is.EqualTo(100));
+ Assert.That(deque.PeekFront(), Is.EqualTo(0));
+ Assert.That(deque.PeekRear(), Is.EqualTo(99));
+ Assert.That(deque.ToArray(), Is.EqualTo(Enumerable.Range(0, 100).ToArray()));
+ }
+
+ [Test]
+ public static void Deque_CircularBehavior_WorksCorrectly()
+ {
+ // Arrange: Create deque with capacity 4
+ var deque = new Deque(4);
+
+ // Act: Test circular wrap-around behavior
+ deque.AddRear(1); // Internal: [1, _, _, _], front=0, rear=1
+ deque.AddRear(2); // Internal: [1, 2, _, _], front=0, rear=2
+ deque.RemoveFront(); // Internal: [_, 2, _, _], front=1, rear=2
+ deque.RemoveFront(); // Internal: [_, _, _, _], front=2, rear=2
+ deque.AddRear(3); // Internal: [_, _, 3, _], front=2, rear=3
+ deque.AddRear(4); // Internal: [_, _, 3, 4], front=2, rear=0 (wrapped)
+ deque.AddRear(5); // Internal: [5, _, 3, 4], front=2, rear=1 (wrapped)
+
+ // Assert: Elements should be in correct logical order despite circular storage
+ Assert.That(deque.ToArray(), Is.EqualTo(new[] { 3, 4, 5 }));
+ }
+}
diff --git a/DataStructures/Deque/Deque.cs b/DataStructures/Deque/Deque.cs
new file mode 100644
index 00000000..48544ad8
--- /dev/null
+++ b/DataStructures/Deque/Deque.cs
@@ -0,0 +1,332 @@
+namespace DataStructures.Deque;
+
+///
+/// Implementation of a Deque (Double-Ended Queue) data structure.
+/// A deque allows insertion and deletion of elements from both ends (front and rear).
+/// This implementation uses a circular array for efficient operations.
+///
+/// Key Features:
+/// - O(1) time complexity for AddFront, AddRear, RemoveFront, RemoveRear operations
+/// - O(1) amortized time for insertions (due to dynamic resizing)
+/// - Space efficient with circular array implementation
+/// - Automatic capacity doubling when full
+///
+/// Use Cases:
+/// - Implementing sliding window algorithms
+/// - Palindrome checking
+/// - Undo/Redo functionality
+/// - Task scheduling with priority at both ends
+///
+/// Reference: "Data Structures and Algorithms in C#" by Michael T. Goodrich.
+///
+/// The type of elements in the deque.
+public class Deque
+{
+ // Internal circular array to store elements
+ private T[] items;
+
+ // Index of the front element (next element to remove from front)
+ private int front;
+
+ // Index where the next element will be added at rear
+ private int rear;
+
+ // Current number of elements in the deque
+ private int count;
+
+ ///
+ /// Initializes a new instance of the class with default capacity.
+ /// Default capacity is 16 elements, which provides a good balance between
+ /// memory usage and avoiding early resizing for typical use cases.
+ ///
+ public Deque()
+ : this(16)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with specified capacity.
+ ///
+ /// The initial capacity of the deque.
+ /// Thrown when capacity is less than 1.
+ public Deque(int capacity)
+ {
+ if (capacity < 1)
+ {
+ throw new ArgumentException("Capacity must be at least 1.", nameof(capacity));
+ }
+
+ items = new T[capacity];
+ front = 0;
+ rear = 0;
+ count = 0;
+ }
+
+ ///
+ /// Gets the number of elements in the deque.
+ ///
+ public int Count => count;
+
+ ///
+ /// Gets a value indicating whether the deque is empty.
+ ///
+ public bool IsEmpty => count == 0;
+
+ ///
+ /// Adds an element to the front of the deque.
+ /// This operation is O(1) time complexity (amortized due to occasional resizing).
+ ///
+ /// The item to add.
+ ///
+ /// deque.AddFront(5); // Deque: [5].
+ /// deque.AddFront(3); // Deque: [3, 5].
+ ///
+ public void AddFront(T item)
+ {
+ // Check if we need to resize before adding
+ if (count == items.Length)
+ {
+ Resize();
+ }
+
+ // Move front pointer backward in circular fashion
+ // Adding items.Length ensures the result is always positive
+ front = (front - 1 + items.Length) % items.Length;
+ items[front] = item;
+ count++;
+ }
+
+ ///
+ /// Adds an element to the rear of the deque.
+ /// This operation is O(1) time complexity (amortized due to occasional resizing).
+ ///
+ /// The item to add.
+ ///
+ /// deque.AddRear(5); // Deque: [5].
+ /// deque.AddRear(7); // Deque: [5, 7].
+ ///
+ public void AddRear(T item)
+ {
+ // Check if we need to resize before adding
+ if (count == items.Length)
+ {
+ Resize();
+ }
+
+ // Add item at rear position
+ items[rear] = item;
+
+ // Move rear pointer forward in circular fashion
+ rear = (rear + 1) % items.Length;
+ count++;
+ }
+
+ ///
+ /// Removes and returns the element at the front of the deque.
+ /// This operation is O(1) time complexity.
+ ///
+ /// The element at the front of the deque.
+ /// Thrown when the deque is empty.
+ ///
+ /// // Deque: [3, 5, 7].
+ /// int value = deque.RemoveFront(); // Returns 3, Deque: [5, 7].
+ ///
+ public T RemoveFront()
+ {
+ // Validate that deque is not empty
+ if (IsEmpty)
+ {
+ throw new InvalidOperationException("Deque is empty.");
+ }
+
+ // Retrieve the front element
+ T item = items[front];
+
+ // Clear the reference to help garbage collection
+ items[front] = default!;
+
+ // Move front pointer forward in circular fashion
+ front = (front + 1) % items.Length;
+ count--;
+
+ return item;
+ }
+
+ ///
+ /// Removes and returns the element at the rear of the deque.
+ /// This operation is O(1) time complexity.
+ ///
+ /// The element at the rear of the deque.
+ /// Thrown when the deque is empty.
+ ///
+ /// // Deque: [3, 5, 7].
+ /// int value = deque.RemoveRear(); // Returns 7, Deque: [3, 5].
+ ///
+ public T RemoveRear()
+ {
+ // Validate that deque is not empty
+ if (IsEmpty)
+ {
+ throw new InvalidOperationException("Deque is empty.");
+ }
+
+ // Move rear pointer backward to the last element
+ rear = (rear - 1 + items.Length) % items.Length;
+
+ // Retrieve the rear element
+ T item = items[rear];
+
+ // Clear the reference to help garbage collection
+ items[rear] = default!;
+ count--;
+
+ return item;
+ }
+
+ ///
+ /// Returns the element at the front of the deque without removing it.
+ /// This operation is O(1) time complexity and does not modify the deque.
+ ///
+ /// The element at the front of the deque.
+ /// Thrown when the deque is empty.
+ ///
+ /// // Deque: [3, 5, 7].
+ /// int value = deque.PeekFront(); // Returns 3, Deque unchanged: [3, 5, 7].
+ ///
+ public T PeekFront()
+ {
+ // Validate that deque is not empty
+ if (IsEmpty)
+ {
+ throw new InvalidOperationException("Deque is empty.");
+ }
+
+ return items[front];
+ }
+
+ ///
+ /// Returns the element at the rear of the deque without removing it.
+ /// This operation is O(1) time complexity and does not modify the deque.
+ ///
+ /// The element at the rear of the deque.
+ /// Thrown when the deque is empty.
+ ///
+ /// // Deque: [3, 5, 7].
+ /// int value = deque.PeekRear(); // Returns 7, Deque unchanged: [3, 5, 7].
+ ///
+ public T PeekRear()
+ {
+ // Validate that deque is not empty
+ if (IsEmpty)
+ {
+ throw new InvalidOperationException("Deque is empty.");
+ }
+
+ // Calculate the index of the last element (rear - 1 in circular array)
+ int rearIndex = (rear - 1 + items.Length) % items.Length;
+ return items[rearIndex];
+ }
+
+ ///
+ /// Removes all elements from the deque.
+ /// This operation is O(n) where n is the capacity of the internal array.
+ /// After clearing, the deque can be reused without reallocation.
+ ///
+ public void Clear()
+ {
+ // Clear all references in the array to help garbage collection
+ Array.Clear(items, 0, items.Length);
+
+ // Reset pointers to initial state
+ front = 0;
+ rear = 0;
+ count = 0;
+ }
+
+ ///
+ /// Converts the deque to an array.
+ /// This operation is O(n) where n is the number of elements.
+ /// The resulting array maintains the order from front to rear.
+ ///
+ /// An array containing all elements in the deque from front to rear.
+ ///
+ /// // Deque: [3, 5, 7].
+ /// int[] array = deque.ToArray(); // Returns [3, 5, 7].
+ ///
+ public T[] ToArray()
+ {
+ // Create result array with exact size needed
+ T[] result = new T[count];
+ int index = front;
+
+ // Copy elements from front to rear, handling circular wrap-around
+ for (int i = 0; i < count; i++)
+ {
+ result[i] = items[index];
+ index = (index + 1) % items.Length;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Determines whether the deque contains a specific element.
+ /// This operation is O(n) where n is the number of elements.
+ /// Uses the default equality comparer for type T.
+ ///
+ /// The item to locate in the deque.
+ /// true if the item is found; otherwise, false.
+ ///
+ /// // Deque: [3, 5, 7].
+ /// bool exists = deque.Contains(5); // Returns true.
+ /// bool missing = deque.Contains(9); // Returns false.
+ ///
+ public bool Contains(T item)
+ {
+ int index = front;
+
+ // Iterate through all elements in order from front to rear
+ for (int i = 0; i < count; i++)
+ {
+ // Use default equality comparer to compare elements
+ if (EqualityComparer.Default.Equals(items[index], item))
+ {
+ return true;
+ }
+
+ // Move to next element in circular array
+ index = (index + 1) % items.Length;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Resizes the internal array to accommodate more elements.
+ /// This is a private helper method called automatically when capacity is reached.
+ /// Doubles the capacity and reorganizes elements to start at index 0.
+ /// Time complexity: O(n) where n is the current number of elements.
+ ///
+ private void Resize()
+ {
+ // Double the capacity to reduce frequency of future resizes
+ int newCapacity = items.Length * 2;
+ T[] newItems = new T[newCapacity];
+
+ // Copy all elements to new array starting from index 0
+ // This "unwraps" the circular structure for simplicity
+ int index = front;
+ for (int i = 0; i < count; i++)
+ {
+ newItems[i] = items[index];
+ index = (index + 1) % items.Length;
+ }
+
+ // Replace old array with new larger array
+ items = newItems;
+
+ // Reset pointers: front at 0, rear at position after last element
+ front = 0;
+ rear = count;
+ }
+}
diff --git a/README.md b/README.md
index 0773c264..8b499683 100644
--- a/README.md
+++ b/README.md
@@ -223,6 +223,7 @@ find more than one implementation for the same objective but using different alg
* [Other](./Algorithms/Other)
* [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs)
* [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs)
+ * [Kadane's Algorithm](./Algorithms/Other/KadanesAlgorithm.cs)
* [Luhn](./Algorithms/Other/Luhn.cs)
* [Int2Binary](./Algorithms/Other/Int2Binary.cs)
* [GeoLocation](./Algorithms/Other/GeoLocation.cs)
@@ -260,6 +261,7 @@ find more than one implementation for the same objective but using different alg
* [Data Structures](./DataStructures)
* [Bag](./DataStructures/Bag)
* [Bit Array](./DataStructures/BitArray.cs)
+ * [Deque (Double-Ended Queue)](./DataStructures/Deque/Deque.cs)
* [Timeline](./DataStructures/Timeline.cs)
* [Segment Trees](./DataStructures/SegmentTrees)
* [Segment Tree](./DataStructures/SegmentTrees/SegmentTree.cs)