Data Structures
Data Structures
Hierarchy Overview: Understand the core interfaces: Collection , List , Set , Queue , and Map .
Implementations:
Comparisons:
Interview Questions:
Resources:
Arrays:
Multi-dimensional arrays
Linked Lists:
Trees:
Data Structures 1
Binary Trees, Binary Search Trees (BST)
Graphs:
Hashing:
Interview Questions:
Resources:
Generics:
Concurrency:
ConcurrentHashMap , synchronization
Java 8 Features:
Streams API
Lambda expressions
Functional interfaces
Interview Questions:
Resources:
Easy Level:
Reverse a string
Medium Level:
Hard Level:
Resources:
Review and analyze past interview questions from top tech companies.
Resources:
By following this structured roadmap, you'll build a solid foundation in Java data structures and
collections, equipping you to tackle technical interviews and coding challenges confidently. Let me
know which phase you'd like to delve into next, or if you need practice problems and solutions for a
specific topic!
Data Structures 3
It is a part of the Java Collections Framework (JCF).
Maintains the insertion order (i.e., the order you add elements is preserved).
Can grow and shrink automatically when elements are added or removed.
If you want to add more elements than the initial size, you have to create a new array manually.
Provides many built-in methods like add() , remove() , contains() , get() , etc., making coding much
easier.
3. Hierarchy of ArrayList
Object
↳ AbstractCollection
↳ AbstractList
↳ ArrayList (implements List, RandomAccess, Cloneable, Serializable)
Important interfaces:
4. ArrayList Properties
Property Explanation
Duplicates Allowed
5. Constructors of ArrayList
Constructor Meaning
Data Structures 4
ArrayList() Creates an empty list with initial capacity 10
ArrayList(int initialCapacity) Creates an empty list with specified initial capacity
ArrayList(Collection<? extends E> c) Creates a list containing the elements of the given collection
6. Important Methods
Method Purpose
add(E e) Adds element to the end
add(int index, E element) Adds element at specific index
remove(Object o) Removes first occurrence of specified element
remove(int index) Removes element at specific index
get(int index) Returns element at index
set(int index, E element) Replaces element at specified index
contains(Object o) Checks if element exists
size() Returns the number of elements
isEmpty() Checks if list is empty
clear() Removes all elements
indexOf(Object o) First index of element
lastIndexOf(Object o) Last index of element
toArray() Converts ArrayList to array
7. Real-World Analogy
An ArrayList is like a magic bag that automatically expands when you need
to put more items inside!
8. Practical Example
import java.util.ArrayList;
list.add("Apple");
list.add("Banana");
list.add("Cherry");
Data Structures 5
list.add(1, "Mango");
System.out.println(list); // [Apple, Mango, Banana, Cherry]
list.remove("Banana");
System.out.println(list); // [Apple, Mango, Cherry]
System.out.println(list.get(2)); // Cherry
}
}
Slow for insertions/deletions in the middle (we'll see why in internal working).
Not thread-safe.
👉 So whenever you create an ArrayList, under the hood, an Object[] array is created.
2. Initial Capacity
Data Structures 6
When you create an ArrayList with default constructor, it starts with a capacity of 10.
Capacity ≠ size.
🔵 Example:
ArrayList<Integer> list = new ArrayList<>();
Capacity = 10
Size = 0
👉 For example:
Old Capacity New Capacity
10 15
15 22
22 33
33 49
etc...
Data Structures 7
elementData = Arrays.copyOf(elementData, newCapacity);
}
Key point:
Most adds are constant time, but some adds (during resizing) take linear
time.
5. Space Complexity
Internally maintains an Object[].
However:
Garbage collector reclaims memory if elements are removed, but capacity does not shrink
automatically.
To shrink manually:
list.trimToSize();
Data Structures 8
ensureCapacity(int minCapacity) Ensures minimum capacity
trimToSize() Shrinks capacity to size
Arrays.copyOf() Used for resizing array
"ArrayList internally uses an Object array. When elements are added beyond its current capacity, it
grows by 50% of the old capacity. Resizing happens via Arrays.copyOf(), which is O(n) in time
complexity. Random access is O(1), insertion/removal in the middle is O(n) because elements need
to be shifted."
Why is adding at the end O(1) but adding in the middle O(n)?
🧠Questions
PHASE 3 — ArrayList Most Asked Interview
& Answers
🎯 Important:
I’ll give you typical real interview questions.
Along with how to structure your answer: short version for HR / casual discussion and deep
technical version for technical rounds.
We'll also include bonus smart points you can throw if you want to impress extra ✨.
✅ List of Most Asked Questions on ArrayList
1. What is an ArrayList in Java?
Simple Version (HR, easy round):
Data Structures 9
"ArrayList is a resizable array implementation in Java that allows dynamic addition of elements and
maintains insertion order."
"ArrayList is a class in the Java Collections Framework that implements the List interface and
internally uses an Object array. It allows random access in O(1) time and automatically resizes by
increasing its capacity by 50% when needed. It is not synchronized by default."
"When we create an ArrayList with the default constructor, its initial capacity is 10."
"Whenever the ArrayList reaches its full capacity, it grows by 50% more than the old capacity. This
is done using Arrays.copyOf() , which creates a new larger array and copies old elements into it."
"ArrayList is not synchronized, meaning it is not thread-safe. To make it synchronized, we can use
Collections.synchronizedList(new ArrayList<>()) ."
Data Structures 10
"When we remove an element, all subsequent elements are shifted one position to the left. Hence,
removing from the end is O(1), but removing from the beginning or middle is O(n)."
"Size is the number of elements actually stored. Capacity is the size of the underlying Object array.
Capacity is always greater than or equal to size."
"We can call ensureCapacity(int minCapacity) to manually increase the ArrayList's capacity without adding
elements."
"ArrayList allows multiple null values because internally it treats null just like any other object
reference. There's no restriction on adding nulls."
"Use ArrayList when random access and retrieval speed is important. Use LinkedList when
frequent insertions and deletions are required at the beginning or middle."
"Yes. We can increase using ensureCapacity() and decrease using trimToSize() ."
Data Structures 11
Then Expand if Interviewer Asks (deep internal stuff)
Mention any smart point if you sense the interviewer wants depth (they'll love it)
You:
"ArrayList is a resizable array implementation of the List interface. Internally, it uses an Object
array and when the array becomes full, it resizes itself by increasing capacity by 50%. Resizing
involves copying old elements to a new larger array, which is an O(n) operation."
"By the way, if the expected size is known, we can optimize performance using ensureCapacity()."
🧠Style)
PHASE 4 — ArrayList Coding Practice (Interview
In this phase:
I'll first show you important coding problems related to ArrayList (with increasing levels: Easy
→ Medium → Hard).
I'll also explain what interviewer expects when you code these — (like where you should use
ArrayList , why LinkedList won't be good here, etc.)
Data Structures 12
🥇OnStep 1: Let's start with Easy Level — Basic Hands-
🔥 Problem 1: Add elements and print ArrayList
✅ Requirements:
Create an ArrayList.
Add 5 elements.
Solution:
import java.util.ArrayList;
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Mango");
fruits.add("Orange");
fruits.add("Pineapple");
⚡ Interviewer Tip:
Don't use .toString() directly unless asked — prefer using enhanced for-loop ( for-each ) when they
say "print elements one-by-one".
Data Structures 13
Example:
Input → [1,2,3,2,1,4,5]
Output → [1,2,3,4,5]
import java.util.ArrayList;
import java.util.LinkedHashSet;
⚡ Interviewer Tip:
If they ask, "How will you remove duplicates without changing order?"
Example:
Input →
List1 = [1, 2, 3, 4, 5]
List2 = [3, 4, 5, 6, 7]
Output →
Common = [3, 4, 5]
Data Structures 14
Solution:
import java.util.ArrayList;
⚡ Interviewer Tip:
If they ask: "Can you optimize this for large lists?"
import java.util.*;
Data Structures 15
System.out.println("Common Elements: " + common);
}
}
Solution:
import java.util.ArrayList;
import java.util.Collections;
int n = list.size();
for (int i = 0; i < n / 2; i++) {
int temp = list.get(i);
list.set(i, list.get(n - i - 1));
list.set(n - i - 1, temp);
}
⚡ Interviewer Tip:
Collections.reverse(list); is the shortcut — but in real interviews they ask you to do without in-built
methods!
Data Structures 16
📍🚀 Now as per your plan: Going to HARD Problems!
🧠 HARD LEVEL PROBLEMS on ArrayList
🔥ArrayList!)
Problem 5: Implement a Custom Dynamic Array (like your own
✅ Requirements:
Create your own class MyArrayList .
It should:
public MyArrayList() {
capacity = 10;
data = new Object[capacity];
size = 0;
}
Data Structures 17
}
for (int i = index; i < size - 1; i++) {
data[i] = data[i + 1];
}
size--;
}
Solution (Simple):
import java.util.ArrayList;
Data Structures 18
list.add(1); list.add(5); list.add(7); list.add(-1); list.add(5);
int target = 6;
Medium Tasks:
3. Reverse an ArrayList of Characters manually.
4. Find and print all unique elements (appearing only once) from an ArrayList.
Hard Task:
5. Build your own
MyArrayListV2 class, but with an extra feature:
Add a shrink() method that halves the capacity if size drops to less than 50% of capacity.
ArrayList is a resizable array implementation of the List interface. Unlike arrays, which have
a fixed size, ArrayLists can dynamically grow or shrink in size.
Arrays can hold both primitive types and objects, whereas ArrayLists can only hold objects.
Data Structures 19
ArrayList maintains an internal array to store elements. When the number of elements
exceeds the current capacity, it creates a new array with increased capacity (typically 1.5
times the old capacity) and copies the old elements to the new array.
Alternatively, use CopyOnWriteArrayList for concurrent read operations with infrequent writes.
6. What is the difference between remove(int index) and remove(Object o) methods in ArrayList?
Ascending: Collections.sort(list);
removeAll(Collection<?> c) removes all elements that are also contained in the specified collection.
It increases the capacity of the ArrayList instance, if necessary, to ensure that it can hold at
least the number of elements specified by the minimum capacity argument.
Since ArrayList is not synchronized, concurrent modifications can lead to inconsistent state
or ConcurrentModificationException . Proper synchronization or concurrent collections should be
Data Structures 20
used.
Convert the list to a Set (e.g., LinkedHashSet to maintain order) and back to a list:
Access: O(1)
Search: O(n)
Example:
🔸 Intermediate Level
1. Merge two ArrayLists and remove duplicates.
🔸 Advanced Level
1. Implement a custom ArrayList class with basic functionalities.
Data Structures 21
//arraylist demo
import java.util.*;
// 2. Adding Elements
list.add("Apple");
list.add("Banana");
list.add("Cherry");
list.add("Date");
list.add("Elderberry");
// 6. Updating an Element
list.set(1, "Blackberry");
System.out.println("After set(1, \"Blackberry\"): " + list);
// 7. Retrieving an Element
String fruit = list.get(2);
System.out.println("Element at index 2: " + fruit);
Data Structures 22
// 10. Checking Size of List
System.out.println("Size of list: " + list.size());
Data Structures 23
List<String> sublist = list.subList(1, 3);
System.out.println("Sublist (1 to 3): " + sublist);
1. Creating an ArrayList
Definition: An ArrayList is created using the constructor new ArrayList<>() , which initializes the list
with the default capacity (10).
Syntax:
Usage: This is the foundation of using the ArrayList in Java. It is often used in problems where
we need to maintain a dynamic list of items (like strings, integers, etc.).
Space Complexity: O(n) where n is the number of elements added to the list.
2. Adding Elements
list.add("Apple");
list.add("Banana");
list.add("Cherry");
list.add("Date");
list.add("Elderberry");
Syntax:
list.add(element);
Data Structures 24
Time Complexity:
Interview Questions:
Q: What happens when the list reaches its capacity and you add another element?
A: The ArrayList automatically resizes its internal array (doubling its size) when the list
exceeds its current capacity.
list.add(2, "Blueberry");
System.out.println("After add(2, \"Blueberry\"): " + list);
Definition: Adds an element at a specified index in the list. All elements after the specified index
are shifted one position to the right.
Syntax:
list.add(index, element);
Usage: Useful when you want to insert an element at a particular position in the list, not just at
the end.
Time Complexity: O(n), where n is the number of elements after the specified index.
Interview Questions:
Q: What happens if you try to add an element at an index greater than the size of the list?
A: An IndexOutOfBoundsException is thrown.
list.remove(3);
System.out.println("After remove(3): " + list);
Definition: Removes the element at the specified index in the list. The elements after the
removed element are shifted to fill the gap.
Syntax:
list.remove(index);
Time Complexity: O(n), where n is the number of elements after the specified index.
Data Structures 25
Space Complexity: O(1).
Interview Questions:
list.remove("Elderberry");
System.out.println("After remove(\"Elderberry\"): " + list);
Definition: Removes the first occurrence of the specified element from the list. If the element is
not found, the list remains unchanged.
Syntax:
list.remove(element);
Usage: Useful when you want to remove an element by its value (not by index).
Time Complexity: O(n), where n is the size of the list, because it searches for the element first.
Interview Questions:
Q: Can you remove an element from an ArrayList that doesn’t exist in the list?
6. Updating an Element
list.set(1, "Blackberry");
System.out.println("After set(1, \"Blackberry\"): " + list);
Definition: Replaces the element at the specified index with the new element.
Syntax:
list.set(index, element);
Usage: Used when you want to replace an existing element with a new one at a specific index.
Time Complexity: O(1), since you're directly updating the element at the given index.
Interview Questions:
7. Retrieving an Element
Data Structures 26
String fruit = list.get(2);
System.out.println("Element at index 2: " + fruit);
Syntax:
list.get(index);
Usage: Used when you want to access an element at a specific index in the list.
Interview Questions:
Definition: Checks if the list contains the specified element. Returns true if the element is
found, otherwise returns false .
Syntax:
list.contains(element);
Time Complexity: O(n), where n is the size of the list, because it needs to search for the
element.
Interview Questions:
A: The contains() method will return true if null is present in the list or false if it’s not.
Definition: Returns the index of the first occurrence of the specified element in the list. If the
element is not found, it returns 1 .
Data Structures 27
Syntax:
list.indexOf(element);
Usage: Useful when you need to find the position of a specific element in the list.
Time Complexity: O(n), where n is the size of the list, because it searches for the element.
Interview Questions:
Q: What will be the output if the element is not present in the list?
A: It will return 1 .
Syntax:
list.size();
Usage: Used to check how many elements are currently in the list.
Interview Questions:
A: Yes, size() returns 0 if the list is empty, so you can use that to check.
Definition: A traditional for loop is used to iterate through the list and access elements by
index.
Syntax:
Data Structures 28
Usage: Common in scenarios where you need to access elements based on their index. It is
preferred for general iteration over an array or list.
Interview Questions:
Q: How can you improve the performance if you have to access the same list multiple
times?
A: You can use a ListIterator for bi-directional iteration or use an enhanced for loop for
readability.
Definition: The enhanced for loop simplifies iteration over a collection without needing to
manage indices.
Syntax:
Usage: Preferred when you do not need the index of elements, making the code more readable
and compact.
Interview Questions:
Q: Can you modify the elements of the list using the enhanced for loop?
Definition: An Iterator provides a way to traverse a collection while also allowing removal of
elements during iteration.
Syntax:
Data Structures 29
Iterator<Type> iterator = collection.iterator();
while (iterator.hasNext()) {
Type element = iterator.next();
}
Usage: Used when you need to remove elements during iteration or just need a safe,
standardized way to traverse.
Interview Questions:
A: Yes, you can use iterator.remove() to safely remove elements during iteration.
Definition: A ListIterator extends Iterator and allows both forward and backward iteration.
Syntax:
Usage: Useful when you need to iterate in both directions or modify elements during iteration.
Interview Questions:
Data Structures 30
A: ListIterator allows both forward and backward iteration, while Iterator only allows forward
iteration.
Collections.sort(list);
Syntax:
Collections.sort(list);
// Or for custom sorting
Collections.sort(list, comparator);
Usage: Used to sort the elements in ascending order (or based on a custom order defined by a
comparator).
Time Complexity: O(n log n) due to the sorting algorithm (typically merge sort or quicksort).
Space Complexity: O(n) for the temporary array used by the sorting algorithm.
Interview Questions:
Collections.reverse(list);
Syntax:
Collections.reverse(list);
Usage: Used when you need to reverse the elements of a list, often useful in algorithms.
Interview Questions:
A: Yes, it simply reverses the current order without modifying the elements themselves.
Data Structures 31
Definition: Creates a view of a portion of the list from the start index to the end index
(exclusive).
Syntax:
list.subList(fromIndex, toIndex);
Usage: Useful when you need to work with a portion of the list without modifying the original
list.
Space Complexity: O(1), since it's a view and not a new list.
Interview Questions:
A: Yes, any modification in the sublist will affect the original list, as it’s just a view.
Syntax:
list.toArray(new Type[0]);
Usage: When you need to work with the list as an array, often required by methods that accept
arrays as input.
Interview Questions:
A: new String[0] is a better practice as it avoids unnecessary array resizing and allows for type
safety.
list.clear();
Syntax:
list.clear();
Usage: Used when you need to empty a list without losing the list object itself.
Data Structures 32
Time Complexity: O(n), where n is the size of the list.
Interview Questions:
Syntax:
list.isEmpty();
Interview Questions:
A: Yes, it’s often used in conjunction with other operations to avoid errors such as
IndexOutOfBoundsException .
This concludes the detailed explanation of all the methods in the ArrayListDemo program. Would you
like to proceed with any specific interview questions, tricky problems, or examples based on these
methods?
📜 Formal Definition:
Collection is a container that holds multiple objects together and provides
methods to manipulate (add, remove, search, sort) them efficiently.
Simple words:
Data Structures 33
What is a Collection? — Deeper Dive
A Collection is a fundamental concept in Java used to group multiple objects together and perform
operations on them.
Think of it as a container that holds multiple items, whether they are related or not.
Example: You want to store 5 integers (numbers). Without collections, you would need 5
variables:
Flexibility: Collections allow you to dynamically add/remove elements without worrying about
the size. Arrays, on the other hand, have fixed size.
Manual management: You had to manually resize arrays or shift elements around when adding
or removing items.
For example:
Data Structures 34
💡 What’s Inside the Framework?
1. Interfaces: Define the contract for what operations can be performed (e.g., adding elements,
removing elements).
Key interfaces:
Examples:
3. Algorithms: Operations like sorting, shuffling, searching are available as static utility methods
in the Collections class.
2. Efficient Algorithms: Many standard algorithms (like sorting, searching, etc.) are built-in.
3. Dynamic Growth: Collections can automatically grow in size (dynamic resizing), whereas
arrays cannot.
Collection: This is the root interface. It provides basic methods that are common to all
collections, such as add() , remove() , size() , etc.
Data Structures 35
List, Set, Queue: These are sub-interfaces that extend Collection and define specific behaviors.
In Java, I wanted to create a unified approach that could handle all types of collections efficiently,
while also being flexible enough to support various use cases. So, the Java Collections Framework
(JCF) was born.
3. Performance Optimization:
Different types of collections perform better in different situations. For example, you wouldn’t
want to use an
ArrayList if you needed fast insertions in the middle of the list; similarly, a HashMap may be
much more efficient than a TreeMap for lookups. By introducing a variety of collection classes,
Data Structures 36
Java allowed developers to pick the most appropriate data structure based on their
performance needs.
List: A List is an ordered collection, meaning the order of insertion is preserved. It allows
duplicates and is great when you need to maintain the order of elements (e.g., when you’re
working with ordered data or need to access elements by their index).
Example Use Case: When you need to store a list of names and want to maintain their
order, like a list of players in a team.
Set: A Set is unordered and doesn’t allow duplicates. It was created to ensure that each
element appears only once, which is useful when you need to check for uniqueness or perform
set operations (like union, intersection, etc.).
Example Use Case: When you want to store a list of student IDs but don’t care about the
order and want to ensure that each ID appears only once.
However, LinkedList is slower for random access (like accessing an element by index) because it
has to traverse the list from the beginning to find the right node.
Example Use Case for LinkedList: If you need to frequently add or remove elements from the
middle of a list, like in a queue or a real-time data stream.
Example Use Case for ArrayList: If you need fast random access to elements (e.g., getting the
10th element directly), then an ArrayList is better.
HashMap: HashMap is backed by a hash table and offers constant-time O(1) performance for
get() and put() operations, assuming a good hash function. It’s great when you need fast
lookups and don’t care about the order of the keys.
Example Use Case: When you need fast lookups or need to store things like user IDs and
names, where order doesn’t matter.
TreeMap: TreeMap, on the other hand, is backed by a Red-Black tree and provides log(n) time
complexity for most operations. It maintains the keys in sorted order. It’s slower than HashMap
Data Structures 37
for most operations but is useful when you need the keys to be sorted, such as when you need
to display or process them in a certain order.
Example Use Case: When you need to store values in sorted order, like storing students'
scores and displaying them in increasing order of score.
By knowing the performance characteristics, you can optimize your code and make smart
choices based on the problem at hand (e.g., whether to use a LinkedList or ArrayList, or a
HashMap or TreeMap).
Understanding the underlying implementation helps you make better trade-offs, improving
your program’s efficiency and ensuring that it performs well in real-world scenarios.
Ultimately, knowing why collections were created helps you become a more efficient, thoughtful
developer and ensures that you use Java’s powerful collections to their fullest potential.
You must manually keep track of how many elements are in the array.
"The Java Collection Framework is a set of interfaces and classes that allow
us to handle groups of objects in a standardized way. It provides several
built-in data structures like lists, sets, queues, and maps, which provide
uniform operations such as adding, removing, and searching for elements.
The framework allows dynamic resizing of collections and provides thread-
safe operations, making it easier and more efficient to manage groups of
objects.
The core idea behind it was to solve problems in earlier versions of Java
where data structures like arrays, vectors, and hashtables were used but
lacked flexibility and efficiency."
✅ Speak slowly.
✅ Focus on why Collection Framework came.
✅ Summary for Step 1:
A Collection is a group of objects that allows you to store, manage, and manipulate them
efficiently.
Before the Collection Framework, there were limitations with arrays, vectors, and hashtables.
Data Structures 39
🧑💻 Quick Target Check for Today:
1. Read through the Collection Framework basics.
Once you're confident with today's deep dive, let me know — and we’ll move to Phase 2: Deep
Dive into the List Interface tomorrow! 🎯
LinkedList
Data Structures 40