From 3850ec230e01a1b557ebabc26900727515689cf7 Mon Sep 17 00:00:00 2001 From: hkiel Date: Tue, 10 Oct 2017 12:02:16 +0200 Subject: [PATCH] implement natural merge sort to have O(n) for already sorted lists --- Compiler/Util/List.mo | 134 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 6 deletions(-) diff --git a/Compiler/Util/List.mo b/Compiler/Util/List.mo index 937efde20e..75131e8600 100644 --- a/Compiler/Util/List.mo +++ b/Compiler/Util/List.mo @@ -737,13 +737,135 @@ algorithm end stripN; public function sort + input list inList; + input CompareFunc inCompFunc; + output list outList; + + partial function CompareFunc + input T inElement1; + input T inElement2; + output Boolean inRes; + end CompareFunc; +algorithm + outList := rsort(inList, inCompFunc); +end sort; + +protected function rsort + input list inList; + input CompareFunc inCompFunc; + output list outList; + + partial function CompareFunc + input T inElement1; + input T inElement2; + output Boolean inRes; + end CompareFunc; + +protected + list> runs; + list l1, l2; +algorithm + if not listEmpty(inList) then + runs := splitRuns(inList, inCompFunc); + outList := rxsort(runs, inCompFunc); + else + outList := inList; + end if; +end rsort; + +protected function splitRuns + input list inList; + input CompareFunc inCompFunc; + output list> outList = {}; + + partial function CompareFunc + input T inElement1; + input T inElement2; + output Boolean inRes; + end CompareFunc; +protected + T e1; + list l = {}, rest; +algorithm + if not listEmpty(inList) then + e1::rest := inList; + for e in rest loop + if inCompFunc(e1, e) then + if listEmpty(l) then + outList := {e1}::outList; + else + outList := listReverseInPlace(e1::l)::outList; + l := {}; + end if; + else + l := e1 :: l; + end if; + e1 := e; + end for; + l := e1::l; + outList := listReverseInPlace(l)::outList; + end if; +end splitRuns; + +protected function rxsort + input list> inList; + input CompareFunc inCompFunc; + output list sorted = {}; + + partial function CompareFunc + input T inElement1; + input T inElement2; + output Boolean inRes; + end CompareFunc; +protected + Integer len; + Integer middle; + list> left = inList, right = {}, rest; + list l1, l2, l3; +algorithm + while true loop + if listEmpty(left) then + if listEmpty(right) then + return; + else + l1::rest := right; + if listEmpty(rest) then + sorted := l1; + return; + else + left := listReverseInPlace(right); + right := {}; + end if; + end if; + else + l1::rest := left; + if listEmpty(rest) then + if listEmpty(right) then + sorted := l1; + return; + else + l2::rest := right; + l3 := merge(l2, l1, inCompFunc, {}); + left := listReverseInPlace(l3::rest); + right := {}; + end if; + else + l2::rest := rest; + left := rest; + right := merge(l1, l2, inCompFunc, {})::right; + end if; + end if; + end while; +end rxsort; + +protected function mergesort "Sorts a list given an ordering function with the mergesort algorithm. Example: sort({2, 1, 3}, intGt) => {1, 2, 3} sort({2, 1, 3}, intLt) => {3, 2, 1}" input list inList; input CompareFunc inCompFunc; - output list outList= {}; + output list outList = {}; partial function CompareFunc input T inElement1; @@ -767,13 +889,13 @@ algorithm else middle := intDiv(listLength(inList), 2); (left, right) := split(inList, middle); - left := sort(left, inCompFunc); - right := sort(right, inCompFunc); + left := mergesort(left, inCompFunc); + right := mergesort(right, inCompFunc); outList := merge(left, right, inCompFunc, {}); end if; end if; end if; -end sort; +end mergesort; public function sortedDuplicates "Returns a list of all duplicates in a sorted list, using the given comparison @@ -936,7 +1058,7 @@ algorithm local Boolean b; T l, r, el; - list l_rest, r_rest, res; + list l_rest, r_rest; /* Tail recursive version */ case (l :: l_rest, r :: r_rest) @@ -1440,7 +1562,7 @@ public function sublist output list outList = {}; protected T e; - list rest = inList, res; + list rest = inList; algorithm true := inOffset > 0; true := inLength >= 0;