1+ /**
2+ * Data-Structures-In-Java
3+ * CustomBagLL.java
4+ */
5+ package com .deepak .data .structures .Bag ;
6+
7+ import java .util .Iterator ;
8+ import java .util .NoSuchElementException ;
9+ import java .util .Random ;
10+
11+ /**
12+ * Custom bag implementation using a Linked List
13+ *
14+ * @author Deepak
15+ *
16+ * @param <T>
17+ */
18+ public class CustomBagLL <T > {
19+
20+ public static void main (String [] args ) {
21+ CustomBagLL <String > bag = new CustomBagLL <>();
22+ System .out .println (bag .isEmpty ());
23+ bag .add ("A" );
24+ bag .add ("C" );
25+ bag .add ("B" );
26+ bag .add ("B" );
27+ bag .add ("A" );
28+ bag .add ("B" );
29+ System .out .println (bag .toString ());
30+ bag .remove ("C" );
31+ System .out .println (bag .toString ());
32+ bag .remove ("A" );
33+ System .out .println (bag .toString ());
34+ System .out .println ("Bag contains C : " + bag .contains ("C" ));
35+ System .out .println ("Bag contains B : " + bag .contains ("B" ));
36+ System .out .println ("Bag Size : " + bag .size ());
37+ System .out .println ("Bag Distinct Size : " + bag .distinctSize ());
38+ System .out .println ("Grab : " + bag .grab ());
39+ Iterator <String > itr = bag .iterator ();
40+ /* Starting to print from iterator */
41+ System .out .println ();
42+ System .out .println ("Printing from iterator : " );
43+ while (itr .hasNext ()) {
44+ System .out .println (itr .next ());
45+ }
46+ }
47+
48+ /* Head node */
49+ private Node <T > head ;
50+
51+ /**
52+ * Constructor
53+ */
54+ public CustomBagLL () {
55+ this .head = null ;
56+ }
57+
58+ /**
59+ * Method to add a item
60+ *
61+ * @param item
62+ */
63+ public void add (T item ) {
64+ /* If bag is empty, make new item as head */
65+ if (isEmpty ()) {
66+ Node <T > newNode = new Node <T >(item );
67+ head = newNode ;
68+ } else {
69+ /* Have two pointers current and last */
70+ Node <T > current = head ;
71+ Node <T > last = head ;
72+ boolean found = false ;
73+ while (current != null ) {
74+ /* If that item is found, just increase the value */
75+ if (current .item == item ) {
76+ current .incrementValue ();
77+ found = true ;
78+ break ;
79+ }
80+ last = current ;
81+ current = current .next ;
82+ }
83+ /* If not found, create as a new node and push to last */
84+ if (!found ) {
85+ Node <T > newNode = new Node <T >(item );
86+ last .next = newNode ;
87+ }
88+ }
89+ }
90+
91+ /**
92+ * Method to remove a item
93+ *
94+ * @param item
95+ * @return {@link boolean}
96+ */
97+ public boolean remove (T item ) {
98+ /* If bag contains the item */
99+ if (contains (item )) {
100+ /* Have two pointers current and prev */
101+ Node <T > current = head ;
102+ Node <T > prev = head ;
103+ /* Keep going while current is not null */
104+ while (current != null ) {
105+ if (current .item == item ) {
106+ /* If item matches, check if it is a head or not */
107+ if (current == head ) {
108+ /* If it's head, decrement the value and update head */
109+ current .decrementValue ();
110+ if (current .value < 1 ) {
111+ head = head .next ;
112+ }
113+ return true ;
114+ } else {
115+ /* Decrement the value, check if this was the last
116+ * entry of that type, it yes, delete the item */
117+ current .decrementValue ();
118+ if (current .value < 1 ) {
119+ prev .next = current .next ;
120+ current .next = null ;
121+ }
122+ return true ;
123+ }
124+ }
125+ /* Move to next set of items */
126+ prev = current ;
127+ current = current .next ;
128+ }
129+ }
130+ return false ;
131+ }
132+
133+ /**
134+ * Method to clear the bag
135+ */
136+ public void clear () {
137+ this .head = null ;
138+ }
139+
140+ /**
141+ * Method to check if bag contains the item
142+ *
143+ * @param item
144+ * @return {@link boolean}
145+ */
146+ public boolean contains (T item ) {
147+ Node <T > current = head ;
148+ /* Start traversing and stop if item matches */
149+ while (current != null ) {
150+ if (current .item == item ) {
151+ return true ;
152+ }
153+ current = current .next ;
154+ }
155+ return false ;
156+ }
157+
158+ /**
159+ * Method to grab any random element
160+ *
161+ * @return {@link T}
162+ */
163+ public T grab () {
164+ /* Have a random index */
165+ Random random = new Random ();
166+ int randomItemIndex = random .nextInt (distinctSize ());
167+ Node <T > current = head ;
168+ /* Move the pointer till we reach that random index */
169+ for (int i = 0 ; i < randomItemIndex ; i ++) {
170+ current = current .next ;
171+ }
172+ return current .item ;
173+ }
174+
175+ /**
176+ * Method to check size of the bag
177+ *
178+ * @return {@link int}
179+ */
180+ public int size () {
181+ Node <T > current = head ;
182+ int size = 0 ;
183+ /* Keep traversing and track size of each entry */
184+ while (current != null ) {
185+ size += current .value ;
186+ current = current .next ;
187+ }
188+ return size ;
189+ }
190+
191+ /**
192+ * Method to get distinct size of the bag
193+ *
194+ * @return {@link int}
195+ */
196+ public int distinctSize () {
197+ Node <T > current = head ;
198+ int counter = 0 ;
199+ /* Increment the counter only when a new element is seen */
200+ while (current != null ) {
201+ counter ++;
202+ current = current .next ;
203+ }
204+ return counter ;
205+ }
206+
207+ /**
208+ * Method to check if bag is empty
209+ *
210+ * @return {@link boolean}
211+ */
212+ public boolean isEmpty () {
213+ if (head == null ) {
214+ return true ;
215+ }
216+ return false ;
217+ }
218+
219+ /**
220+ * Method to print the content of bag as string
221+ */
222+ public String toString () {
223+ if (isEmpty ()) {
224+ return "Bag is Empty" ;
225+ } else {
226+ /* Keep appending the elements to string */
227+ Node <T > current = head ;
228+ String str = "Bag = " ;
229+ while (current != null ) {
230+ for (int i = 0 ; i < current .value ; i ++) {
231+ str += "{" + current .item + "}" ;
232+ }
233+ current = current .next ;
234+ }
235+ return str ;
236+ }
237+ }
238+
239+ /**
240+ * Method to get a iterator on bag
241+ *
242+ * @return {@link Iterator<T>}
243+ */
244+ public Iterator <T > iterator () {
245+ return new Iterator <T >() {
246+
247+ /* Keep a track of next item and value count for each item */
248+ private Node <T > nextItem = head ;
249+ private int valueCount = 0 ;
250+
251+ /**
252+ * Method to check if bag has elements
253+ */
254+ @ Override
255+ public boolean hasNext () {
256+ /* If next item is head and it's not null,
257+ * we have more elements */
258+ if (nextItem == head && nextItem != null ) {
259+ return true ;
260+ } else if (nextItem != head && nextItem .next != null ){
261+ return true ;
262+ } else if (nextItem .value > valueCount + 1 ) {
263+ return true ;
264+ }
265+ return false ;
266+ }
267+
268+ /**
269+ * Method to get the next element
270+ */
271+ @ Override
272+ public T next () {
273+ if (!hasNext ()) {
274+ throw new NoSuchElementException ("No Element left in collection" );
275+ }
276+ if (nextItem .value > valueCount ) {
277+ /* We still have items of same type left */
278+ valueCount ++;
279+ } else {
280+ /* Time to move to next item */
281+ nextItem = nextItem .next ;
282+ valueCount = 0 ;
283+ }
284+ Node <T > itemToReturn = nextItem ;
285+ if (itemToReturn != null ) {
286+ return itemToReturn .item ;
287+ } else {
288+ return null ;
289+ }
290+ }
291+
292+ };
293+ }
294+
295+ /**
296+ * Class Node for Bag
297+ *
298+ * @author Deepak
299+ *
300+ * @param <E>
301+ */
302+ public class Node <E > {
303+
304+ /* Item, counter associated with item and next pointer */
305+ private E item ;
306+ private int value ;
307+ private Node <E > next ;
308+
309+ /**
310+ * Constructor to create the Node
311+ *
312+ * @param item
313+ */
314+ public Node (E item ) {
315+ this .item = item ;
316+ this .value = 1 ;
317+ this .next = null ;
318+ }
319+
320+ /**
321+ * Method to increment the value
322+ */
323+ public void incrementValue () {
324+ value ++;
325+ }
326+
327+ /**
328+ * Method to decrement the value
329+ */
330+ public void decrementValue () {
331+ value --;
332+ }
333+
334+ @ Override
335+ public String toString () {
336+ return "Item : [" + this .item + "]" ;
337+ }
338+
339+ }
340+
341+ }
0 commit comments