AP CSA: Sorts, Searches, Abstract, Interfaces
Searches
Linear Search
The Linear Search searches through a list, one element at a time to look for a match.
The index position of a match is returned if found
Otherwise, -1 is returned
Traits:
Works on unsorted data (the data doesn’t have to be sorted)
Simple to implement
No extra memory needed
In the worst case, it may need to check every element
In the best case (the value is in the first position), it finds it immediately
// Primitives
int linearSearch(int[] stuff, int target) //sends in a array, and the target
{
for (int i = 0; i< stuff.length; i++)
{
if (stuff [i] == target) // if test to see if any of the values equal the target in the array
{
return i; // if so, returns their index
}
}
return -1; //otherwise, returns -1 if not found
}// Objects
int linearSearch(Comparable[] stuff, Comparable item) // takes an array of Comparable objects and a target item
{
for (int i = 0; i < stuff.length; i++)
{
if (stuff[i].compareTo(item) == 0) // compare current object with target using compareTo instead just ==
{
return i; // if they are equal, return the index
}
}
return -1; //otherwise, return -1 if not found
}Examples
Integer[] numbers = {5, 12, 8, 20, 3};
int result = linearSearch(numbers, 20);Your target amount is 20, and your array is {5, 12, 8, 20, 3};
The Linear Search is going to run like this:
numbers[0] (5) = 20 ❌
numbers[1] (12) = 20 ❌
numbers[2] (8) = 20 ❌
numbers [3] (20) = 20 ✅
The number returned would be 3, since 20 was found at index 3.
Integer[] numbers = {5, 12, 8, 20, 3};
int result = linearSearch(numbers, 7);The Linear Search is going to run like this:
numbers[0] (5) = 7 ❌
numbers[1] (12) = 7 ❌
numbers[2] (8) = 7 ❌
numbers [3] (20) = 7 ❌
numbers [4] (3) = 7 ❌
Since none of the values were 7, the compiler returns a -1.
Binary Search
Binary Search finds a value by repeatedly diving a sorted list in half and checking the middle element
The list must be sorted for Binary Search to work
The index position of a match is returned if found
Otherwise, -1 is returned
// Primitives
int binarySearch(int[] stuff, int target)
{
int low = 0;
int high = stuff.length - 1;
while (low <= high)
{
int mid = (low + high) / 2; // mid divides the whole array in half and saves it
if (stuff[mid] == target)
{
return mid; // found target
}
else if (stuff[mid] < target) // the < would be > if the thing passed was in DESCENDING order (e.g., {20, 18, 16, 14, 12....})
{
low = mid + 1; // search right half
}
else
{
high = mid - 1; // search left half
}
}
return -1; // not found
}int binarySearch(Comparable[] stuff, Comparable item)
{
int low = 0;
int high = stuff.length - 1;
while (low <= high)
{
int mid = (low + high) / 2;
if (stuff[mid].compareTo(item) == 0)
{
return mid; // found target
}
else if (stuff[mid].compareTo(item) < 0)
{
low = mid + 1; // search right half
}
else
{
high = mid - 1; // search left half
}
}
return -1; // not found
}Examples
Integer[] numbers = {3, 5, 8, 12, 20};
int result = binarySearch(numbers, 20);The Binary Search is going to run like this:
Start with the entire array: {3, 5, 8, 12, 20}.
Calculate the middle index: mid = (0 + 4) / 2 = 2, looking at numbers[2] = 8.
Since 20 > 8, discard the left half and focus on the right half: {12, 20}.
Recalculate middle index for the new subarray: mid = (3 + 4) / 2 = 3, checking numbers[3] = 12.
Since 20 > 12, discard the 12 and focus only on the last element: {20}.
Again calculate the middle index: mid = (4 + 4) / 2 = 4, checking numbers[4] = 20.
Since we found the target, return the index 4.
Sorts
Selection Search
Selection Sort is a sorting algorithm that repeatedly finds the smallest (or largest) element in the unsorted part of the array and moves it to the correct position.
The list becomes sorted by building it from the left to the right
Traits:
Works on unsorted data
Repeatedly selects minimum value (or maximum if sorting descending)
Simple but takes very long for large datasets
# of swaps is typically smaller compared to the # of comparisons
//Primitives - Ascending
void selectionSort(int[] arr)
{
for (int i = 0; i < arr.length - 1; i++)
{
int minIndex = i;
// IMPORTANT: assumes first unsorted element is smallest
for (int j = i + 1; j < arr.length; j++)
{
if (arr[j] < arr[minIndex]) // would be > if descending
// IMPORTANT: finds smaller value in unsorted section
{
minIndex = j;
}
}
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
// IMPORTANT: swap puts smallest value in correct position
}
}Insertion Search
Insertion Sort builds a sorted list by taking each element and inserting it into its correct position in the already sorted part of the array.
Traits:
Works on unsorted data
Builds the sorted section from left to right
Efficient for small or nearly sorted arrays
In-place sorting (no extra memory needed)
Stable sorting algorithm (keeps equal items in order)
//Primitives
void insertionSort(int[] arr)
{
for (int i = 1; i < arr.length; i++)
{
int key = arr[i];
// IMPORTANT: value to be inserted into sorted section
int j = i - 1;
while (j >= 0 && arr[j] > key) // < would make it descending
// IMPORTANT: shifts larger values to the right
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
// IMPORTANT: inserts key into correct position
}
}Bubble Sort
Bubble Sort repeatedly compares adjacent elements and swaps them if they are in the wrong order.
Larger values “bubble” to the end of the array each pass.
Traits:
Works on unsorted data
Repeatedly compares adjacent elements
Simple but very inefficient for large datasets
In-place sorting (no extra memory needed)
Stable sorting algorithm (keeps equal elements in order)
void bubbleSort(int[] arr)
{
for (int i = 0; i < arr.length - 1; i++)
// IMPORTANT: controls number of passes (n - 1 passes)
{
for (int j = 0; j < arr.length - 1 - i; j++)
// IMPORTANT: each pass ignores last sorted elements
{
if (arr[j] > arr[j + 1]) // < descending
// IMPORTANT: swap if left is greater (ascending)
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
// IMPORTANT: swaps adjacent elements
}
}
}
}Quick Sort
Quick Sort is a divide-and-conquer sorting algorithm that works by selecting a pivot and partitioning the array into two halves:
Values less than the pivot
Values greater than the pivot
It then recursively sorts the two halves.
Traits:
Picks a pivot element
Partitions array into left (smaller) and right (larger)
Very fast for large datasets
Not stable (order of equal elements may change
int partition(int[] arr, int low, int high)
{
int pivot = arr[high];
// IMPORTANT: choosing last element as pivot (common choice)
int i = low - 1;
// IMPORTANT: tracks position for smaller elements
for (int j = low; j < high; j++)
{
if (arr[j] < pivot) // > : descending
// IMPORTANT: elements smaller than pivot go left
{
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
// swap
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
// IMPORTANT: place pivot in correct position
return i + 1;
}Merge Sort
Merge Sort is a divide-and-conquer algorithm that repeatedly splits the array into smaller halves until each part has only one element.
The left side is created by taking the first half of the array.
Key Idea:
You split the array using the middle index:
int mid = (low + high) / 2;Left side → from
lowtomidRight side → from
mid + 1tohigh
void mergeSort(int[] arr, int low, int high)
{
if (low < high)
// IMPORTANT: base case (stop when 1 element)
{
int mid = (low + high) / 2;
mergeSort(arr, low, mid);
// IMPORTANT: LEFT HALF
mergeSort(arr, mid + 1, high);
// RIGHT HALF
merge(arr, low, mid, high);
// combines both halves
}
}Abstract/Interfaces
Abstract Classes
An abstract class in Java is a class that cannot be instantiated and is meant to be inherited.
It can contain:
Abstract methods (no body, must be implemented in subclasses)
Concrete methods (with implementation)
Variables and constructors
Key Points
Declared using the
abstractkeyword.You cannot create objects of an abstract class.
Subclasses must implement all abstract methods or also be declared abstract.
Supports code reuse and provides a common structure for related classes.
Purpose
Used to define a common template for related classes while allowing specific behavior to be implemented by subclasses.
Simple Idea
An abstract class is like a partially defined blueprint, it sets rules and provides some implementation, but leaves details to child classes.
// Abstract class: cannot be instantiated directly
abstract class Animal {
// Abstract method: no body, must be implemented by subclasses
abstract void makeSound();
// Concrete method: already implemented, shared by all subclasses
void sleep() {
System.out.println("Animal is sleeping...");
}
}
// Dog is a subclass of Animal
class Dog extends Animal {
// Providing implementation for abstract method
@Override
void makeSound() {
System.out.println("Dog barks");
}
}
// Cat is another subclass of Animal
class Cat extends Animal {
// Each subclass defines its own version of makeSound()
@Override
void makeSound() {
System.out.println("Cat meows");
}
}
// Main class to run the program
public class Main {
public static void main(String[] args) {
// Cannot do: Animal a = new Animal(); ❌ (abstract class)
// Using polymorphism: parent reference, child object
Animal a1 = new Dog();
Animal a2 = new Cat();
// Calls Dog's version of makeSound()
a1.makeSound();
a1.sleep(); // inherited concrete method
// Calls Cat's version of makeSound()
a2.makeSound();
a2.sleep(); // same shared method
}
}
An interface in Java is a blueprint/contract that defines what a class should do, but not how it does it.
Interfaces
Key Features
Declared using the
interfacekeyword.Contains abstract methods by default (no method body).
Variables are public, static, and final (constants).
Cannot be instantiated (no objects can be created).
Implemented using the
implementskeyword.
Syntax Idea
interface Animal {
void makeSound(); // abstract method
}Implementation
A class must implement all methods of the interface.
Otherwise, the class must be declared abstract.
class Dog implements Animal {
public void makeSound() {
System.out.println("Bark");
}
}Important Rules
All methods are public by default.
No constructors allowed.
No instance variables (only constants).
A class can implement multiple interfaces → supports multiple inheritance.
Advantages
Achieves abstraction
Supports multiple inheritance
Provides loose coupling
Improves code flexibility and maintainability