DSA Concepts
Quick reference guide for Java Data Structure and Algorithms.
🔢 Arrays
// 1) Declaring and initializing arrays
int[] numbers = new int[5]; // Fixed-size array with default values (0)
int[] primes = {2, 3, 5, 7, 11}; // Array literal
String[] fruits = new String[3]; // Array of Strings (null by default)
// 2) Accessing elements
int firstPrime = primes[0]; // Access by index (zero-based): 2
primes[4] = 13; // Modify element
// 3) Array properties
int length = primes.length; // Array length: 5
// 4) Multi-dimensional arrays
int[][] matrix = new int[3][3]; // 3x3 matrix with default values
int[][] grid = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}; // 2D array literal
// Accessing elements in 2D array
int center = grid[1][1]; // 5
// 5) Array utilities (java.util.Arrays)
import java.util.Arrays;
// Sorting
int[] unsorted = {5, 2, 8, 1, 9};
Arrays.sort(unsorted); // Sorts in-place: [1, 2, 5, 8, 9]
// Binary search (on sorted array)
int index = Arrays.binarySearch(unsorted, 5); // Returns index: 2
// Fill
int[] zeros = new int[5];
Arrays.fill(zeros, 0); // [0, 0, 0, 0, 0]
// Copy
int[] copy = Arrays.copyOf(primes, primes.length);
int[] partial = Arrays.copyOfRange(primes, 1, 4); // [3, 5, 7]
// Compare
boolean equal = Arrays.equals(primes, copy); // true
// Convert to String
String arrayStr = Arrays.toString(primes); // "[2, 3, 5, 7, 13]"
// 6) Dynamic arrays (ArrayList)
import java.util.ArrayList;
ArrayList<Integer> dynamicArray = new ArrayList<>();
dynamicArray.add(10); // Add to end
dynamicArray.add(20); // [10, 20]
dynamicArray.add(0, 5); // Add at index: [5, 10, 20]
dynamicArray.set(1, 15); // Replace: [5, 15, 20]
int value = dynamicArray.get(0); // Get by index: 5
dynamicArray.remove(2); // Remove by index: [5, 15]
int size = dynamicArray.size(); // Size: 2
boolean contains = dynamicArray.contains(15); // true
📋 Lists
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Arrays;
// 1) ArrayList (dynamic array implementation)
List<String> namesList = new ArrayList<>();
namesList.add("Alice"); // Add element
namesList.add("Bob");
namesList.add("Charlie");
// Common list operations
namesList.add(1, "David"); // Insert at index: [Alice, David, Bob, Charlie]
namesList.set(2, "Eve"); // Replace: [Alice, David, Eve, Charlie]
namesList.remove("Eve"); // Remove by value: [Alice, David, Charlie]
namesList.remove(0); // Remove by index: [David, Charlie]
boolean exists = namesList.contains("David"); // true
int size = namesList.size(); // 2
boolean empty = namesList.isEmpty(); // false
String first = namesList.get(0); // "David"
// 2) LinkedList (doubly-linked list implementation)
List<Integer> linkedNumbers = new LinkedList<>();
linkedNumbers.add(10);
linkedNumbers.add(20);
linkedNumbers.add(30);
// LinkedList specific operations
LinkedList<Integer> numbers = (LinkedList<Integer>) linkedNumbers;
numbers.addFirst(5); // Add to front: [5, 10, 20, 30]
numbers.addLast(40); // Add to end: [5, 10, 20, 30, 40]
int first = numbers.getFirst(); // 5
int last = numbers.getLast(); // 40
numbers.removeFirst(); // [10, 20, 30, 40]
numbers.removeLast(); // [10, 20, 30]
// 3) Creating lists from arrays
List<String> fixedList = Arrays.asList("Red", "Green", "Blue");
// fixedList.add("Yellow"); // Error: Fixed size!
// Java 9+ immutable lists
List<String> immutableList = List.of("Red", "Green", "Blue");
// 4) Iterating through lists
// Using for-each loop
for (String name : namesList) {
System.out.println(name);
}
// Using iterator
import java.util.Iterator;
Iterator<String> it = namesList.iterator();
while (it.hasNext()) {
String name = it.next();
// it.remove(); // Safe removal during iteration
}
// Using forEach method (Java 8+)
namesList.forEach(name -> System.out.println(name));
// 5) Sorting lists
import java.util.Collections;
Collections.sort(namesList); // Natural ordering
// Custom comparator
import java.util.Comparator;
Collections.sort(namesList, Comparator.reverseOrder());
// Java 8+
namesList.sort(Comparator.naturalOrder());
🔍 Sets
import java.util.Set;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.LinkedHashSet;
// 1) HashSet (unordered, fastest)
Set<String> fruits = new HashSet<>();
fruits.add("Apple"); // Add element
fruits.add("Banana");
fruits.add("Apple"); // Duplicate ignored
System.out.println(fruits); // [Banana, Apple] (order not guaranteed)
boolean contains = fruits.contains("Apple"); // true
fruits.remove("Banana"); // Remove element
int size = fruits.size(); // 1
// 2) TreeSet (sorted)
Set<Integer> numbers = new TreeSet<>();
numbers.add(5);
numbers.add(1);
numbers.add(10);
System.out.println(numbers); // [1, 5, 10] (natural ordering)
// TreeSet with custom comparator
Set<String> orderedStrings = new TreeSet<>(Comparator.comparing(String::length));
orderedStrings.add("aaa");
orderedStrings.add("b");
orderedStrings.add("cc");
System.out.println(orderedStrings); // [b, cc, aaa] (ordered by length)
// 3) LinkedHashSet (insertion-ordered)
Set<String> orderedFruits = new LinkedHashSet<>();
orderedFruits.add("Banana");
orderedFruits.add("Apple");
orderedFruits.add("Orange");
System.out.println(orderedFruits); // [Banana, Apple, Orange] (insertion order)
// 4) Set operations
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> set2 = new HashSet<>(Arrays.asList(4, 5, 6, 7, 8));
// Union
Set<Integer> union = new HashSet<>(set1);
union.addAll(set2); // [1, 2, 3, 4, 5, 6, 7, 8]
// Intersection
Set<Integer> intersection = new HashSet<>(set1);
intersection.retainAll(set2); // [4, 5]
// Difference
Set<Integer> difference = new HashSet<>(set1);
difference.removeAll(set2); // [1, 2, 3]
// Subset testing
boolean isSubset = set1.containsAll(intersection); // true
// 5) Iterating through sets
for (String fruit : fruits) {
System.out.println(fruit);
}
// 6) Creating immutable sets (Java 9+)
Set<String> immutableSet = Set.of("Red", "Green", "Blue");
🔑 Maps
import java.util.Map;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.LinkedHashMap;
// 1) HashMap (unordered, fastest)
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 30); // Add key-value pair
ages.put("Bob", 25);
ages.put("Charlie", 35);
// 2) Accessing elements
int aliceAge = ages.get("Alice"); // 30
Integer davidAge = ages.get("David"); // null
int defaultAge = ages.getOrDefault("David", 0); // 0
boolean exists = ages.containsKey("Bob"); // true
boolean hasAge30 = ages.containsValue(30); // true
// 3) Updating and removing
ages.put("Bob", 26); // Update value
ages.remove("Charlie"); // Remove key-value pair
// 4) Map properties
int size = ages.size(); // 2
boolean isEmpty = ages.isEmpty(); // false
// 5) Views of the map
Set<String> keys = ages.keySet(); // [Alice, Bob]
Collection<Integer> values = ages.values(); // [30, 26]
Set<Map.Entry<String, Integer>> entries = ages.entrySet();
// 6) TreeMap (sorted by keys)
Map<String, String> employees = new TreeMap<>();
employees.put("C123", "Charlie");
employees.put("A789", "Alice");
employees.put("B456", "Bob");
System.out.println(employees); // {A789=Alice, B456=Bob, C123=Charlie}
// 7) LinkedHashMap (insertion order)
Map<String, Double> prices = new LinkedHashMap<>();
prices.put("Banana", 1.99);
prices.put("Apple", 0.99);
prices.put("Orange", 1.49);
System.out.println(prices); // {Banana=1.99, Apple=0.99, Orange=1.49}
// 8) Iterating through maps
// Over keys
for (String name : ages.keySet()) {
System.out.println(name + " is " + ages.get(name) + " years old");
}
// Over entries
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + " is " + entry.getValue() + " years old");
}
// Java 8+ forEach
ages.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));
// 9) Immutable maps (Java 9+)
Map<String, Integer> immutableMap = Map.of(
"Red", 1,
"Green", 2,
"Blue", 3
);
// 10) Specialized maps
// LinkedHashMap with access-order (LRU cache)
Map<String, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > 3; // Maximum size of 3
}
};
🔄 Collections Utilities
import java.util.*;
// 1) Sorting
List<Integer> numbers = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9));
Collections.sort(numbers); // [1, 2, 5, 8, 9]
Collections.sort(numbers, Collections.reverseOrder()); // [9, 8, 5, 2, 1]
// 2) Searching
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
int index = Collections.binarySearch(names, "Charlie"); // 2 (requires sorted list)
// 3) Min/Max
int min = Collections.min(numbers); // 1
int max = Collections.max(numbers); // 9
// Custom comparator
String shortest = Collections.min(names, Comparator.comparing(String::length)); // "Bob"
// 4) Frequency and disjoint
List<String> letters = Arrays.asList("a", "b", "a", "c", "a");
int freq = Collections.frequency(letters, "a"); // 3
boolean disjoint = Collections.disjoint(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5, 6)
); // true - no elements in common
// 5) Fill, copy, and replace
List<String> filledList = new ArrayList<>(Arrays.asList("", "", ""));
Collections.fill(filledList, "X"); // ["X", "X", "X"]
List<String> source = Arrays.asList("A", "B", "C");
List<String> dest = Arrays.asList("", "", "");
Collections.copy(dest, source); // dest becomes ["A", "B", "C"]
Collections.replaceAll(letters, "a", "z"); // ["z", "b", "z", "c", "z"]
// 6) Unmodifiable views
List<String> readOnlyList = Collections.unmodifiableList(names);
// readOnlyList.add("Eve"); // Throws UnsupportedOperationException
// 7) Synchronized views (thread-safe)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
// 8) Empty collections
List<Object> emptyList = Collections.emptyList();
Set<Object> emptySet = Collections.emptySet();
Map<Object, Object> emptyMap = Collections.emptyMap();
// 9) Singleton collections
Set<String> singletonSet = Collections.singleton("only element");
List<Integer> singletonList = Collections.singletonList(42);
Map<String, Integer> singletonMap = Collections.singletonMap("key", 1);
// 10) Shuffle
List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
Collections.shuffle(deck); // Random order
Collections.shuffle(deck, new Random(42)); // Deterministic shuffle with seed
📊 Queues and Stacks
import java.util.Queue;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.PriorityQueue;
import java.util.Stack;
import java.util.Deque;
// 1) Queue (FIFO - First In, First Out)
Queue<String> queue = new LinkedList<>();
queue.offer("First"); // Add to end
queue.offer("Second");
queue.offer("Third");
String front = queue.peek(); // Examine the front: "First"
String removed = queue.poll(); // Remove and return front: "First"
int size = queue.size(); // 2
// 2) Stack (LIFO - Last In, First Out)
// Using legacy Stack class
Stack<Integer> stack = new Stack<>();
stack.push(1); // Add to top
stack.push(2);
stack.push(3);
int top = stack.peek(); // Examine the top: 3
int popped = stack.pop(); // Remove and return top: 3
boolean empty = stack.empty(); // false
// 3) Deque (double-ended queue)
// Preferred way to implement both stacks and queues
Deque<Integer> deque = new ArrayDeque<>();
// Queue operations
deque.offer(1); // Add to end
deque.offer(2);
deque.poll(); // Remove from front: 1
// Stack operations
deque.push(10); // Add to front
deque.push(20);
deque.pop(); // Remove from front: 20
// Deque-specific operations
deque.offerFirst(0); // Add to front
deque.offerLast(3); // Add to end
deque.peekFirst(); // Examine front
deque.peekLast(); // Examine end
deque.pollFirst(); // Remove from front
deque.pollLast(); // Remove from end
// 4) PriorityQueue (min-heap by default)
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(5);
minHeap.offer(2);
minHeap.offer(8);
minHeap.offer(1);
while (!minHeap.isEmpty()) {
System.out.print(minHeap.poll() + " "); // Prints: 1 2 5 8
}
// Max-heap using custom comparator
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
maxHeap.offer(5);
maxHeap.offer(2);
maxHeap.offer(8);
maxHeap.offer(1);
while (!maxHeap.isEmpty()) {
System.out.print(maxHeap.poll() + " "); // Prints: 8 5 2 1
}
// 5) PriorityQueue with custom objects
class Task implements Comparable<Task> {
String name;
int priority;
Task(String name, int priority) {
this.name = name;
this.priority = priority;
}
@Override
public int compareTo(Task other) {
return Integer.compare(this.priority, other.priority);
}
@Override
public String toString() {
return name + "(" + priority + ")";
}
}
PriorityQueue<Task> tasks = new PriorityQueue<>();
tasks.offer(new Task("Email", 3));
tasks.offer(new Task("Report", 1));
tasks.offer(new Task("Meeting", 2));
while (!tasks.isEmpty()) {
System.out.println(tasks.poll()); // Ordered by priority
}
🧩 Common Algorithms
import java.util.*;
// 1) Binary Search
public static int binarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
}
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // Not found
}
// 2) Sorting algorithms
// Bubble Sort O(n²)
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap arr[j] and arr[j+1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// Merge Sort O(n log n)
public static void mergeSort(int[] arr) {
if (arr.length <= 1) return;
int mid = arr.length / 2;
int[] left = Arrays.copyOfRange(arr, 0, mid);
int[] right = Arrays.copyOfRange(arr, mid, arr.length);
mergeSort(left);
mergeSort(right);
merge(arr, left, right);
}
private static void merge(int[] arr, int[] left, int[] right) {
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
}
}
while (i < left.length) {
arr[k++] = left[i++];
}
while (j < right.length) {
arr[k++] = right[j++];
}
}
// 3) Graph traversal
// BFS (Breadth-First Search)
public static void bfs(Map<Integer, List<Integer>> graph, int start) {
Set<Integer> visited = new HashSet<>();
Queue<Integer> queue = new LinkedList<>();
visited.add(start);
queue.offer(start);
while (!queue.isEmpty()) {
int vertex = queue.poll();
System.out.print(vertex + " ");
for (int neighbor : graph.getOrDefault(vertex, Collections.emptyList())) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
queue.offer(neighbor);
}
}
}
}
// DFS (Depth-First Search)
public static void dfs(Map<Integer, List<Integer>> graph, int start) {
Set<Integer> visited = new HashSet<>();
dfsHelper(graph, start, visited);
}
private static void dfsHelper(Map<Integer, List<Integer>> graph, int vertex, Set<Integer> visited) {
visited.add(vertex);
System.out.print(vertex + " ");
for (int neighbor : graph.getOrDefault(vertex, Collections.emptyList())) {
if (!visited.contains(neighbor)) {
dfsHelper(graph, neighbor, visited);
}
}
}
// 4) Shortest path (Dijkstra's algorithm)
public static Map<Integer, Integer> dijkstra(Map<Integer, Map<Integer, Integer>> graph, int start) {
Map<Integer, Integer> distances = new HashMap<>();
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
Set<Integer> visited = new HashSet<>();
// Initialize distances
for (int node : graph.keySet()) {
distances.put(node, Integer.MAX_VALUE);
}
distances.put(start, 0);
pq.offer(new int[]{start, 0});
while (!pq.isEmpty()) {
int[] current = pq.poll();
int currentNode = current[0];
int currentDist = current[1];
if (visited.contains(currentNode)) continue;
visited.add(currentNode);
for (Map.Entry<Integer, Integer> neighbor : graph.getOrDefault(currentNode, Collections.emptyMap()).entrySet()) {
int neighborNode = neighbor.getKey();
int weight = neighbor.getValue();
if (!visited.contains(neighborNode)) {
int distance = currentDist + weight;
if (distance < distances.get(neighborNode)) {
distances.put(neighborNode, distance);
pq.offer(new int[]{neighborNode, distance});
}
}
}
}
return distances;
}