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...)
(* 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
(* 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