Bitonic Sort (original) (raw)

Last Updated : 19 Dec, 2025

Bitonic Sort is a parallel sorting algorithm designed to take full advantage of hardware that can perform multiple operations simultaneously.

Unlike traditional sorting algorithms like Quick Sort or Merge Sort, Bitonic Sort is built to **exploit parallelism, making it highly effective on GPUs, multi-core processors, and hardware-based sorting networks.

It works only when the number of elements is a **power of 2, and it guarantees a fully sorted sequence using a predictable sequence of compare and swap operations.

Understanding Bitonic Sequences

A bitonic sequence is the core concept behind Bitonic Sort.

A sequence is **bitonic if it satisfies one of these:

  1. It first increases and then decreases,
  2. Or it can be rotated to form an increasing-then-decreasing sequence.

**Examples:

Why bitonic sequences matter:

Bitonic Sort works by recursively building bitonic sequences and then merging them into a fully sorted array. This structure allows the algorithm to perform many compare-and-swap operations simultaneously, which is why it’s ideal for parallel execution.

How Bitonic Sort Works

**Phase 1: Build a Bitonic Sequence

Example: [3, 7, 4, 8, 6, 2, 1, 5]

This bitonic sequence allows efficient merging using compare-and-swap operations.

**Phase 2: Bitonic Merge

Example:

The initial ascending/descending halves and fixed compare-swap pattern make this algorithm **highly parallelizable.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

// Compare and swap elements based on direction // direction = 1 → ascending, direction = 0 → descending void compAndSwap(vector& arr, int i, int j, int direction) { if ((direction == 1 && arr[i] > arr[j]) || (direction == 0 && arr[i] < arr[j])) { swap(arr[i], arr[j]); } }

// Recursively merge a bitonic sequence into sorted order void bitonicMerge(vector& arr, int low, int cnt, int direction) { if (cnt > 1) { int k = cnt / 2; for (int i = low; i < low + k; i++) { compAndSwap(arr, i, i + k, direction); } bitonicMerge(arr, low, k, direction); bitonicMerge(arr, low + k, k, direction); } }

// Recursively build bitonic sequences and sort them void bitonicSort(vector& arr, int low, int cnt, int direction) { if (cnt > 1) { int k = cnt / 2;

    // Sort first half ascending
    bitonicSort(arr, low, k, 1);

    // Sort second half descending
    bitonicSort(arr, low + k, k, 0);

    // Merge entire sequence in given direction
    bitonicMerge(arr, low, cnt, direction);
}

}

// function to sort the entire array void sortArray(vector& arr) {

// up = 1 → ascending, up = 0 → descending
int up = 1; 
bitonicSort(arr, 0, arr.size(), up);

}

//Driver Code Starts int main() { vector arr = {7, 3, 4, 8, 6, 2, 1, 5};

sortArray(arr);

for (int x : arr) cout << x << " ";
cout << endl;

return 0;

}

//Driver Code Ends

Java

//Driver Code Starts class GFG { //Driver Code Ends

// Compare and swap elements based on direction
// direction = 1 → ascending, direction = 0 → descending
static void compAndSwap(int[] arr, int i, int j, int direction) {
    if ((direction == 1 && arr[i] > arr[j])
        || (direction == 0 && arr[i] < arr[j])) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

// Recursively merge a bitonic sequence into sorted order
static void bitonicMerge(int[] arr, int low, int cnt, int direction) {
    if (cnt > 1) {
        int k = cnt / 2;
        for (int i = low; i < low + k; i++) {
            compAndSwap(arr, i, i + k, direction);
        }
        bitonicMerge(arr, low, k, direction);
        bitonicMerge(arr, low + k, k, direction);
    }
}

// Recursively build bitonic sequences and sort them
static void bitonicSort(int[] arr, int low, int cnt, int direction) {
    if (cnt > 1) {
        int k = cnt / 2;

        // Sort first half ascending
        bitonicSort(arr, low, k, 1);

        // Sort second half descending
        bitonicSort(arr, low + k, k, 0);

        // Merge entire sequence in given direction
        bitonicMerge(arr, low, cnt, direction);
    }
}

// function to sort the entire array
static void sortArray(int[] arr) {

    // up = 1 → ascending, up = 0 → descending
    int up = 1;
    bitonicSort(arr, 0, arr.length, up);
}

//Driver Code Starts public static void main(String[] args) { int[] arr = {7, 3, 4, 8, 6, 2, 1, 5};

    sortArray(arr);

    for (int x : arr)
        System.out.print(x + " ");
    System.out.println();
}

}

//Driver Code Ends

Python

Compare and swap elements based on direction

direction = 1 → ascending, direction = 0 → descending

def compAndSwap(arr, i, j, direction): if (direction == 1 and arr[i] > arr[j])
or (direction == 0 and arr[i] < arr[j]): arr[i], arr[j] = arr[j], arr[i]

Recursively merge a bitonic sequence into sorted order

def bitonicMerge(arr, low, cnt, direction): if cnt > 1: k = cnt // 2 for i in range(low, low + k): compAndSwap(arr, i, i + k, direction) bitonicMerge(arr, low, k, direction) bitonicMerge(arr, low + k, k, direction)

Recursively build bitonic sequences and sort them

def bitonicSort(arr, low, cnt, direction): if cnt > 1: k = cnt // 2

    # Sort first half ascending
    bitonicSort(arr, low, k, 1)

    # Sort second half descending
    bitonicSort(arr, low + k, k, 0)

    # Merge entire sequence in given direction
    bitonicMerge(arr, low, cnt, direction)

function to sort the entire array

def sortArray(arr):

# up = 1 → ascending, up = 0 → descending
up = 1

bitonicSort(arr, 0, len(arr), up)

#Driver Code Starts

if name == 'main': arr = [7, 3, 4, 8, 6, 2, 1, 5] sortArray(arr) print(*arr)

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

// Compare and swap elements based on direction
// direction = 1 → ascending, direction = 0 → descending
static void CompAndSwap(int[] arr, int i, int j, int direction) {
    if ((direction == 1 && arr[i] > arr[j]) 
        || (direction == 0 && arr[i] < arr[j])) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

// Recursively merge a bitonic sequence into sorted order
static void BitonicMerge(int[] arr, int low, int cnt, int direction) {
    if (cnt > 1) {
        int k = cnt / 2;
        for (int i = low; i < low + k; i++) {
            CompAndSwap(arr, i, i + k, direction);
        }
        BitonicMerge(arr, low, k, direction);
        BitonicMerge(arr, low + k, k, direction);
    }
}

// Recursively build bitonic sequences and sort them
static void BitonicSort(int[] arr, int low, int cnt, int direction) {
    if (cnt > 1) {
        int k = cnt / 2;

        // Sort first half ascending
        BitonicSort(arr, low, k, 1);

        // Sort second half descending
        BitonicSort(arr, low + k, k, 0);

        // Merge entire sequence in given direction
        BitonicMerge(arr, low, cnt, direction);
    }
}

// function to sort the entire array
static void SortArray(int[] arr) {
    
    // up = 1 → ascending, up = 0 → descending
    int up = 1;
    BitonicSort(arr, 0, arr.Length, up);
}

//Driver Code Starts static void Main() { int[] arr = {7, 3, 4, 8, 6, 2, 1, 5}; SortArray(arr); Console.WriteLine(string.Join(" ", arr)); } }

//Driver Code Ends

JavaScript

// Compare and swap elements based on direction // direction = 1 → ascending, direction = 0 → descending function compAndSwap(arr, i, j, direction) { if ((direction === 1 && arr[i] > arr[j]) || (direction === 0 && arr[i] < arr[j])) { [arr[i], arr[j]] = [arr[j], arr[i]]; } }

// Recursively merge a bitonic sequence into sorted order function bitonicMerge(arr, low, cnt, direction) { if (cnt > 1) { let k = Math.floor(cnt / 2); for (let i = low; i < low + k; i++) { compAndSwap(arr, i, i + k, direction); } bitonicMerge(arr, low, k, direction); bitonicMerge(arr, low + k, k, direction); } }

// Recursively build bitonic sequences and sort them function bitonicSort(arr, low, cnt, direction) { if (cnt > 1) { let k = Math.floor(cnt / 2);

    // Sort first half ascending
    bitonicSort(arr, low, k, 1);

    // Sort second half descending
    bitonicSort(arr, low + k, k, 0);

    // Merge entire sequence in given direction
    bitonicMerge(arr, low, cnt, direction);
}

}

// function to sort the entire array function sortArray(arr) {

// up = 1 → ascending, up = 0 → descending
let up = 1;
bitonicSort(arr, 0, arr.length, up);

}

// Driver Code //Driver Code Starts let arr = [7, 3, 4, 8, 6, 2, 1, 5]; sortArray(arr); console.log(arr.join(" "));

//Driver Code Ends

`

**Time Complexity:

**Auxiliary Space: O(log n), due to recursion stack space

**Stability: No, Bitonic Sort is not stable, since elements may be swapped across sequences during merging.

Understanding Time Complexity for Bitonic Sort

Bitonic Sort first builds bitonic sequences (half ascending, half descending) and then merges them into sorted order.

Each of these two phases has log n levels, and every level performs O(n) comparisons.
Thus, total time = O(n × log n × log n) = O(n log² n).

Although it’s slower than Merge Sort on a single processor, Bitonic Sort is highly effective on parallel hardware, where many compare-swap operations can be executed simultaneously, reducing actual runtime significantly.

Applications of Bitonic Sort

applications_

Advantages and Disadvantages of Bitonic Sort