Skip to content

Commit 404ad72

Browse files
authored
refactor: Bag data structure (#5340)
1 parent e8985b3 commit 404ad72

File tree

2 files changed

+153
-60
lines changed
  • src
    • main/java/com/thealgorithms/datastructures/bags
    • test/java/com/thealgorithms/datastructures/bag

2 files changed

+153
-60
lines changed

src/main/java/com/thealgorithms/datastructures/bags/Bag.java

+42-60
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,68 @@
44
import java.util.NoSuchElementException;
55

66
/**
7-
* Collection which does not allow removing elements (only collect and iterate)
7+
* A collection that allows adding and iterating over elements but does not support element removal.
88
*
9-
* @param <Element> - the generic type of an element in this bag
9+
* @param <E> the type of elements in this bag
1010
*/
11-
public class Bag<Element> implements Iterable<Element> {
11+
public class Bag<E> implements Iterable<E> {
1212

13-
private Node<Element> firstElement; // first element of the bag
14-
private int size; // size of bag
13+
private Node<E> firstElement; // First element in the bag
14+
private int size; // Number of elements in the bag
1515

16-
private static final class Node<Element> {
17-
18-
private Element content;
19-
private Node<Element> nextElement;
16+
// Node class representing each element in the bag
17+
private static final class Node<E> {
18+
private E content;
19+
private Node<E> nextElement;
2020
}
2121

2222
/**
23-
* Create an empty bag
23+
* Constructs an empty bag.
2424
*/
2525
public Bag() {
2626
firstElement = null;
2727
size = 0;
2828
}
2929

3030
/**
31-
* @return true if this bag is empty, false otherwise
31+
* Checks if the bag is empty.
32+
*
33+
* @return true if the bag is empty, false otherwise
3234
*/
3335
public boolean isEmpty() {
34-
return firstElement == null;
36+
return size == 0;
3537
}
3638

3739
/**
40+
* Returns the number of elements in the bag.
41+
*
3842
* @return the number of elements
3943
*/
4044
public int size() {
4145
return size;
4246
}
4347

4448
/**
45-
* @param element - the element to add
49+
* Adds an element to the bag.
50+
*
51+
* @param element the element to add
4652
*/
47-
public void add(Element element) {
48-
Node<Element> oldfirst = firstElement;
49-
firstElement = new Node<>();
50-
firstElement.content = element;
51-
firstElement.nextElement = oldfirst;
53+
public void add(E element) {
54+
Node<E> newNode = new Node<>();
55+
newNode.content = element;
56+
newNode.nextElement = firstElement;
57+
firstElement = newNode;
5258
size++;
5359
}
5460

5561
/**
56-
* Checks if the bag contains a specific element
62+
* Checks if the bag contains a specific element.
5763
*
58-
* @param element which you want to look for
59-
* @return true if bag contains element, otherwise false
64+
* @param element the element to check for
65+
* @return true if the bag contains the element, false otherwise
6066
*/
61-
public boolean contains(Element element) {
62-
for (Element value : this) {
67+
public boolean contains(E element) {
68+
for (E value : this) {
6369
if (value.equals(element)) {
6470
return true;
6571
}
@@ -68,61 +74,37 @@ public boolean contains(Element element) {
6874
}
6975

7076
/**
71-
* @return an iterator that iterates over the elements in this bag in
72-
* arbitrary order
77+
* Returns an iterator over the elements in this bag.
78+
*
79+
* @return an iterator that iterates over the elements in the bag
7380
*/
74-
public Iterator<Element> iterator() {
81+
@Override
82+
public Iterator<E> iterator() {
7583
return new ListIterator<>(firstElement);
7684
}
7785

78-
@SuppressWarnings("hiding")
79-
private class ListIterator<Element> implements Iterator<Element> {
86+
// Private class for iterating over elements
87+
private static class ListIterator<E> implements Iterator<E> {
8088

81-
private Node<Element> currentElement;
89+
private Node<E> currentElement;
8290

83-
ListIterator(Node<Element> firstElement) {
84-
currentElement = firstElement;
91+
ListIterator(Node<E> firstElement) {
92+
this.currentElement = firstElement;
8593
}
8694

95+
@Override
8796
public boolean hasNext() {
8897
return currentElement != null;
8998
}
9099

91-
/**
92-
* remove is not allowed in a bag
93-
*/
94100
@Override
95-
public void remove() {
96-
throw new UnsupportedOperationException();
97-
}
98-
99-
public Element next() {
101+
public E next() {
100102
if (!hasNext()) {
101103
throw new NoSuchElementException();
102104
}
103-
Element element = currentElement.content;
105+
E element = currentElement.content;
104106
currentElement = currentElement.nextElement;
105107
return element;
106108
}
107109
}
108-
109-
/**
110-
* main-method for testing
111-
*/
112-
public static void main(String[] args) {
113-
Bag<String> bag = new Bag<>();
114-
115-
bag.add("1");
116-
bag.add("1");
117-
bag.add("2");
118-
119-
System.out.println("size of bag = " + bag.size());
120-
for (String s : bag) {
121-
System.out.println(s);
122-
}
123-
124-
System.out.println(bag.contains(null));
125-
System.out.println(bag.contains("1"));
126-
System.out.println(bag.contains("3"));
127-
}
128110
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.thealgorithms.datastructures.bag;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import com.thealgorithms.datastructures.bags.Bag;
8+
import java.util.Iterator;
9+
import org.junit.jupiter.api.Test;
10+
11+
class BagTest {
12+
13+
@Test
14+
void testBagOperations() {
15+
Bag<String> bag = new Bag<>();
16+
assertTrue(bag.isEmpty(), "Bag should be empty initially");
17+
assertEquals(0, bag.size(), "Bag size should be 0 initially");
18+
19+
bag.add("item1");
20+
bag.add("item2");
21+
bag.add("item1"); // adding duplicate item
22+
23+
assertFalse(bag.isEmpty(), "Bag should not be empty after adding elements");
24+
assertEquals(3, bag.size(), "Bag size should be 3 after adding 3 elements");
25+
26+
assertTrue(bag.contains("item1"), "Bag should contain 'item1'");
27+
assertTrue(bag.contains("item2"), "Bag should contain 'item2'");
28+
assertFalse(bag.contains("item3"), "Bag should not contain 'item3'");
29+
assertFalse(bag.contains(null), "Bag should not contain null");
30+
31+
// Test iteration
32+
int count = 0;
33+
for (String item : bag) {
34+
assertTrue(item.equals("item1") || item.equals("item2"), "Item should be either 'item1' or 'item2'");
35+
count++;
36+
}
37+
assertEquals(3, count, "Iterator should traverse all 3 items");
38+
}
39+
40+
@Test
41+
void testBagInitialization() {
42+
Bag<String> bag = new Bag<>();
43+
assertTrue(bag.isEmpty(), "Bag should be empty initially");
44+
assertEquals(0, bag.size(), "Bag size should be 0 initially");
45+
}
46+
47+
@Test
48+
void testAddElements() {
49+
Bag<String> bag = new Bag<>();
50+
bag.add("item1");
51+
bag.add("item2");
52+
bag.add("item1"); // Adding duplicate item
53+
54+
assertFalse(bag.isEmpty(), "Bag should not be empty after adding elements");
55+
assertEquals(3, bag.size(), "Bag size should be 3 after adding 3 elements");
56+
}
57+
58+
@Test
59+
void testContainsMethod() {
60+
Bag<String> bag = new Bag<>();
61+
bag.add("item1");
62+
bag.add("item2");
63+
64+
assertTrue(bag.contains("item1"), "Bag should contain 'item1'");
65+
assertTrue(bag.contains("item2"), "Bag should contain 'item2'");
66+
assertFalse(bag.contains("item3"), "Bag should not contain 'item3'");
67+
assertFalse(bag.contains(null), "Bag should not contain null");
68+
}
69+
70+
@Test
71+
void testContainsAfterRemoveOperation() {
72+
Bag<String> bag = new Bag<>();
73+
bag.add("item1");
74+
bag.add("item2");
75+
assertTrue(bag.contains("item1"), "Bag should contain 'item1' before removal");
76+
assertTrue(bag.contains("item2"), "Bag should contain 'item2' before removal");
77+
}
78+
79+
@Test
80+
void testIterator() {
81+
Bag<String> bag = new Bag<>();
82+
bag.add("item1");
83+
bag.add("item2");
84+
bag.add("item3");
85+
86+
int count = 0;
87+
for (String item : bag) {
88+
assertTrue(item.equals("item1") || item.equals("item2") || item.equals("item3"), "Item should be one of 'item1', 'item2', or 'item3'");
89+
count++;
90+
}
91+
assertEquals(3, count, "Iterator should traverse all 3 items");
92+
}
93+
94+
@Test
95+
void testIteratorEmptyBag() {
96+
Bag<String> bag = new Bag<>();
97+
int count = 0;
98+
for (String ignored : bag) {
99+
org.junit.jupiter.api.Assertions.fail("Iterator should not return any items for an empty bag");
100+
}
101+
assertEquals(0, count, "Iterator should not traverse any items in an empty bag");
102+
}
103+
104+
@Test
105+
void testRemoveMethodThrowsException() {
106+
Bag<String> bag = new Bag<>();
107+
bag.add("item1");
108+
Iterator<String> iterator = bag.iterator();
109+
org.junit.jupiter.api.Assertions.assertThrows(UnsupportedOperationException.class, iterator::remove, "Remove operation should throw UnsupportedOperationException");
110+
}
111+
}

0 commit comments

Comments
 (0)