Lecture 007

More on complexity of sorting

list sort list merge sort tree merge sort
Work $n^2$ $n\log(n)$ $n\log(n)$
Span $n^2$ $n$ $\log^3(n) ~ \log^2(n)$
(* split: int list -> int list * int list
REQUIRES: true
ENSURES: split L |-> A@B is a permutation of L, |length A - length B| <= 1
*)

fun split ([]: int list) : int list * int list = ([], [])
| split ([x]) = ([x], [])
| split (x::y::L) = let
val (A, B) = split L
in
(x::A, y::B)
end

W_{split}(0) = C_0
W_{split}(1) = C_1
W_{split}(n) = C_2 + W_{split} (n-2)
O(n)

S_{split} is the same as work

(* merge: int list * int list -> int list
REQUIRES: A and B are sorted
ENSURE: merge (A, B) |-> a sorted list that is a permutation of A@B
*)

fun merge ([]: int list, B: int list): int list = B
| merge (A, []) = A
| merge (x::xs, y::ys) = (case Int.compare (x, y) of
LESS => x :: merge(xs, y::ys)
EQUAL => x::y::merge(xs, ys)
GRETER => y :: merge(x::xs, ys)
)

W_{merge}(n) where n is the sum of length
W_{merge}(0) = C_0
W_{merge}(1) = C_1
W_{merge}(n) = C_2 + W_{merge} (n-1) (worst case for n > 1)
W_{merge} is O(n)
S_{merge} is O(n)

(*msort: int list -> int list
REQUIRES: true
ENSURES msort L |-> sorted permutation of L
*)

fun msort ([] : int list) : int list = []
| msort ([x]) = [x]
| msort L = let
val (A, B) = split L
in
merge (msort A, msort B)
end

W_{msort} (n) where n is the input length
W_{msort} (0) = C_0
W_{msort} (1) = C_1
W_{msort} (n) = C_2 + W_{split} (n) + W_{merge} (n) + 2W_{msort}(n/2) <= C_3 * n + 2 * msort(n/2)

Work is O(nlog(n)) by tree method
Span is O(n) by going down one branch C_3(n+n/2+n/4...)


Sorting Tree

(* Ins: int * tree -> tree
REQUIRES: T is sorted
ENSURES: Ins(x, T) |-> a sorted tree containing x and T
*)

fun Ins(x: int, Empty: tree) : tree = Node(Empty, x, Empty)
| Ins(x, Node(l, y, r)) = (case Int.compare(x, y) of
GREATER => Node(l, y, Ins(x, r))
| _ => Node(Ins(x, l), y, r))

W_{ins} (d) = O(d)
W_{ins} (n) = log(n) if the tree is balanced
W_{ins} (n) = n if the tree is not balanced

S_{ins} (d) is O(d)

(* Msort: tree -> tree
REQUIRES: true
ENSURES: Msort t |-> a sorted rearangement of t
*)

fun Msort (Empty : tree) : tree = Empty
| Msort (Node(l, x, r)) = Ins(x, Merge(Msort l, Msort r))


(* SplitAt: int * tree -> tree * tree
REQUIRES: T is sorted
ENSURES: SplitAt (x, T) => (S1, S2), S1 is sorted and all elements <= x, S2 is sorted and all elelment > x. Elements of S1, S2 together are the same as T
*)

fun splitAt (_: int, Empty: tree) : tree * tree = (Empty, Empty)
| splitAt (x, Node(l, y, r)) = (case Int.compare(x, y) of
LESS => let
val (s1, s2) = splitAt (x, l) (* all s1 <= x <= all s2 <= y <= all r*)
in
(s1, Node(s2, y, r))
end
| _ => let
val (s1, s2) = splitAt (x, r) (*all l <= y <= all s1 <= x <= all s*)
in
(Node(l, y, s1), s2)
end
)

(* Merge: tree * tree -> tree
REQUIRES: T1, T2 are sorted
ENSURES: Merge(T1, T2) contains T1 and T2
*)
fun Merge (Empty : tree, T2: tree) = T2
| Merge (T1, Empty) = T1 (*not essential*)
| Merge (Node (l1, x, r1), T2) = let
val (l2, r2) = splitAt (x, T2) (* so all l2 <= x <= all r2*)
in
Node(Merge(l1, l2), x, Merge(r1, r2))
end


Work of merge = O(nlog(n))

S_{ins}(d) = O(d) S_{splitAt}(d) = O(d) S_{merge}(d1, d2) = O(d1*d2)

S_{msort}(d) where d is the input's depth S_{msort}(0) = C_0 S_{msort}(d) = C_1 + max(S_{msort}(d-1), S_{msort}(d')) + S_{merge}() + S_{ins}()

| We can't do this since merged trees are unbalance, therefore, depth is greater than the original depth

Re-balance Tree

(* Msort: tree -> tree
REQUIRES: true
ENSURES: Msort t |-> a sorted rearangement of t
*)

fun Msort (Empty : tree) : tree = Empty
| Msort (Node(l, x, r)) = Rebalance(Ins(x, Merge(Msort l, Msort r)))

S_{Rebalance}(d) is O(d^2)


S_{msort}(d) where d is the input's depth S_{msort}(0) = C_0 S_{msort}(d) = C_1 + max(S_{msort}(d-1), S_{msort}(d')) + S_{Rebalance}(d) + S_{merge}(d1, d2) + S_{ins}(d3)

d' <= d-1 d1, d2 <= d d3 <= 2d

S_{msort}(d) <= C1 + C2d + C3d^2 (rebalance) + C4*d^2 (merge) + S_{msort}(d-1) S_{Msort}(d) is O(d^3), or O((log n)^3) if it is balanced

Table of Content