From 730eb5a5f699f70dd56d2e61b047f560b62e24e1 Mon Sep 17 00:00:00 2001 From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:31:26 +0530 Subject: [PATCH] Enhance docs, add more tests in `Bag` (#5947) --- .../datastructures/bags/Bag.java | 46 ++++++++++++--- .../datastructures/bag/BagTest.java | 56 +++++++++++++++++-- 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/bags/Bag.java b/src/main/java/com/thealgorithms/datastructures/bags/Bag.java index 1bb143fab..afc3bbe40 100644 --- a/src/main/java/com/thealgorithms/datastructures/bags/Bag.java +++ b/src/main/java/com/thealgorithms/datastructures/bags/Bag.java @@ -4,14 +4,18 @@ import java.util.Iterator; import java.util.NoSuchElementException; /** - * A collection that allows adding and iterating over elements but does not support element removal. + * A generic collection that allows adding and iterating over elements but does not support + * element removal. This class implements a simple bag data structure, which can hold duplicate + * elements and provides operations to check for membership and the size of the collection. + * + *

Bag is not thread-safe and should not be accessed by multiple threads concurrently. * * @param the type of elements in this bag */ public class Bag implements Iterable { - private Node firstElement; // First element in the bag - private int size; // Number of elements in the bag + private Node firstElement; // Reference to the first element in the bag + private int size; // Count of elements in the bag // Node class representing each element in the bag private static final class Node { @@ -21,6 +25,7 @@ public class Bag implements Iterable { /** * Constructs an empty bag. + *

This initializes the bag with zero elements. */ public Bag() { firstElement = null; @@ -30,7 +35,7 @@ public class Bag implements Iterable { /** * Checks if the bag is empty. * - * @return true if the bag is empty, false otherwise + * @return {@code true} if the bag contains no elements; {@code false} otherwise */ public boolean isEmpty() { return size == 0; @@ -39,7 +44,7 @@ public class Bag implements Iterable { /** * Returns the number of elements in the bag. * - * @return the number of elements + * @return the number of elements currently in the bag */ public int size() { return size; @@ -48,7 +53,10 @@ public class Bag implements Iterable { /** * Adds an element to the bag. * - * @param element the element to add + *

This method adds the specified element to the bag. Duplicates are allowed, and the + * bag will maintain the order in which elements are added. + * + * @param element the element to add; must not be {@code null} */ public void add(E element) { Node newNode = new Node<>(); @@ -61,8 +69,10 @@ public class Bag implements Iterable { /** * Checks if the bag contains a specific element. * - * @param element the element to check for - * @return true if the bag contains the element, false otherwise + *

This method uses the {@code equals} method of the element to determine membership. + * + * @param element the element to check for; must not be {@code null} + * @return {@code true} if the bag contains the specified element; {@code false} otherwise */ public boolean contains(E element) { for (E value : this) { @@ -76,6 +86,8 @@ public class Bag implements Iterable { /** * Returns an iterator over the elements in this bag. * + *

The iterator provides a way to traverse the elements in the order they were added. + * * @return an iterator that iterates over the elements in the bag */ @Override @@ -88,19 +100,35 @@ public class Bag implements Iterable { private Node currentElement; + /** + * Constructs a ListIterator starting from the given first element. + * + * @param firstElement the first element of the bag to iterate over + */ ListIterator(Node firstElement) { this.currentElement = firstElement; } + /** + * Checks if there are more elements to iterate over. + * + * @return {@code true} if there are more elements; {@code false} otherwise + */ @Override public boolean hasNext() { return currentElement != null; } + /** + * Returns the next element in the iteration. + * + * @return the next element in the bag + * @throws NoSuchElementException if there are no more elements to return + */ @Override public E next() { if (!hasNext()) { - throw new NoSuchElementException(); + throw new NoSuchElementException("No more elements in the bag."); } E element = currentElement.content; currentElement = currentElement.nextElement; diff --git a/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java b/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java index c0fe107bf..b7e648513 100644 --- a/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java +++ b/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java @@ -2,6 +2,7 @@ package com.thealgorithms.datastructures.bag; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import com.thealgorithms.datastructures.bags.Bag; @@ -68,12 +69,12 @@ class BagTest { } @Test - void testContainsAfterRemoveOperation() { + void testContainsAfterAdditions() { Bag bag = new Bag<>(); bag.add("item1"); bag.add("item2"); - assertTrue(bag.contains("item1"), "Bag should contain 'item1' before removal"); - assertTrue(bag.contains("item2"), "Bag should contain 'item2' before removal"); + assertTrue(bag.contains("item1"), "Bag should contain 'item1' after addition"); + assertTrue(bag.contains("item2"), "Bag should contain 'item2' after addition"); } @Test @@ -106,6 +107,53 @@ class BagTest { Bag bag = new Bag<>(); bag.add("item1"); Iterator iterator = bag.iterator(); - org.junit.jupiter.api.Assertions.assertThrows(UnsupportedOperationException.class, iterator::remove, "Remove operation should throw UnsupportedOperationException"); + assertThrows(UnsupportedOperationException.class, iterator::remove, "Remove operation should throw UnsupportedOperationException"); + } + + @Test + void testMultipleDuplicates() { + Bag bag = new Bag<>(); + bag.add("item1"); + bag.add("item1"); + bag.add("item1"); // Add three duplicates + + assertEquals(3, bag.size(), "Bag size should be 3 after adding three duplicates"); + assertTrue(bag.contains("item1"), "Bag should contain 'item1'"); + } + + @Test + void testLargeNumberOfElements() { + Bag bag = new Bag<>(); + for (int i = 0; i < 1000; i++) { + bag.add(i); + } + assertEquals(1000, bag.size(), "Bag should contain 1000 elements"); + } + + @Test + void testMixedTypeElements() { + Bag bag = new Bag<>(); + bag.add("string"); + bag.add(1); + bag.add(2.0); + + assertTrue(bag.contains("string"), "Bag should contain a string"); + assertTrue(bag.contains(1), "Bag should contain an integer"); + assertTrue(bag.contains(2.0), "Bag should contain a double"); + } + + @Test + void testIteratorWithDuplicates() { + Bag bag = new Bag<>(); + bag.add("item1"); + bag.add("item1"); + bag.add("item2"); + + int count = 0; + for (String item : bag) { + assertTrue(item.equals("item1") || item.equals("item2"), "Item should be either 'item1' or 'item2'"); + count++; + } + assertEquals(3, count, "Iterator should traverse all 3 items including duplicates"); } }