What is a data structure? A named location that can be used to store and organize data. eg. Array A collection of element stored at contiguous memory locations.
What is an Algorithm? A collection of steps to solve a problem.
💡 THE GOLDEN RULE OF DSA Data Structures are HOW we store data. Algorithms are HOW we solve problems using that data. They work together. You cannot have an efficient algorithm without an appropriate data structure.
Big O Notation measures how well an algorithm scales as the amount of data (n) increases.
- O(1) - Constant Time: Excellent. The operation takes the same amount of time regardless of data size.
- Example: Accessing an array element by index (
arr[5]).
- Example: Accessing an array element by index (
- O(log n) - Logarithmic Time: Very Good. The dataset is halved with each step.
- Example: Binary Search.
- O(n) - Linear Time: Fair. The time grows directly proportional to the data size.
- Example: Looping through an array once.
- O(n log n) - Linearithmic Time: Bad. Typical for good sorting algorithms.
- Example: Merge Sort, Quick Sort.
- O(n²) - Quadratic Time: Terrible. Time grows exponentially with the data size. Nested loops!
- Example: Bubble Sort, Insertion Sort, a loop inside a loop.
- O(2^n) - Exponential Time: Horrible.
- Example: Recursive Fibonacci.
- O(n!) - Factorial Time: Disastrous.
- Example: Generating all permutations of a string.
☕ Hidden Notes for Java Developers
- Primitives (
int,double,boolean) are lightweight and stored directly where they are needed (usually the stack). - Reference Types (Objects, arrays,
String,Integer) store a pointer (reference) to the actual data located on the heap. - Why it matters in DSA: An
int[]is a contiguous block of actual numbers. AnInteger[]orArrayList<Integer>is a contiguous block of pointers pointing to objects scattered around the heap. This causes "cache misses" and is significantly slower for massive datasets.
- In Java,
Stringis immutable (cannot be changed). - Operation:
str += "a"creates a completely new string in memory and copies the old one over. This is O(n) time every single time you do it! - DSA Secret: If you are building or modifying strings in a loop, ALWAYS use
StringBuilder. Itsappend()method is O(1).
- Collections (like
ArrayList,HashMap) have dynamic sizing. - When an
ArrayListhits its capacity, it creates a new array that is 1.5x larger and copies everything over (O(n) operation). - DSA Secret: If you know you are going to put 10,000 items into a list, instantiate it with that capacity:
new ArrayList<>(10000). This prevents expensive resize operations.
- Under the hood,
HashMapuses an array. It takes your key'shashCode(), does some math, and uses that as the array index. - Lookups are O(1) (average case).
- DSA Secret: If you need to repeatedly check "does this item exist?" (like checking for duplicates or seen nodes in a graph), do NOT use
ArrayList.contains()which is O(n). Put them in aHashSetand useset.contains()which is O(1).
- Every recursive call in Java adds a new "frame" to the call stack holding local variables.
- Too many recursive calls =
StackOverflowError. - DSA Secret: Java does not optimize "tail recursion" like some other languages (e.g., Scala). If your algorithm recurses deeply (e.g., 10,000+ times), you must convert it to an iterative approach using a loop and your own
Stackobject.
- Java ALWAYS passes arguments by value.
- However, for objects, the "value" being passed is the reference (the remote control to the object).
- DSA Secret: If you pass an array or a
Listinto a helper function and modify it (e.g.,arr[0] = 5;), those changes will be reflected in the original caller's data. If you reassign the reference itself (e.g.,arr = new int[5];), the original caller sees nothing.