Array Basics
Array Basics
Arrays are the most fundamental data structure in programming. Understanding arrays deeply is essential for mastering algorithms and data structures.
An array is a collection of elements stored in contiguous memory locations, allowing fast access to any element by its index.
Goal: Master array fundamentals, common operations, and recognize when arrays are the right choice.
Key Insight: Arrays provide O(1) random access but O(n) insertion/deletion. This trade-off makes them perfect for scenarios where you frequently access elements by index but rarely modify the structure.
What is an Array?
Array: A collection of elements of the same type stored in contiguous memory locations.
Key Properties:
- ›Fixed size (in most languages)
- ›Indexed starting from 0
- ›Homogeneous (same data type)
- ›Contiguous memory (elements stored sequentially)
Real-World Analogy:
Think of an array like apartment buildings:
- ›Each apartment has a number (index)
- ›All apartments are in the same building (contiguous)
- ›You can instantly find apartment #5 without checking #1-4
- ›Adding a new apartment requires rebuilding (insertion is costly)
Memory Layout:
Array: [10, 20, 30, 40, 50]
Index: 0 1 2 3 4
Memory:
┌────┬────┬────┬────┬────┐
│ 10 │ 20 │ 30 │ 40 │ 50 │
└────┴────┴────┴────┴────┘
1000 1004 1008 1012 1016 (memory addresses)
Each element is 4 bytes apart (for integers).
Array Declaration and Initialization
Static Arrays (Fixed Size)
1# Python uses lists (dynamic arrays) by default
2# But we can demonstrate fixed-size behavior
3
4# Method 1: Initialize with values
5arr = [1, 2, 3, 4, 5]
6
7# Method 2: Initialize with size (all zeros)
8arr = [0] * 5 # [0, 0, 0, 0, 0]
9
10# Method 3: Empty list
11arr = []
12
13# Method 4: Using array module (true arrays)
14import array
15arr = array.array('i', [1, 2, 3, 4, 5]) # 'i' = integer type
16
17# Access elements
18print(arr[0]) # Output: 1
19print(arr[2]) # Output: 3Dynamic Arrays (Variable Size)
1# Python lists are dynamic by default
2
3# Create empty list
4arr = []
5
6# Add elements dynamically
7arr.append(10) # [10]
8arr.append(20) # [10, 20]
9arr.append(30) # [10, 20, 30]
10
11# Insert at specific position
12arr.insert(1, 15) # [10, 15, 20, 30]
13
14# Remove element
15arr.remove(15) # [10, 20, 30]
16
17# Pop (remove and return last)
18last = arr.pop() # last=30, arr=[10, 20]
19
20# Length
21print(len(arr)) # Output: 2Basic Array Operations
1. Accessing Elements - O(1)
Random access is the superpower of arrays!
1arr = [10, 20, 30, 40, 50]
2
3# Access by index
4print(arr[0]) # Output: 10 (first element)
5print(arr[2]) # Output: 30
6print(arr[-1]) # Output: 50 (last element, Python only)
7
8# Modify element
9arr[2] = 35
10print(arr) # Output: [10, 20, 35, 40, 50]
11
12# Out of bounds raises IndexError
13# print(arr[10]) # Error!2. Traversing (Iterating) - O(n)
Visit every element in the array.
1arr = [10, 20, 30, 40, 50]
2
3# Method 1: For loop with index
4for i in range(len(arr)):
5 print(arr[i], end=' ')
6print() # Output: 10 20 30 40 50
7
8# Method 2: For-each loop (Pythonic)
9for num in arr:
10 print(num, end=' ')
11print() # Output: 10 20 30 40 50
12
13# Method 3: With index using enumerate
14for i, num in enumerate(arr):
15 print(f"arr[{i}] = {num}")3. Searching - O(n) Linear, O(log n) Binary
Find if an element exists in the array.
Linear Search (Unsorted Array):
1def linear_search(arr, target):
2 for i in range(len(arr)):
3 if arr[i] == target:
4 return i # Found at index i
5 return -1 # Not found
6
7# Example
8arr = [10, 20, 30, 40, 50]
9print(linear_search(arr, 30)) # Output: 2
10print(linear_search(arr, 35)) # Output: -1Binary Search (Sorted Array):
1def binary_search(arr, target):
2 left, right = 0, len(arr) - 1
3
4 while left <= right:
5 mid = (left + right) // 2
6
7 if arr[mid] == target:
8 return mid # Found
9 elif arr[mid] < target:
10 left = mid + 1 # Search right half
11 else:
12 right = mid - 1 # Search left half
13
14 return -1 # Not found
15
16# Example (array must be sorted!)
17arr = [10, 20, 30, 40, 50]
18print(binary_search(arr, 30)) # Output: 2
19print(binary_search(arr, 35)) # Output: -14. Insertion - O(n)
Insert an element at a specific position.
1# Python lists handle insertion automatically
2arr = [10, 20, 30, 50]
3
4# Insert 40 at index 3
5arr.insert(3, 40)
6print(arr) # Output: [10, 20, 30, 40, 50]
7
8# Manual implementation (for fixed-size array simulation)
9def insert_at(arr, pos, value):
10 arr.append(0) # Make space
11 # Shift elements to the right
12 for i in range(len(arr) - 1, pos, -1):
13 arr[i] = arr[i - 1]
14 arr[pos] = value
15 return arr
16
17arr = [10, 20, 30, 50]
18arr = insert_at(arr, 3, 40)
19print(arr) # Output: [10, 20, 30, 40, 50]Why O(n)? Must shift all elements after the insertion point.
5. Deletion - O(n)
Remove an element from a specific position.
1arr = [10, 20, 30, 40, 50]
2
3# Remove by index
4del arr[2] # Removes element at index 2
5print(arr) # Output: [10, 20, 40, 50]
6
7# Remove by value
8arr.remove(40) # Removes first occurrence of 40
9print(arr) # Output: [10, 20, 50]
10
11# Manual implementation
12def delete_at(arr, pos):
13 # Shift elements to the left
14 for i in range(pos, len(arr) - 1):
15 arr[i] = arr[i + 1]
16 arr.pop() # Remove last element
17 return arr
18
19arr = [10, 20, 30, 40, 50]
20arr = delete_at(arr, 2)
21print(arr) # Output: [10, 20, 40, 50]Why O(n)? Must shift all elements after the deletion point.
Array Operations Complexity Summary
| Operation | Time Complexity | Explanation |
|---|---|---|
| Access | O(1) | Direct index calculation |
| Search | O(n) linear, O(log n) binary | Must check each element / binary split |
| Insert at end | O(1) amortized | Append is fast |
| Insert at position | O(n) | Must shift elements |
| Delete at end | O(1) | Pop is fast |
| Delete at position | O(n) | Must shift elements |
| Traverse | O(n) | Visit each element once |
Multi-Dimensional Arrays
2D Arrays (Matrices)
1# Method 1: List of lists
2matrix = [
3 [1, 2, 3],
4 [4, 5, 6],
5 [7, 8, 9]
6]
7
8# Access element
9print(matrix[1][2]) # Output: 6 (row 1, col 2)
10
11# Traverse 2D array
12for i in range(len(matrix)):
13 for j in range(len(matrix[i])):
14 print(matrix[i][j], end=' ')
15 print()
16
17# Method 2: Initialize with zeros
18rows, cols = 3, 4
19matrix = [[0] * cols for _ in range(rows)]Common Array Patterns
Pattern 1: Two Pointers
Use two pointers moving toward each other.
1def reverse_array(arr):
2 left, right = 0, len(arr) - 1
3
4 while left < right:
5 # Swap elements
6 arr[left], arr[right] = arr[right], arr[left]
7 left += 1
8 right -= 1
9
10 return arr
11
12# Example
13arr = [1, 2, 3, 4, 5]
14print(reverse_array(arr)) # Output: [5, 4, 3, 2, 1]Pattern 2: Sliding Window
Maintain a window of fixed or variable size.
1def max_sum_subarray(arr, k):
2 # Find maximum sum of k consecutive elements
3 n = len(arr)
4 if n < k:
5 return -1
6
7 # Calculate sum of first window
8 window_sum = sum(arr[:k])
9 max_sum = window_sum
10
11 # Slide the window
12 for i in range(k, n):
13 window_sum = window_sum - arr[i - k] + arr[i]
14 max_sum = max(max_sum, window_sum)
15
16 return max_sum
17
18# Example
19arr = [1, 4, 2, 10, 23, 3, 1, 0, 20]
20k = 4
21print(max_sum_subarray(arr, k)) # Output: 39 (10+23+3+1)Pattern 3: Kadane's Algorithm
Find maximum subarray sum.
1def max_subarray_sum(arr):
2 max_sum = arr[0]
3 current_sum = arr[0]
4
5 for i in range(1, len(arr)):
6 # Either extend current subarray or start new
7 current_sum = max(arr[i], current_sum + arr[i])
8 max_sum = max(max_sum, current_sum)
9
10 return max_sum
11
12# Example
13arr = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
14print(max_subarray_sum(arr)) # Output: 6 (subarray [4,-1,2,1])When to Use Arrays
✅ Use Arrays When:
- ›Need random access - O(1) access by index
- ›Fixed size known - Size doesn't change
- ›Sequential data - Data naturally ordered
- ›Memory efficiency - Contiguous storage is cache-friendly
- ›Simple iteration - Processing all elements in order
❌ Avoid Arrays When:
- ›Frequent insertions/deletions - O(n) cost is too high
- ›Dynamic size - Size changes frequently (use dynamic arrays/lists)
- ›Sparse data - Many unused elements waste memory
- ›Need fast search - Use hash table for O(1) search
- ›Complex structure - Need hierarchical data (use trees)
Common Mistakes
Mistake 1: Off-by-One Errors
1arr = [1, 2, 3, 4, 5]
2
3# Wrong: Goes out of bounds
4for i in range(len(arr) + 1): # ❌ Bug!
5 print(arr[i]) # IndexError on last iteration
6
7# Correct
8for i in range(len(arr)): # ✅ Correct
9 print(arr[i])Mistake 2: Not Checking Bounds
1def get_element(arr, index):
2 # Wrong: No bounds checking
3 return arr[index] # ❌ May crash
4
5# Correct: Check bounds
6def get_element_safe(arr, index):
7 if 0 <= index < len(arr):
8 return arr[index]
9 return None # Or raise exceptionKey Takeaways
Array Fundamentals:
Definition: Contiguous memory storage with fixed size and O(1) access
Strengths:
- ›O(1) random access by index
- ›Memory efficient (cache-friendly)
- ›Simple to use and understand
Weaknesses:
- ›O(n) insertion/deletion at arbitrary positions
- ›Fixed size (in most languages)
- ›Wasted space if not fully utilized
Common Operations:
- ›Access: O(1)
- ›Search: O(n) linear, O(log n) binary (if sorted)
- ›Insert/Delete: O(n)
Key Patterns:
- ›Two pointers for reversals and searches
- ›Sliding window for subarray problems
- ›Kadane's algorithm for maximum subarray
Remember: Arrays are perfect when you need fast random access but rarely modify the structure
What's Next?
Now that you understand arrays:
- ›Sorting Algorithms - Learn to sort arrays efficiently
- ›Two Pointers Pattern - Master array manipulation
- ›Dynamic Arrays - Understand ArrayList/Vector internals
Practice Problems
Problem 1: Find Second Largest
Find the second largest element in an array.
Problem 2: Remove Duplicates
Remove duplicates from a sorted array in-place.
Problem 3: Rotate Array
Rotate an array to the right by k steps.
Problem 4: Missing Number
Find the missing number in array containing n-1 distinct numbers from 1 to n.
Congratulations! You now understand arrays deeply and can use them effectively!