{% extends "base.html" %} {% block title %}Compare All | USSU Algorithm Analyzer v4.0{% endblock %} {% block content %}

Battle Setup

Battle Rules

Sorting Battle

13 Algorithms Time + Space + Stability

All sorting algorithms race on the same input. Slow algorithms (O(n²)) skipped for inputs > 2000 elements. Winner is determined by execution time.

Search Battle

8 Algorithms Comparisons + Accesses

All search algorithms compete on the same array and target. Measures time, comparisons, and success rate. Binary search family expected to dominate.

{% if chart_img %}

Performance Chart

{% endif %} {% if result %}

Battle Results

{% if result[0].stable is defined %}{% endif %} {% if result[0].found is defined %}{% endif %} {% if result[0].comparisons is defined %}{% endif %} {% for r in result %} {% if r.stable is defined %}{% endif %} {% if r.found is defined %}{% endif %} {% if r.comparisons is defined %}{% endif %} {% endfor %}
Algorithm Time (ms) ComplexityStableFoundComparisons
{{ r.name }} {% if r.time_ms is number and r.time_ms < 999999 %} {{ "%.4f"|format(r.time_ms) }} {% else %} Skipped {% endif %} {{ r.complexity }}{{ r.stable }}{{ "Yes" if r.found else "No" }}{{ r.comparisons }}

▸ DETAILED PROCESS ANALYSIS

{% if request.form.get('category') == 'sort' or not request.form.get('category') %}

📊 How Sorting Works

1. Bubble Sort

O(n²) Stable

Repeatedly steps through the list, compares adjacent elements and swaps them if they are in the wrong order. The pass through the list is repeated until the list is sorted. Like bubbles rising to the surface — largest elements "bubble up" to their correct position.

for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
swap(arr[j], arr[j+1])

2. Merge Sort

O(n log n) Stable

Divide-and-conquer: splits array in half recursively until single elements, then merges sorted halves. Guaranteed n log n performance. The merge step compares elements from two sorted subarrays and builds a larger sorted array.

def merge_sort(arr):
if len(arr) <= 1: return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)

3. Quick Sort

O(n log n) avg Unstable

Pick a pivot, partition array into elements less than and greater than pivot, recursively sort partitions. In-place with O(log n) stack space. Fastest in practice for large random datasets. Worst case O(n²) when pivot selection is poor.

def quick_sort(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quick_sort(arr, low, pi-1)
quick_sort(arr, pi+1, high)

4. Heap Sort

O(n log n) Unstable

Build a max-heap from the array, then repeatedly extract the maximum element and place it at the end. In-place sorting with guaranteed O(n log n) performance. Uses heapify to maintain heap property after each extraction.

build_max_heap(arr)
for i from n-1 down to 1:
swap(arr[0], arr[i])
heapify(arr, 0, i)

🔬 Sorting Deep Dive

5. Counting Sort

O(n + k) Stable

Non-comparison based. Count occurrences of each value, compute cumulative counts, then place elements in output array in stable order. Only works for integer ranges. Extremely fast when k (range) is small.

6. Radix Sort

O(d(n+k)) Stable

Sorts by processing individual digits from least significant to most significant. Uses counting sort as a subroutine for each digit. Handles large integers efficiently when digit count d is small.

7. Shell Sort

O(n log² n) Unstable

Generalization of insertion sort. Sorts elements that are gap apart, then reduces gap. Final gap of 1 is regular insertion sort. Performance depends on gap sequence (Shell, Knuth, Ciura).

8. Timsort

O(n log n) Stable

Python's built-in sort. Hybrid of merge sort and insertion sort. Identifies "runs" (already sorted sequences) and merges them. Highly optimized for real-world data with existing order. Best practical performance.

💡 Sorting Strategy Guide

Small arrays (n < 50): Insertion Sort
General purpose: Timsort / Merge Sort
In-place needed: Quick Sort / Heap Sort
Integer range small: Counting / Radix Sort
Stability required: Merge Sort / Timsort

{% endif %} {% if request.form.get('category') == 'search' %}

🔍 How Searching Works

1. Linear Search

O(n) O(1) Space

Sequentially checks each element until the target is found or the end is reached. No preprocessing required. Works on unsorted data. Simple but slow for large datasets. Best when data is small or unsorted.

for i in range(len(arr)):
if arr[i] == target:
return i
return -1

2. Binary Search

O(log n) O(1) Space Requires Sorted

Compare target with middle element. If equal, return. If target is smaller, search left half. Otherwise search right half. Repeat until found or bounds cross. Requires sorted array. The gold standard for sorted data.

while left <= right:
mid = (left + right) // 2
if arr[mid] == target: return mid
elif arr[mid] < target: left = mid + 1
else: right = mid - 1

3. Jump Search

O(√n) O(1) Space

Jump ahead by √n steps until finding a block where target could be, then linear search backward. Balance between linear and binary search. Optimal jump size is √n for minimizing comparisons.

step = int(sqrt(n))
prev = 0
while arr[min(step,n)-1] < target:
prev = step; step += sqrt(n)
if prev >= n: return -1
while arr[prev] < target: prev += 1
if arr[prev] == target: return prev

4. Interpolation Search

O(log log n) avg O(1) Space

Estimates position using linear interpolation: pos = low + ((target - arr[low]) / (arr[high] - arr[low])) * (high - low). Best for uniformly distributed sorted data. Can degrade to O(n) for non-uniform distributions.

pos = low + int((target - arr[low]) /
(arr[high] - arr[low]) * (high - low))
if arr[pos] == target: return pos
elif arr[pos] < target: low = pos + 1
else: high = pos - 1

🔬 Search Deep Dive

5. Exponential Search

O(log n) O(1) Space

Find range where element exists by checking indices 1, 2, 4, 8... (exponential jumps). Then binary search within that range. Useful for unbounded/infinite arrays. First element checked is at index 0.

6. Ternary Search

O(log₃ n) O(1) Space

Divide array into three parts using two midpoints. Eliminate one-third of the search space each iteration. Slightly slower than binary search in practice due to more comparisons, but useful for unimodal function optimization.

7. Fibonacci Search

O(log n) O(1) Space

Uses Fibonacci numbers to divide array. Find smallest Fibonacci number ≥ n, then compare element at Fibonacci offset. Eliminates ~1/φ (61.8%) of remaining elements. Interesting mathematical property but rarely used in practice.

💡 Search Strategy Guide

Unsorted data: Linear Search
Sorted array: Binary Search
Uniform distribution: Interpolation Search
Unknown/infinite size: Exponential Search
Function optimization: Ternary Search
Small array: Linear or Jump Search

{% endif %} {% endif %} {% endblock %} {% block extra_scripts %} {% endblock %}