(load "asmt-helper.scm") (header "Code from class" "6 March 2019") (problem "Insertion sort") ;; INSERT ;; ------ ;; INPUTS: NUM, a number ;; SORTED, a list of numbers already sorted ;; into non-decreasing order. ;; OUTPUT: The list obtained by inserting NUM into SORTED ;; while preserving the non-decreasing ordering. (define insert (lambda (num sorted) (cond ;; Base case 1: SORTED is empty ((null? sorted) (list num)) ;; Base case 2: We found where NUM goes ((<= num (first sorted)) (cons num sorted)) ;; Recursive case: We haven't found where NUM goes (else (cons (first sorted) (insert num (rest sorted))))))) (tester '(insert 3 '())) (tester '(insert 3 '(6 8 9))) (tester '(insert 3 '(1 2 3 4 5 6))) ;; INSERTION-SORT ;; -------------- ;; INPUTS: LST, a list of numbers ;; OUTPUT: A list containing the same elements as LST, but ;; sorted into non-decreasing order. (define insertion-sort (lambda (lst) (if (null? lst) ;; Base case: The list is already sorted. '() ;; Recursive case: Sort the rest of the list and ;; then put the first item in the right place. (insert (first lst) (insertion-sort (rest lst)))))) ;; INSERTION-SORT-ACC ;; ------------------ ;; INPUTS: LST, a list of numbers ;; OUTPUT: A list containing the same elements as LST, but ;; sorted into non-decreasing order. (define insertion-sort-acc (lambda (lst) (letrec ((helper (lambda (lst acc) (if (null? lst) acc (helper (rest lst) (insert (first lst) acc)))))) (helper lst '())))) (problem "Merge sort") (define split-acc (lambda (lst left right) (cond ;; Base case 1: LST is empty ;; Create a two-element list whose elements are ;; LEFT and RIGHT. ((null? lst) (list left right)) ;; Base case 2: LST has one element ;; Arbitrarily let RIGHT accumulate the one element ((null? (rest lst)) (list left (cons (first lst) right))) ;; Recursive Case: LST has at least two elements ;; Put one on each accumulator. (else (split-acc (rest (rest lst)) (cons (first lst) left) (cons (second lst) right)))))) (define split (lambda (lst) (split-acc lst '() '()))) (tester '(split '(1 2 3 4 5 6 7))) ;; MERGE ;; ----- ;; INPUTS: SORTED1, SORTED2, two already sorted lists of ;; numbers ;; OUTPUT: A list containing all of the elements of both ;; input lists, sorted. (define merge (lambda (sorted1 sorted2) (cond ;; Base Case 1 ((null? sorted1) sorted2) ;; Base Case 2 ((null? sorted2) sorted1) ;; Recursive Case 1: Both lists are non-empty ((<= (first sorted1) (first sorted2)) (cons (first sorted1) (merge (rest sorted1) sorted2))) ;; Recursive Case 2 (else (cons (first sorted2) (merge sorted1 (rest sorted2))))))) (tester '(merge '(1 2 3) '())) (tester '(merge '(1 3 5) '(2 4 6))) ;; MERGE-SORT ;; ---------- ;; INPUT: LST, a list of numbers ;; OUTPUT: A list containing the elements of LST in ;; non-decreasing order. (define merge-sort (lambda (lst) (if (or (null? lst) (null? (rest lst))) ;; Base case: LST has 0 or 1 elements, so it's ;; already sorted lst ;; Recursive case: LST has at least TWO elements (let* ((pair-of-lists (split lst)) (left (first pair-of-lists)) (right (second pair-of-lists)) (sorted-left (merge-sort left)) (sorted-right (merge-sort right))) (merge sorted-left sorted-right))))) (tester '(merge-sort '(1 0 8 3 2))) (problem "Generating random data") ;; RANDOM-NUMS ;; ----------- ;; INPUTS: N, a positive integer ;; BOUND, a positive integer ;; OUTPUT: A list containing N numbers, each randomly ;; generated from the set {0, 1, ... BOUND - 1} (define random-nums (lambda (n bound) (if (<= n 0) ;; Base case: No (more) numbers to generate '() ;; Recursive case: ;; Generate at least one more number (cons (random bound) (random-nums (- n 1) bound))))) (tester '(random-nums 5 10)) (problem "Comparing performance of insertion sort and merge sort") (tester '(define data (random-nums 10000 100000))) (tester '(time (insertion-sort data) #t)) (tester '(time (insertion-sort-acc data) #t)) (tester '(time (merge-sort data) #t))