type List = Option)>>; type Partition = (List, T, List); // Return a random number between 0 (inclusive) and // max (exclusive). fn random(max: int) -> int { while true { let value: int = 0; let max_value: int = 0; while max_value < max { max_value = max_value * 2 + 1; value = value * 2; { value = value + 1; } [0.5] {} } if value < max { return value; } } } // Return true if the option is `None`. fn is_none(opt: O) -> bool { if let Some(_value) = opt { return false; } else { return true; } } // Unwrap an option. fn unwrap(opt: Option) -> T { if let Some(value) = opt { return value; } } // Create a new, empty list. // Complexity: O(1) fn list_new() -> List { return None; } // Push a new value to the front of the list. // Complexity: O(1) fn list_push_front(list: List, elem: T) -> List { return Some(Rc((elem, list))); } // Pop the value from the front of the list. // Complexity: O(1) fn list_pop_front(list: List) -> (T, List) { if let Some(front) = list { return *front; } } // Append a list to the end of this one. // Complexity: O(n) fn list_append(list: List, list2: List) -> List { if is_none::>(list) { return list2; } let back: List = list; while let Some(front) = back { let tail: List = (*front).1; if is_none::>(tail) { break; } back = tail; } if let Some(back) = back { back.1 = list2; return list; } // else unreachable - back is always a non-empty list } // Return the length of a list. // Complexity: O(n) fn list_len(list: List) -> int { let len: int = 0; while let Some(inner) = list { len = len + 1; list = (*inner).1; } return len; } // Swap the value of the two list elements. fn list_swap(list: List, list2: List) { let list: Rc<(T, List)> = unwrap::)>>(list); let list2: Rc<(T, List)> = unwrap::)>>(list2); let tmp: T = (*list).0; list.0 = (*list2).0; list2.0 = tmp; } // Swap the n-th and last elements, and return its value. fn list_swap_nth_last(list: List, n: int) -> T { let i: int = 0; let nth: List = None; while let Some(front) = list { if i == n { nth = list; } let tail: List = (*front).1; if is_none::>(tail) { let _unit: () = list_swap::(nth, list); return (*front).0; } list = tail; i = i + 1; } } // Return the next list element. fn list_next(list: List) -> List { return (*unwrap::)>>(list)).1; } // Split the list at index n. fn list_split(list: List, n: int) -> (List, List) { if n == 0 { return (None, list); } let list2: List = list; let i: int = 0; while i < n - 1 { list2 = list_next::(list2); i = i + 1; } if let Some(front) = list2 { list2 = (*front).1; front.1 = None; } return (list, list2); } // Increase swap count fn inc_swaps(swaps_and_comps: Rc<(int, int)>) { swaps_and_comps.0 = (*swaps_and_comps).0 + 1; } // Increase comparison count fn inc_comps(swaps_and_comps: Rc<(int, int)>) { swaps_and_comps.1 = (*swaps_and_comps).1 + 1; } // Randomised quicksort. // Expected complexity: O(n log n) fn quicksort(list: List, swaps_and_comps: Rc<(int, int)>) -> List { if list_len::(list) < 2 { return list; } let partition: Partition = partition(list, swaps_and_comps); let list: List = quicksort(partition.0, swaps_and_comps); let pivot: int = partition.1; let list2: List = quicksort(partition.2, swaps_and_comps); list2 = list_push_front::(list2, pivot); return list_append::(list, list2); } // Partition a list into smaller, pivot, and larger elements fn partition(list: List, swaps_and_comps: Rc<(int, int)>) -> Partition { // choose some random element as pivot and move it to the last position let list_len: int = list_len::(list); let pivot: int = list_swap_nth_last::(list, random(list_len)); let _unit: () = inc_swaps(swaps_and_comps); // this is our pivot position let iter: List = list; let iter_idx: int = -1; // move all elements smaller than our pivot to its left let i: int = 0; let iter2: List = list; while let Some(front) = iter2 { // don't swap out the pivot already if i != list_len - 1 { let _unit: () = inc_comps(swaps_and_comps); if (*front).0 <= pivot { // move pivot index forward if iter_idx >= 0 { iter = list_next::(iter); } iter_idx = iter_idx + 1; // swap current element with pivot position if iter_idx != i { let _unit: () = list_swap::(iter, iter2); let _unit: () = inc_swaps(swaps_and_comps); } } } iter2 = (*front).1; i = i + 1; } // move pivot to the correct pivot position iter_idx = iter_idx + 1; let _pivot: int = list_swap_nth_last::(list, iter_idx); let _unit: () = inc_swaps(swaps_and_comps); // split the list into two let lists: (List, List) = list_split::(list, iter_idx); let pop: (int, List) = list_pop_front::(lists.1); return (lists.0, pop.0, pop.1); } // Assert that the list is sorted. fn assert_sorted(list: List) -> () { if let Some(first) = list { if assert_sorted_impl((*first).1, (*first).0) { return (); } // else there's no path to a return statement - assert failed } else { return (); } } fn assert_sorted_impl(list: List, prev: int) -> bool { while let Some(front) = list { let curr: int = (*front).0; if curr < prev { return false; } prev = curr; list = (*front).1; } return true; } input!(len); // Create a random list. let list: List = list_new::(); let i: int = 0; while i < len { list = list_push_front::(list, random(len*2)); i = i + 1; } // Run quicksort. let swaps_and_comps: Rc<(int, int)> = Rc((0, 0)); list = quicksort(list, swaps_and_comps); let swaps: int = (*swaps_and_comps).0; let comps: int = (*swaps_and_comps).1; // Ensure the list is now sorted. let _unit: () = assert_sorted(list); output!(swaps); output!(comps);