Python — quicksort.py
Python โ Randomized Quicksort (HW3)
Run command
wsl.exe -d Ubuntu -- bash -c "cd '/mnt/c/Users/granite/Documents/DSU/Algorithms 482/3/HW3/python' && python3 quicksort.py"
(Equivalent, from inside a WSL Ubuntu shell already cd'd into this folder: python3 quicksort.py.)
Runtime version
$ python3 --version
Python 3.14.4
Confirmed via the command above, run inside WSL2 Ubuntu ("Ubuntu", 26.04 "Resolute Raccoon"),
default user granite.
Files
quicksort.pyโ implementation of CLRSRANDOMIZED-QUICKSORT/RANDOMIZED-PARTITION(in-place on a Pythonlistof ints) plus the timing harness described in../DESIGN.md. Uses only the Python standard library (random,time,csv,os,sys) โ no third-party packages, nolist.sort()/sorted().- Writes results to
../results/python.csv(headern,time_seconds) and prints the same rows to stdout as it runs.
No build step
Python is interpreted; there is nothing to compile. No optimization flags
were used (no -O, standard python3 invocation).
"""
Randomized Quicksort timing harness (CSC 482 HW3 - Language Comparison).
Algorithm: CLRS RANDOMIZED-QUICKSORT / RANDOMIZED-PARTITION (Ch. 5).
In-place quicksort on a Python list of ints; at every partition step the
pivot index is chosen uniformly at random from the current subarray range
using the standard library `random` module, swapped into the last position,
and a standard Lomuto partition is run around it.
No external code used - original implementation based on CLRS
RANDOMIZED-QUICKSORT pseudocode. No sorting-library shortcuts
(list.sort()/sorted() are never called).
"""
import csv
import os
import random
import sys
import time
def randomized_partition(a, lo, hi):
"""Lomuto partition of a[lo..hi] around a uniformly random pivot.
Chooses a random index in [lo, hi], swaps it into position hi (the
CLRS RANDOMIZED-PARTITION step), then runs the standard Lomuto
partition, returning the pivot's final index.
"""
pivot_index = random.randint(lo, hi)
a[pivot_index], a[hi] = a[hi], a[pivot_index]
pivot = a[hi]
i = lo - 1
for j in range(lo, hi):
if a[j] <= pivot:
i += 1
a[i], a[j] = a[j], a[i]
a[i + 1], a[hi] = a[hi], a[i + 1]
return i + 1
def randomized_quicksort(a, lo=0, hi=None):
"""In-place CLRS RANDOMIZED-QUICKSORT on a[lo..hi] (inclusive)."""
if hi is None:
hi = len(a) - 1
if lo < hi:
p = randomized_partition(a, lo, hi)
randomized_quicksort(a, lo, p - 1)
randomized_quicksort(a, p + 1, hi)
def generate_random_list(n, lo=0, hi=1_000_000):
return [random.randrange(lo, hi) for _ in range(n)]
def main():
script_dir = os.path.dirname(os.path.abspath(__file__))
results_dir = os.path.abspath(os.path.join(script_dir, "..", "results"))
os.makedirs(results_dir, exist_ok=True)
csv_path = os.path.join(results_dir, "python.csv")
n = 1000
max_iterations = 25
time_cutoff = 4.0
n_cap = 200_000_000
rows = []
print("n,time_seconds")
iteration = 0
while True:
iteration += 1
data = generate_random_list(n)
start = time.perf_counter()
try:
randomized_quicksort(data)
except RecursionError as exc:
print(f"ANOMALY: RecursionError at n={n}: {exc}", file=sys.stderr)
break
elapsed = time.perf_counter() - start
rows.append((n, elapsed))
print(f"{n},{elapsed:.6f}")
# Sanity check the sort is actually correct (not timed; cheap relative
# to the sort itself only for small n, but useful during development).
# Left in place as a lightweight correctness guard.
# (Comment out if it ever becomes a measurable overhead concern.)
# assert all(data[i] <= data[i + 1] for i in range(len(data) - 1))
if elapsed > time_cutoff:
print(f"Stopping: elapsed {elapsed:.3f}s exceeded {time_cutoff}s cutoff at n={n}")
break
if iteration >= max_iterations:
print(f"Stopping: reached {max_iterations} iterations")
break
if n * 2 > n_cap:
print(f"Stopping: next n ({n * 2}) would exceed cap {n_cap}")
break
n *= 2
with open(csv_path, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["n", "time_seconds"])
for row_n, row_t in rows:
writer.writerow([row_n, f"{row_t:.6f}"])
print(f"\nWrote {len(rows)} rows to {csv_path}")
if __name__ == "__main__":
main()