Linear Search Algorithm Explained — How It Works, When to Use It, and Why It Matters
Every app you've ever used searches for something. Your music app searches for a song by name. Your contacts app finds a phone number. Your email client hunts for a message from last Tuesday. Under the hood, all of these rely on some form of search algorithm — a set of steps a computer follows to find a specific piece of data inside a collection. Without search algorithms, every piece of software that handles data would be helpless. Linear search is the most fundamental of them all, and understanding it is the foundation for understanding everything smarter that comes after it.
The problem linear search solves is deceptively simple: given a list of items, find whether a specific target item exists in that list, and if so, tell us exactly where it is. Sounds easy, right? But computers don't have eyes. They can't 'glance' at a list and spot something instantly. They need explicit instructions: start here, check this, move to the next one. Linear search gives them those exact instructions in the most straightforward way possible — check every element, one at a time, from the beginning to the end.
By the end of this article, you'll understand exactly how linear search works step by step, you'll be able to write a complete, working linear search function in Java from memory, you'll know its time and space complexity and what that means in plain English, and you'll know precisely when to reach for it — and when to put it down and use something better. You'll also walk away with the two gotchas that trip up almost every beginner, and the interview answers that will make you sound like you actually understand what's happening under the hood.
How Linear Search Actually Works — Step by Step
Let's make this concrete. Say you have an array of five student ID numbers: [1042, 3387, 2291, 4410, 1895]. You want to find whether ID number 4410 exists in that list.
Linear search does this: it starts at index 0 (the first position) and asks 'is this 4410?' The answer is no — it's 1042. So it moves to index 1 and asks the same question. No, that's 3387. Index 2? No, 2291. Index 3? Yes — 4410 matches! The algorithm stops and reports back: 'Found it at position 3.'
If the target wasn't in the list at all, the algorithm would keep going until it ran out of elements, then report 'not found.' That's it. No magic. No sorting required. No preprocessing. Just a simple, honest loop.
One thing that trips people up early: the algorithm stops as soon as it finds the first match. If your list has duplicates, linear search returns the index of the very first occurrence and doesn't keep looking. This is almost always the right behaviour, but it's worth knowing.
public class LinearSearchBasic { /** * Searches for a target value inside an array of integers. * * @param numbers The array we want to search through * @param target The number we're looking for * @return The index where the target was found, or -1 if it doesn't exist */ public static int linearSearch(int[] numbers, int target) { // Start at the very first element (index 0) and walk forward one step at a time for (int index = 0; index < numbers.length; index++) { // Ask the key question: is THIS element the one we're looking for? if (numbers[index] == target) { // Yes! Stop immediately and report WHERE we found it return index; } // No match — the loop automatically moves to the next index } // If we reach here, we checked every single element and found nothing // Returning -1 is the universal convention for 'not found' return -1; } public static void main(String[] args) { int[] studentIds = {1042, 3387, 2291, 4410, 1895}; int targetId = 4410; int resultIndex = linearSearch(studentIds, targetId); // -1 means the target was not found anywhere in the array if (resultIndex != -1) { System.out.println("Student ID " + targetId + " found at index " + resultIndex); } else { System.out.println("Student ID " + targetId + " does not exist in the list."); } // Now test the 'not found' case int missingId = 9999; int missingResult = linearSearch(studentIds, missingId); if (missingResult != -1) { System.out.println("Student ID " + missingId + " found at index " + missingResult); } else { System.out.println("Student ID " + missingId + " does not exist in the list."); } } }
Student ID 9999 does not exist in the list.
Time and Space Complexity — What It Costs to Run Linear Search
Every algorithm has a cost. That cost is measured in two ways: time (how many steps does it take?) and space (how much extra memory does it need?). Understanding this for linear search is crucial — not because it's hard, but because it's the baseline you'll compare every other search algorithm against for the rest of your career.
Time Complexity — the 'how long' question: In the best case, the target is the very first element. One comparison, done. That's O(1) — constant time. In the worst case, the target is the last element, or it's not in the list at all. You checked every single element — that's n comparisons for a list of n items. That's O(n) — linear time, which is where the algorithm gets its name. On average, you'll find the target somewhere in the middle, which is roughly n/2 comparisons — still O(n) because we drop constants in Big O notation.
Space Complexity — the 'how much memory' question: Linear search is O(1) space. It doesn't create any new arrays or data structures. It just uses a single loop variable (the index counter). No matter if your input has 10 items or 10 million, the extra memory used stays constant.
The honest takeaway: linear search is slow for large datasets but costs almost nothing in memory. It's the algorithm equivalent of a reliable old bicycle — not the fastest thing on the road, but it always gets you there and never breaks down.
public class LinearSearchComplexityDemo { // We'll count comparisons manually so you can SEE the O(n) behaviour public static int linearSearchWithCount(int[] numbers, int target) { int comparisonCount = 0; // Track how many times we check an element for (int index = 0; index < numbers.length; index++) { comparisonCount++; // Every loop iteration is one comparison if (numbers[index] == target) { System.out.println("Found after " + comparisonCount + " comparison(s)."); return index; } } System.out.println("Not found. Made " + comparisonCount + " comparison(s) — checked every element."); return -1; } public static void main(String[] args) { int[] temperatures = {72, 68, 91, 55, 83, 77, 64, 98, 45, 88}; // Array has 10 elements (indices 0 through 9) System.out.println("--- Best Case: Target is the FIRST element ---"); linearSearchWithCount(temperatures, 72); // At index 0 System.out.println(); System.out.println("--- Average Case: Target is somewhere in the MIDDLE ---"); linearSearchWithCount(temperatures, 83); // At index 4 System.out.println(); System.out.println("--- Worst Case: Target is the LAST element ---"); linearSearchWithCount(temperatures, 88); // At index 9 System.out.println(); System.out.println("--- Worst Case: Target does NOT exist ---"); linearSearchWithCount(temperatures, 100); // Not in the array } }
Found after 1 comparison(s).
--- Average Case: Target is somewhere in the MIDDLE ---
Found after 5 comparison(s).
--- Worst Case: Target is the LAST element ---
Found after 10 comparison(s).
--- Worst Case: Target does NOT exist ---
Not found. Made 10 comparison(s) — checked every element.
Linear Search on Strings and Custom Objects — It's Not Just for Numbers
Every example you see in textbooks uses integers. That's fine for learning, but real-world code searches through names, emails, product titles, and custom objects. Linear search works on all of these — the logic is identical. The only thing that changes is how you compare two elements.
With integers, you use ==. With Strings in Java, you must use .equals() — because == on objects checks whether two variables point to the same memory address, not whether they have the same content. This is one of the most common bugs beginners write, and it's the kind of bug that can pass your own manual tests but fail in production when the string comes from user input or a database.
With custom objects (like a Student class), you decide what 'equal' means. You might search by name, by ID, or by email. You write the comparison logic yourself. This makes linear search incredibly flexible — you can search any collection for any criteria without sorting or pre-processing anything first. That flexibility is genuinely valuable in small collections and quick scripts.
public class LinearSearchStringsAndObjects { // --- Searching through an array of Strings --- public static int searchByName(String[] names, String targetName) { for (int index = 0; index < names.length; index++) { // CRITICAL: Use .equals() for Strings, NOT == // .equals() compares the actual text content character by character if (names[index].equals(targetName)) { return index; } } return -1; // Name not found } // --- A simple Student record to demonstrate searching objects --- static class Student { int studentId; String fullName; double gpa; Student(int studentId, String fullName, double gpa) { this.studentId = studentId; this.fullName = fullName; this.gpa = gpa; } } // --- Searching through an array of Student objects by their ID --- public static Student searchById(Student[] roster, int targetId) { for (int index = 0; index < roster.length; index++) { // We define what 'match' means: two students match if their IDs are equal if (roster[index].studentId == targetId) { return roster[index]; // Return the whole Student object, not just the index } } return null; // Convention: return null when a searched object isn't found } public static void main(String[] args) { // --- String search demo --- String[] cityNames = {"Austin", "Denver", "Phoenix", "Nashville", "Portland"}; String searchCity = "Nashville"; int cityIndex = searchByName(cityNames, searchCity); if (cityIndex != -1) { System.out.println(searchCity + " found at index " + cityIndex); } else { System.out.println(searchCity + " is not in the list."); } // --- Object search demo --- Student[] classRoster = { new Student(1001, "Maria Chen", 3.8), new Student(1042, "James Okafor", 3.5), new Student(1087, "Priya Nair", 3.9), new Student(1103, "Lucas Ferreira", 3.2) }; int searchId = 1087; Student foundStudent = searchById(classRoster, searchId); if (foundStudent != null) { System.out.println("Found student: " + foundStudent.fullName + " | GPA: " + foundStudent.gpa); } else { System.out.println("No student with ID " + searchId + " found."); } } }
Found student: Priya Nair | GPA: 3.9
When to Use Linear Search — and When to Walk Away
Linear search isn't a bad algorithm. It's a misused one. Knowing when it's exactly the right tool is what separates a developer who memorised a concept from one who actually understands it.
Use linear search when: Your list is small (under a few hundred items) and performance isn't critical. Your data is unsorted and you can't afford the time to sort it first. You're searching based on a condition that can't be indexed, like 'find the first student with a GPA above 3.7' — you genuinely have to check each one. You're writing a quick script or throwaway tool and simplicity beats optimisation.
Don't use linear search when: Your dataset is large (thousands of records or more) and you're searching repeatedly. In that case, binary search (for sorted data) gives you O(log n) — searching a million items in about 20 steps instead of a million. Or use a HashMap for O(1) lookup by key. The performance difference becomes dramatic at scale.
The honest real-world truth: most production code that 'searches a list' is actually using a database index, a HashMap, or a sorted structure. But every single one of those was built by someone who first understood linear search. It's the bedrock.
import java.util.ArrayList; import java.util.List; public class LinearSearchRealWorldUse { // Real-world use case: find all products under a given price threshold // This CAN'T use binary search because we want ALL matches, not just one, // and the condition is a range, not an exact value. // Linear search is genuinely the right tool here. static class Product { String name; double priceInDollars; boolean inStock; Product(String name, double priceInDollars, boolean inStock) { this.name = name; this.priceInDollars = priceInDollars; this.inStock = inStock; } } // Returns ALL in-stock products at or below the budget — not just the first one public static List<Product> findAffordableInStockProducts( Product[] catalogue, double budget) { List<Product> matches = new ArrayList<>(); for (int index = 0; index < catalogue.length; index++) { // Two conditions must BOTH be true to add this product to results boolean withinBudget = catalogue[index].priceInDollars <= budget; boolean available = catalogue[index].inStock; if (withinBudget && available) { matches.add(catalogue[index]); // Collect the match; keep going } // Notice: we do NOT return early — we need to check every product } return matches; // Return everything we found } public static void main(String[] args) { Product[] storeCatalogue = { new Product("Wireless Earbuds", 79.99, true), new Product("Laptop Stand", 45.00, true), new Product("Mechanical Keyboard", 129.99, false), // Out of stock new Product("USB Hub", 35.50, true), new Product("Webcam HD", 89.99, true), new Product("Monitor Light", 49.99, false) // Out of stock }; double userBudget = 80.00; List<Product> recommendations = findAffordableInStockProducts(storeCatalogue, userBudget); System.out.println("In-stock products under $" + userBudget + ":"); for (Product product : recommendations) { System.out.println(" - " + product.name + " ($" + product.priceInDollars + ")"); } } }
- Wireless Earbuds ($79.99)
- Laptop Stand ($45.0)
- USB Hub ($35.5)
| Feature / Aspect | Linear Search | Binary Search |
|---|---|---|
| Requires sorted data? | No — works on any array | Yes — data MUST be sorted first |
| Time complexity (worst) | O(n) — checks every element | O(log n) — halves the search space each step |
| Time complexity (best) | O(1) — target is first element | O(1) — target is middle element |
| Space complexity | O(1) — no extra memory needed | O(1) iterative / O(log n) recursive |
| Works on unsorted data? | Yes, always | No — gives wrong results on unsorted data |
| Works on linked lists? | Yes — just traverse forward | No — requires random index access |
| Implementation complexity | Very simple — a single loop | Moderate — tricky boundary conditions |
| Best used when | Small data, unsorted, complex conditions | Large sorted data, repeated exact lookups |
| Can find ALL matches? | Yes — just don't return early | Not easily — finds one match near the middle |
🎯 Key Takeaways
- Linear search checks every element one by one from start to finish — it needs no sorting, no preprocessing, and no special data structure. That simplicity is a feature, not just a limitation.
- Worst-case time complexity is O(n) — if the target is last or absent, you check every element. Best case is O(1). Space complexity is always O(1) because no extra memory is allocated regardless of input size.
- Always use .equals() to compare Strings and always return -1 (not 0) for 'not found' — these two conventions prevent the two most common linear search bugs beginners write in Java.
- Linear search is the right choice for small or unsorted data and for complex multi-condition searches. For large sorted datasets with repeated lookups, binary search (O(log n)) or a HashMap (O(1)) will dramatically outperform it.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Using == to compare Strings instead of .equals() — Symptom: your search returns -1 even when the target string is visually right there in the array. This happens because == compares memory addresses, not text content, and strings from user input or external sources live at different memory locations than your literal values. Fix: always use targetString.equals(arrayElement) for String comparisons, or equalsIgnoreCase() if casing might differ.
- ✕Mistake 2: Returning 0 instead of -1 for 'not found' — Symptom: calling code can't tell the difference between 'found at index 0' (the first element) and 'not found at all,' leading to the wrong element being returned to the user. Fix: use -1 as your sentinel value for 'not found' — it can never be a valid array index, so it's unambiguous. This is the universal convention across Java, Python, and JavaScript standard libraries.
- ✕Mistake 3: Forgetting to check the return value before using it — Symptom: a NullPointerException or ArrayIndexOutOfBoundsException crash at runtime when the search returns -1 and the calling code blindly uses it as an index (e.g., array[-1]). Fix: always check the result before acting on it — wrap your usage in an if (result != -1) block, or if searching objects, check if (foundObject != null) before accessing its fields.
Interview Questions on This Topic
- QWhat is the time complexity of linear search in the best, average, and worst case — and can you explain what causes each case to occur?
- QIf I have a sorted array of 10,000 integers and I need to search it thousands of times per second, would you use linear search? What would you use instead and why?
- QHow would you modify a linear search function to return ALL indices where a target value appears, rather than just the first one? What change does this force you to make to the function's return type and early-exit logic?
Frequently Asked Questions
What is linear search and when should I use it?
Linear search is an algorithm that finds a target value in a list by checking each element one at a time from the beginning until it finds a match or runs out of elements. Use it when your data is unsorted, your list is small, or your search condition is too complex for indexed lookups — like finding all records that satisfy multiple field conditions simultaneously.
What is the time complexity of linear search?
Linear search has O(1) best-case time complexity (when the target is the very first element), O(n) worst-case complexity (when the target is last or doesn't exist), and O(n) average-case complexity. Its space complexity is always O(1) because it uses only a loop counter and no additional data structures.
Does linear search require the array to be sorted?
No — and that's one of its biggest advantages over binary search. Linear search works correctly on completely unsorted data because it doesn't make any assumptions about the order of elements. It simply checks each one in sequence. Binary search, by contrast, will give wrong results on unsorted data because its halving logic depends on the sorted order being intact.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.