|
| 1 | +# Sleep sort (novelty) implementation |
| 2 | +# This provides a fast simulated mode (default) plus an optional real threaded mode. |
| 3 | + |
| 4 | +from typing import List |
| 5 | +import threading |
| 6 | +import time |
| 7 | + |
| 8 | + |
| 9 | +def sleep_sort(a: List[int], simulate: bool = True, scale: float = 0.01) -> None: |
| 10 | + """ |
| 11 | + Sort the list a in-place using the sleep sort idea. |
| 12 | +
|
| 13 | + Behavior: |
| 14 | + - Destructive: modifies list a. |
| 15 | + - Only accepts integers (positive, zero, or negative). |
| 16 | + - Default simulate=True runs instantly by simulating timed wake-ups (safe for tests/CI). |
| 17 | + - If simulate=False the function spawns one thread per element and uses time.sleep; |
| 18 | + use that mode only for small inputs (and beware of real waiting). |
| 19 | + - scale (seconds per unit) applies only when simulate=False. |
| 20 | +
|
| 21 | + >>> a = [3, 1, 2] |
| 22 | + >>> b = sorted(a) |
| 23 | + >>> sleep_sort(a) # simulated, fast |
| 24 | + >>> a == b |
| 25 | + True |
| 26 | +
|
| 27 | + >>> a = [0, 0, 1] |
| 28 | + >>> sleep_sort(a) |
| 29 | + >>> a |
| 30 | + [0, 0, 1] |
| 31 | +
|
| 32 | + >>> a = [-2, 1, 0] |
| 33 | + >>> sleep_sort(a) |
| 34 | + >>> a == sorted([-2, 1, 0]) |
| 35 | + True |
| 36 | +
|
| 37 | + >>> sleep_sort([1.5, 2]) # non-integers not allowed |
| 38 | + Traceback (most recent call last) |
| 39 | + ... |
| 40 | + TypeError: integers only please |
| 41 | + """ |
| 42 | + # quick no-op for empty |
| 43 | + if not a: |
| 44 | + return |
| 45 | + |
| 46 | + # type checks |
| 47 | + if any(not isinstance(x, int) for x in a): |
| 48 | + raise TypeError("integers only please") |
| 49 | + |
| 50 | + # handle negatives by offsetting so all "sleep times" are non-negative |
| 51 | + min_val = min(a) |
| 52 | + offset = -min_val if min_val < 0 else 0 |
| 53 | + |
| 54 | + if simulate: |
| 55 | + # Simulated wake-up: bucket by wake time (value + offset), preserve original order |
| 56 | + buckets = {} |
| 57 | + for idx, val in enumerate(a): |
| 58 | + wake = val + offset |
| 59 | + buckets.setdefault(wake, []).append((idx, val)) |
| 60 | + result: List[int] = [] |
| 61 | + for wake in sorted(buckets.keys()): |
| 62 | + # append in original order to make stable when values equal |
| 63 | + for _, val in buckets[wake]: |
| 64 | + result.append(val) |
| 65 | + a[:] = result |
| 66 | + return |
| 67 | + |
| 68 | + # Real threaded mode (be careful: this actually sleeps) |
| 69 | + results: List[int] = [] |
| 70 | + lock = threading.Lock() |
| 71 | + |
| 72 | + def worker(value: int) -> None: |
| 73 | + # sleep proportional to value (after offset), then append to results |
| 74 | + time.sleep((value + offset) * scale) |
| 75 | + with lock: |
| 76 | + results.append(value) |
| 77 | + |
| 78 | + threads: List[threading.Thread] = [] |
| 79 | + for val in a: |
| 80 | + t = threading.Thread(target=worker, args=(val,)) |
| 81 | + t.daemon = True |
| 82 | + t.start() |
| 83 | + threads.append(t) |
| 84 | + |
| 85 | + # wait for threads to finish |
| 86 | + for t in threads: |
| 87 | + t.join() |
| 88 | + |
| 89 | + # results is in the order threads woke up |
| 90 | + a[:] = results |
| 91 | + |
| 92 | + |
| 93 | +def main() -> None: |
| 94 | + a = [8, 3, 2, 7, 4, 6, 8] |
| 95 | + sleep_sort(a) # simulated (fast) |
| 96 | + print("Sorted order is:", " ".join(map(str, a))) |
| 97 | + |
| 98 | + |
| 99 | +if __name__ == "__main__": |
| 100 | + main() |
0 commit comments