7 min read

Mastering Cyclic Sort: A Powerful Algorithm Technique

Cyclic Sort is an in-place algorithm particularly effective for sorting arrays containing numbers in a specific range. It's ideal when you need to sort integers ranging from 1 to n, where n is the length of the array. The core idea revolves around placing each element at its correct index. This technique boasts a time complexity of O(n), making it highly efficient.

How Cyclic Sort Works

The algorithm iterates through the array. For each element, it checks if it's already in its correct sorted position (value equals index + 1). If not, it swaps the element with the element at its correct position. This process continues until all elements are in their sorted positions.

Let's visualize this with an example:

Unsorted Array: [3, 1, 5, 4, 2]

Iteration 1:

  • The first element is 3. Its correct position is index 2 (value - 1 = 2). Since it's not at index 2, we swap 3 and 5. Array becomes: [5, 1, 3, 4, 2]
  • Now, the first element is 5. Its correct position is index 4. We swap 5 and 2. Array becomes: [2, 1, 3, 4, 5]

Iteration 2:

  • The first element is 2. Its correct position is index 1. We swap 2 and 1. Array becomes: [1, 2, 3, 4, 5]

Now, the array is sorted. Notice how we effectively "cycled" elements into their correct positions.


flowchart TD
    Start["Current Index i = 0"] --> CheckIndex{"i < nums.length ?"}
    CheckIndex -- No --> Done["Array Sorted: O(n) Time, O(1) Space"]
    CheckIndex -- Yes --> Calc["correctIndex = nums[i] - 1"]
    Calc --> CheckPos{"nums[i] != nums[correctIndex] ?"}
    CheckPos -- Yes --> Swap["Swap nums[i] <--> nums[correctIndex]
(Place number at its natural slot)"]
    Swap --> CheckPos
    CheckPos -- No --> Adv["Element is in place
Advance index: i++"]
    Adv --> CheckIndex

Code Examples

Java:

public static void cyclicSort(int[] nums) {
    int i = 0;
    while (i < nums.length) {
        int correctIndex = nums[i] - 1;
        if (nums[i] != nums[correctIndex]) {
            swap(nums, i, correctIndex);
        } else {
            i++;
        }
    }
}

private static void swap(int[] nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

Python:

def cyclic_sort(nums):
    i = 0
    while i < len(nums):
        correct_index = nums[i] - 1
        if nums[i] != nums[correct_index]:
            nums[i], nums[correct_index] = nums[correct_index], nums[i]
        else:
            i += 1

JavaScript:

function cyclicSort(nums) {
  let i = 0;
  while (i < nums.length) {
    let correctIndex = nums[i] - 1;
    if (nums[i] !== nums[correctIndex]) {
      [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]];
    } else {
      i++;
    }
  }
}

Identifying Cyclic Sort Patterns

You can identify problems suitable for Cyclic Sort by looking for these indicators:

  • The input is an array of integers.
  • The integers are within a specific range, typically from 1 to n, where n is the array's length.
  • The problem involves finding duplicates, missing numbers, or sorting the array.
  • In-place sorting is desired for efficiency.

Tips and Tricks for Identification

  • Examine the constraints: Pay close attention to the range of numbers in the input. A range from 1 to n is a strong indicator.
  • Look for keywords: Keywords like "find duplicates," "find missing numbers," or "sort the array" might suggest Cyclic Sort's applicability.
  • Consider the efficiency requirements: If the problem emphasizes in-place sorting and time efficiency, Cyclic Sort is a prime candidate.

Mastering Algorithms: A Deep Dive into Cyclic Sort

This blog post explores the Cyclic Sort algorithm, a powerful technique for efficiently sorting arrays with specific properties. We'll examine its mechanics, delve into example problems, and provide code implementations in Java, Python, and JavaScript.

Understanding Cyclic Sort

Cyclic Sort is an in-place sorting algorithm particularly effective when dealing with arrays containing numbers in a specific range, typically from 1 to n (where n is the array's length). The core idea is to place each number at its correct index. If a number is already at its correct index, we move on; otherwise, we swap it with the number at its correct index. This process continues until all numbers are in their sorted positions. Crucially, this algorithm only works correctly when numbers are within the 1 to n range, and no duplicates are present.

Step-by-Step Approach: Finding the Missing Number

Let's illustrate Cyclic Sort with a common problem: finding the missing number in an array of numbers from 1 to n.

Problem: Given an array of integers from 1 to n with one number missing, find the missing number.

Step 1: Pattern Identification

The missing number disrupts the correct placement of elements using the cyclic sort principles. By applying Cyclic Sort, elements are moved to their correct indices (i.e., arr[i] = i+1). Any index where the expected number is not present reveals the missing number.

Step 2: Algorithm Implementation (Java)

public class MissingNumber {
    public static int findMissingNumber(int[] nums) {
        int i = 0;
        while (i < nums.length) {
            int correctIndex = nums[i] - 1; // Adjust for 1-based indexing
            if (nums[i] != nums[correctIndex]) {
                swap(nums, i, correctIndex);
            } else {
                i++;
            }
        }
        for (int j = 0; j < nums.length; j++) {
            if (nums[j] != j + 1) {
                return j + 1;
            }
        }
        return nums.length + 1; //Missing number is at the end of the range
    }
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    public static void main(String[] args) {
        int[] nums = {4, 0, 3, 1};
        int missing = findMissingNumber(nums);
        System.out.println("The missing number is: " + missing); // Output: 2
    }
}

Step 3: Algorithm Implementation (Python)

def find_missing_number(nums):
    i = 0
    while i < len(nums):
        correct_index = nums[i] - 1
        if nums[i] != nums[correct_index]:
            nums[i], nums[correct_index] = nums[correct_index], nums[i]
        else:
            i += 1
    for j in range(len(nums)):
        if nums[j] != j + 1:
            return j + 1
    return len(nums) + 1

nums = [4, 0, 3, 1]
missing = find_missing_number(nums)
print(f"The missing number is: {missing}") # Output: 2

Step 4: Algorithm Implementation (JavaScript)

function findMissingNumber(nums) {
  let i = 0;
  while (i < nums.length) {
    let correctIndex = nums[i] - 1;
    if (nums[i] !== nums[correctIndex]) {
      [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]];
    } else {
      i++;
    }
  }
  for (let j = 0; j < nums.length; j++) {
    if (nums[j] !== j + 1) {
      return j + 1;
    }
  }
  return nums.length + 1;
}

let nums = [4, 0, 3, 1];
let missing = findMissingNumber(nums);
console.log("The missing number is: " + missing); // Output: 2

Example Problems

  1. Find all duplicates in an array: Identify numbers that appear more than once.
  2. Find the smallest missing positive number: Find the smallest positive integer that's not present in the array.
  3. Find all missing numbers in an array: Identify all numbers missing from the expected range.
  4. Set Mismatch: Find the number that appears twice and the number that is missing.
  5. Find the duplicate number in an array (with duplicates): Similar to finding missing numbers, but with duplicates allowed. Requires additional handling.
  6. First Missing Positive: Find the smallest positive integer that is missing from the input array. This can be solved by adapting the cyclic sort algorithm.
  7. Find the kth smallest element in an unsorted array. (Adapt Cyclic Sort for partial sorting).
  8. Find if array contains a cycle.
  9. Range Sum: Given a range of numbers and an array of numbers in that range, find the sum of the missing numbers.
  10. Array Partition I: Given an array of even length, partition the array such that the maximum sum of each element's pair is minimized.

Mastering Cyclic Sort: A Programmer's Guide

Cyclic sort is an elegant and efficient algorithm for sorting arrays with specific properties. It's particularly useful when dealing with arrays containing numbers within a known range, often from 1 to n, where n is the array's length. This technique shines in its in-place nature and linear time complexity (O(n)). Let's delve into its mechanics.

Understanding the Pattern

The core idea behind cyclic sort is to place each element at its correct index. If an element at index i is not equal to i+1 (assuming 1-based indexing), we swap it with the element at index i+1 - elementValue. We continue this process until every element is in its correct sorted position. This naturally forms a cycle; hence the name "cyclic sort".

Simple Approach

  1. Iteration: Iterate through the array.
  2. Correct Position Check: For each element, check if it's in the correct sorted position (its value equals its index + 1).
  3. Swap: If not, swap it with the element at the index that should contain the current element.
  4. Cycle Detection: The swapping creates cycles. Continue swapping until the element is in its correct position.
  5. Repeat: Repeat steps 2-4 for every element in the array.

Example: Find the Missing Number

Problem: Given an array of integers from 1 to n, where one number is missing, find the missing number.

Difficulty: Easy

Java:

public int findMissingNumber(int[] nums) {
    int i = 0;
    while (i < nums.length) {
        int correctIndex = nums[i] - 1;
        if (nums[i] != nums[correctIndex]) {
            swap(nums, i, correctIndex);
        } else {
            i++;
        }
    }
    for (i = 0; i < nums.length; i++) {
        if (nums[i] != i + 1) {
            return i + 1;
        }
    }
    return nums.length + 1; // Missing number is n+1
}

private void swap(int[] nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

Python:

def find_missing_number(nums):
    i = 0
    while i < len(nums):
        correct_index = nums[i] - 1
        if nums[i] != nums[correct_index]:
            nums[i], nums[correct_index] = nums[correct_index], nums[i]
        else:
            i += 1
    for i in range(len(nums)):
        if nums[i] != i + 1:
            return i + 1
    return len(nums) + 1

JavaScript:

function findMissingNumber(nums) {
    let i = 0;
    while (i < nums.length) {
        let correctIndex = nums[i] - 1;
        if (nums[i] !== nums[correctIndex]) {
            [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]];
        } else {
            i++;
        }
    }
    for (i = 0; i < nums.length; i++) {
        if (nums[i] !== i + 1) {
            return i + 1;
        }
    }
    return nums.length + 1;
}

Example Problems:

  1. Find the Missing Number (Easy): As shown above.
  2. Find all Duplicate Numbers (Medium): Given an array with duplicates, find all numbers that appear more than once.
  3. Find all Missing Numbers (Medium): Given an array with missing numbers, find all the missing numbers.
  4. Set Mismatch (Medium): Given an array of integers from 1 to n, find the two numbers that appear twice and once, respectively.
  5. First Missing Positive (Hard): Find the smallest positive integer that is missing from the array. (This problem can be solved efficiently with Cyclic Sort, but other approaches exist.)
  6. Find the Duplicate Number (Hard): Find a duplicate number in an array where numbers are in the range 1 to n, and there is only one duplicate. (This can also leverage Cyclic Sort principles).
  7. Array Nesting (Hard): A zero-indexed array A contains N integers. For each integer A[i], consider the sequence A[i], A[A[i]], A[A[A[i]]], ... This sequence is called the sequence starting at A[i]. Find the length of the longest such sequence.

Visualize the swapping process using array diagrams for each iteration in the findMissingNumber example. Show how the elements "cycle" into their correct positions.

Interview Questions Related to Cyclic Sort

  1. Explain the Cyclic Sort algorithm and its time and space complexity.
  2. When is Cyclic Sort an appropriate algorithm to use? Give examples.
  3. How would you handle negative numbers or numbers outside the 1 to n range using a modified Cyclic Sort approach?
  4. How does Cyclic Sort compare to other sorting algorithms like merge sort or quicksort in terms of efficiency and applicability?
  5. Design a test suite to thoroughly evaluate a Cyclic Sort implementation. Consider edge cases and boundary conditions.
  6. Describe a scenario where Cyclic Sort would be less efficient than other sorting algorithms.


Related Guides:
← PreviousModified Binary Search: Mental Models & Boundary PatternsNext →Fast and Slow Pointers: Cycle Detection & Invariants