refactor: Bag
data structure (#5340)
This commit is contained in:
parent
e8985b3edb
commit
404ad7272f
@ -4,23 +4,23 @@ import java.util.Iterator;
|
|||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection which does not allow removing elements (only collect and iterate)
|
* A collection that allows adding and iterating over elements but does not support element removal.
|
||||||
*
|
*
|
||||||
* @param <Element> - the generic type of an element in this bag
|
* @param <E> the type of elements in this bag
|
||||||
*/
|
*/
|
||||||
public class Bag<Element> implements Iterable<Element> {
|
public class Bag<E> implements Iterable<E> {
|
||||||
|
|
||||||
private Node<Element> firstElement; // first element of the bag
|
private Node<E> firstElement; // First element in the bag
|
||||||
private int size; // size of bag
|
private int size; // Number of elements in the bag
|
||||||
|
|
||||||
private static final class Node<Element> {
|
// Node class representing each element in the bag
|
||||||
|
private static final class Node<E> {
|
||||||
private Element content;
|
private E content;
|
||||||
private Node<Element> nextElement;
|
private Node<E> nextElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty bag
|
* Constructs an empty bag.
|
||||||
*/
|
*/
|
||||||
public Bag() {
|
public Bag() {
|
||||||
firstElement = null;
|
firstElement = null;
|
||||||
@ -28,13 +28,17 @@ public class Bag<Element> implements Iterable<Element> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this bag is empty, false otherwise
|
* Checks if the bag is empty.
|
||||||
|
*
|
||||||
|
* @return true if the bag is empty, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return firstElement == null;
|
return size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns the number of elements in the bag.
|
||||||
|
*
|
||||||
* @return the number of elements
|
* @return the number of elements
|
||||||
*/
|
*/
|
||||||
public int size() {
|
public int size() {
|
||||||
@ -42,24 +46,26 @@ public class Bag<Element> implements Iterable<Element> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param element - the element to add
|
* Adds an element to the bag.
|
||||||
|
*
|
||||||
|
* @param element the element to add
|
||||||
*/
|
*/
|
||||||
public void add(Element element) {
|
public void add(E element) {
|
||||||
Node<Element> oldfirst = firstElement;
|
Node<E> newNode = new Node<>();
|
||||||
firstElement = new Node<>();
|
newNode.content = element;
|
||||||
firstElement.content = element;
|
newNode.nextElement = firstElement;
|
||||||
firstElement.nextElement = oldfirst;
|
firstElement = newNode;
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the bag contains a specific element
|
* Checks if the bag contains a specific element.
|
||||||
*
|
*
|
||||||
* @param element which you want to look for
|
* @param element the element to check for
|
||||||
* @return true if bag contains element, otherwise false
|
* @return true if the bag contains the element, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean contains(Element element) {
|
public boolean contains(E element) {
|
||||||
for (Element value : this) {
|
for (E value : this) {
|
||||||
if (value.equals(element)) {
|
if (value.equals(element)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -68,61 +74,37 @@ public class Bag<Element> implements Iterable<Element> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return an iterator that iterates over the elements in this bag in
|
* Returns an iterator over the elements in this bag.
|
||||||
* arbitrary order
|
*
|
||||||
|
* @return an iterator that iterates over the elements in the bag
|
||||||
*/
|
*/
|
||||||
public Iterator<Element> iterator() {
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
return new ListIterator<>(firstElement);
|
return new ListIterator<>(firstElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("hiding")
|
// Private class for iterating over elements
|
||||||
private class ListIterator<Element> implements Iterator<Element> {
|
private static class ListIterator<E> implements Iterator<E> {
|
||||||
|
|
||||||
private Node<Element> currentElement;
|
private Node<E> currentElement;
|
||||||
|
|
||||||
ListIterator(Node<Element> firstElement) {
|
ListIterator(Node<E> firstElement) {
|
||||||
currentElement = firstElement;
|
this.currentElement = firstElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return currentElement != null;
|
return currentElement != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* remove is not allowed in a bag
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public E next() {
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Element next() {
|
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
Element element = currentElement.content;
|
E element = currentElement.content;
|
||||||
currentElement = currentElement.nextElement;
|
currentElement = currentElement.nextElement;
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* main-method for testing
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Bag<String> bag = new Bag<>();
|
|
||||||
|
|
||||||
bag.add("1");
|
|
||||||
bag.add("1");
|
|
||||||
bag.add("2");
|
|
||||||
|
|
||||||
System.out.println("size of bag = " + bag.size());
|
|
||||||
for (String s : bag) {
|
|
||||||
System.out.println(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(bag.contains(null));
|
|
||||||
System.out.println(bag.contains("1"));
|
|
||||||
System.out.println(bag.contains("3"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
111
src/test/java/com/thealgorithms/datastructures/bag/BagTest.java
Normal file
111
src/test/java/com/thealgorithms/datastructures/bag/BagTest.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
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.assertTrue;
|
||||||
|
|
||||||
|
import com.thealgorithms.datastructures.bags.Bag;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class BagTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBagOperations() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
assertTrue(bag.isEmpty(), "Bag should be empty initially");
|
||||||
|
assertEquals(0, bag.size(), "Bag size should be 0 initially");
|
||||||
|
|
||||||
|
bag.add("item1");
|
||||||
|
bag.add("item2");
|
||||||
|
bag.add("item1"); // adding duplicate item
|
||||||
|
|
||||||
|
assertFalse(bag.isEmpty(), "Bag should not be empty after adding elements");
|
||||||
|
assertEquals(3, bag.size(), "Bag size should be 3 after adding 3 elements");
|
||||||
|
|
||||||
|
assertTrue(bag.contains("item1"), "Bag should contain 'item1'");
|
||||||
|
assertTrue(bag.contains("item2"), "Bag should contain 'item2'");
|
||||||
|
assertFalse(bag.contains("item3"), "Bag should not contain 'item3'");
|
||||||
|
assertFalse(bag.contains(null), "Bag should not contain null");
|
||||||
|
|
||||||
|
// Test iteration
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBagInitialization() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
assertTrue(bag.isEmpty(), "Bag should be empty initially");
|
||||||
|
assertEquals(0, bag.size(), "Bag size should be 0 initially");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAddElements() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
bag.add("item1");
|
||||||
|
bag.add("item2");
|
||||||
|
bag.add("item1"); // Adding duplicate item
|
||||||
|
|
||||||
|
assertFalse(bag.isEmpty(), "Bag should not be empty after adding elements");
|
||||||
|
assertEquals(3, bag.size(), "Bag size should be 3 after adding 3 elements");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testContainsMethod() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
bag.add("item1");
|
||||||
|
bag.add("item2");
|
||||||
|
|
||||||
|
assertTrue(bag.contains("item1"), "Bag should contain 'item1'");
|
||||||
|
assertTrue(bag.contains("item2"), "Bag should contain 'item2'");
|
||||||
|
assertFalse(bag.contains("item3"), "Bag should not contain 'item3'");
|
||||||
|
assertFalse(bag.contains(null), "Bag should not contain null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testContainsAfterRemoveOperation() {
|
||||||
|
Bag<String> 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIterator() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
bag.add("item1");
|
||||||
|
bag.add("item2");
|
||||||
|
bag.add("item3");
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (String item : bag) {
|
||||||
|
assertTrue(item.equals("item1") || item.equals("item2") || item.equals("item3"), "Item should be one of 'item1', 'item2', or 'item3'");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
assertEquals(3, count, "Iterator should traverse all 3 items");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIteratorEmptyBag() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
int count = 0;
|
||||||
|
for (String ignored : bag) {
|
||||||
|
org.junit.jupiter.api.Assertions.fail("Iterator should not return any items for an empty bag");
|
||||||
|
}
|
||||||
|
assertEquals(0, count, "Iterator should not traverse any items in an empty bag");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRemoveMethodThrowsException() {
|
||||||
|
Bag<String> bag = new Bag<>();
|
||||||
|
bag.add("item1");
|
||||||
|
Iterator<String> iterator = bag.iterator();
|
||||||
|
org.junit.jupiter.api.Assertions.assertThrows(UnsupportedOperationException.class, iterator::remove, "Remove operation should throw UnsupportedOperationException");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user