Skip to content

Commit c720f4d

Browse files
committed
Move bag to implement it's own linked list base
Updated bag documentation Add tests for bag
1 parent b09935a commit c720f4d

File tree

5 files changed

+258
-76
lines changed

5 files changed

+258
-76
lines changed

DataStructures.Tests/BagTests.cs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
using System.Linq;
2+
using DataStructures.Bag;
3+
using FluentAssertions;
4+
using NUnit.Framework;
5+
6+
namespace DataStructures.Tests;
7+
8+
internal class BagTests
9+
{
10+
[Test]
11+
public void Add_ShouldIncreaseCount()
12+
{
13+
// Arrange & Act
14+
var bag = new Bag<int>
15+
{
16+
1,
17+
2,
18+
1
19+
};
20+
21+
// Assert
22+
bag.Count.Should().Be(3);
23+
}
24+
25+
[Test]
26+
public void Add_ShouldHandleDuplicates()
27+
{
28+
// Arrange & Act
29+
var bag = new Bag<string>
30+
{
31+
"apple",
32+
"apple"
33+
};
34+
35+
// Assert
36+
bag.Count.Should().Be(2);
37+
bag.Should().Contain("apple");
38+
}
39+
40+
[Test]
41+
public void Clear_ShouldEmptyTheBag()
42+
{
43+
// Arrange
44+
var bag = new Bag<int>
45+
{
46+
1,
47+
2
48+
};
49+
50+
// Act
51+
bag.Clear();
52+
53+
// Assert
54+
bag.IsEmpty().Should().BeTrue();
55+
bag.Count.Should().Be(0);
56+
}
57+
58+
[Test]
59+
public void IsEmpty_ShouldReturnTrueForEmptyBag()
60+
{
61+
// Arrange
62+
var bag = new Bag<int>();
63+
64+
// Act & Assert
65+
bag.IsEmpty().Should().BeTrue();
66+
}
67+
68+
[Test]
69+
public void IsEmpty_ShouldReturnFalseForNonEmptyBag()
70+
{
71+
// Arrange
72+
var bag = new Bag<int>
73+
{
74+
1
75+
};
76+
77+
// Act & Assert
78+
bag.IsEmpty().Should().BeFalse();
79+
}
80+
81+
[Test]
82+
public void GetEnumerator_ShouldIterateAllItems()
83+
{
84+
// Arrange
85+
var bag = new Bag<int>
86+
{
87+
1,
88+
2,
89+
1
90+
};
91+
92+
// Act
93+
var items = bag.ToList();
94+
95+
// Assert
96+
items.Count.Should().Be(3);
97+
items.Should().Contain(1);
98+
items.Should().Contain(2);
99+
}
100+
101+
[Test]
102+
public void Count_ShouldReturnZeroForEmptyBag()
103+
{
104+
// Arrange
105+
var bag = new Bag<int>();
106+
107+
// Act & Assert
108+
bag.Count.Should().Be(0);
109+
}
110+
111+
[Test]
112+
public void Count_ShouldReturnCorrectCount()
113+
{
114+
// Arrange
115+
var bag = new Bag<int>
116+
{
117+
1,
118+
2,
119+
1
120+
};
121+
122+
// Act & Assert
123+
bag.Count.Should().Be(3);
124+
}
125+
}

DataStructures/Bag.cs

Lines changed: 0 additions & 75 deletions
This file was deleted.

DataStructures/Bag/Bag.cs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
4+
namespace DataStructures.Bag;
5+
6+
/// <summary>
7+
/// Implementation of a Bag (or multiset) data structure using a basic linked list.
8+
/// </summary>
9+
/// <remarks>
10+
/// A bag (or multiset, or mset) is a modification of the concept of a set that, unlike a set, allows for multiple instances for each of its elements.
11+
/// The number of instances given for each element is called the multiplicity of that element in the multiset.
12+
/// As a consequence, an infinite number of multisets exist that contain only elements a and b, but vary in the multiplicities of their elements.
13+
/// See https://en.wikipedia.org/wiki/Multiset for more information.
14+
/// </remarks>
15+
/// <typeparam name="T">Generic Type.</typeparam>
16+
public class Bag<T> : IEnumerable<T> where T : notnull
17+
{
18+
private BagNode<T>? head;
19+
private int totalCount;
20+
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="Bag{T}" /> class.
23+
/// </summary>
24+
public Bag()
25+
{
26+
head = null;
27+
totalCount = 0;
28+
}
29+
30+
/// <summary>
31+
/// Adds an item to the bag. If the item already exists, increases its multiplicity.
32+
/// </summary>
33+
public void Add(T item)
34+
{
35+
// If the bag is empty, create the first node
36+
if (head == null)
37+
{
38+
head = new BagNode<T>(item);
39+
totalCount = 1;
40+
return;
41+
}
42+
43+
// Check if item already exists
44+
var current = head;
45+
BagNode<T>? previous = null;
46+
47+
while (current != null)
48+
{
49+
if (EqualityComparer<T>.Default.Equals(current.Item, item))
50+
{
51+
current.Multiplicity++;
52+
totalCount++;
53+
return;
54+
}
55+
56+
previous = current;
57+
current = current.Next;
58+
}
59+
60+
// Item not found, add it
61+
if (previous != null)
62+
{
63+
previous.Next = new BagNode<T>(item);
64+
totalCount++;
65+
}
66+
}
67+
68+
/// <summary>
69+
/// Clears the bag.
70+
/// </summary>
71+
public void Clear()
72+
{
73+
head = null;
74+
totalCount = 0;
75+
}
76+
77+
/// <summary>
78+
/// Gets the number of items in the bag.
79+
/// </summary>
80+
public int Count => totalCount;
81+
82+
/// <summary>
83+
/// Gets the total number of items in the bag, including all multiplicities.
84+
/// </summary>
85+
public int TotalCount => totalCount;
86+
87+
/// <summary>
88+
/// Returns a boolean indicating whether the bag is empty.
89+
/// </summary>
90+
public bool IsEmpty() => head == null;
91+
92+
/// <summary>
93+
/// Returns an enumerator that iterates through the bag.
94+
/// </summary>
95+
public IEnumerator<T> GetEnumerator()
96+
{
97+
var current = head;
98+
99+
while (current != null)
100+
{
101+
// Yield the item as many times as its multiplicity, pretending they are separate items
102+
for (var i = 0; i < current.Multiplicity; i++)
103+
{
104+
yield return current.Item;
105+
}
106+
107+
current = current.Next;
108+
}
109+
}
110+
111+
/// <summary>
112+
/// Returns an enumerator that iterates through the bag.
113+
/// </summary>
114+
IEnumerator IEnumerable.GetEnumerator()
115+
{
116+
return GetEnumerator();
117+
}
118+
}

DataStructures/Bag/BagNode.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace DataStructures.Bag;
2+
3+
/// <summary>
4+
/// Generic node class for Bag.
5+
/// </summary>
6+
/// <typeparam name="T">A type for node.</typeparam>
7+
public class BagNode<T>(T item)
8+
{
9+
public T Item { get; } = item;
10+
11+
public int Multiplicity { get; set; } = 1;
12+
13+
public BagNode<T>? Next { get; set; } = null;
14+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ find more than one implementation for the same objective but using different alg
247247
* [Levenshtein Distance](./Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs)
248248

249249
* [Data Structures](./DataStructures)
250-
* [Bag](./DataStructures/Bag.cs)
250+
* [Bag](./DataStructures/Bag)
251251
* [Bit Array](./DataStructures/BitArray.cs)
252252
* [Timeline](./DataStructures/Timeline.cs)
253253
* [Segment Trees](./DataStructures/SegmentTrees)

0 commit comments

Comments
 (0)