Bottom up merge sort in Haskell
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
Although this sort works on Int lists < length million, when the stack overflows, the last clause of the merge function definition looks odd to me, recursing in 2 places. Is there clearer way to define that definition and how can the stack limitation be avoided?
msort :: Ord a => [a] -> [a]
msort =
msort xs = concat . merge . split $ xs
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge (l1:l2:ls) = merge $ mpair l1 l2 : merge ls
mpair :: Ord a => [a] -> [a] -> [a]
mpair l2 = l2
mpair l1 = l1
mpair l1@(x:xs) l2@(y:ys) | x >= y = x : mpair xs l2
| otherwise = y : mpair l1 ys
split :: [a] -> [[a]]
split xs = [[x]| x<-xs]
haskell mergesort
add a comment |Â
up vote
2
down vote
favorite
Although this sort works on Int lists < length million, when the stack overflows, the last clause of the merge function definition looks odd to me, recursing in 2 places. Is there clearer way to define that definition and how can the stack limitation be avoided?
msort :: Ord a => [a] -> [a]
msort =
msort xs = concat . merge . split $ xs
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge (l1:l2:ls) = merge $ mpair l1 l2 : merge ls
mpair :: Ord a => [a] -> [a] -> [a]
mpair l2 = l2
mpair l1 = l1
mpair l1@(x:xs) l2@(y:ys) | x >= y = x : mpair xs l2
| otherwise = y : mpair l1 ys
split :: [a] -> [[a]]
split xs = [[x]| x<-xs]
haskell mergesort
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
Although this sort works on Int lists < length million, when the stack overflows, the last clause of the merge function definition looks odd to me, recursing in 2 places. Is there clearer way to define that definition and how can the stack limitation be avoided?
msort :: Ord a => [a] -> [a]
msort =
msort xs = concat . merge . split $ xs
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge (l1:l2:ls) = merge $ mpair l1 l2 : merge ls
mpair :: Ord a => [a] -> [a] -> [a]
mpair l2 = l2
mpair l1 = l1
mpair l1@(x:xs) l2@(y:ys) | x >= y = x : mpair xs l2
| otherwise = y : mpair l1 ys
split :: [a] -> [[a]]
split xs = [[x]| x<-xs]
haskell mergesort
Although this sort works on Int lists < length million, when the stack overflows, the last clause of the merge function definition looks odd to me, recursing in 2 places. Is there clearer way to define that definition and how can the stack limitation be avoided?
msort :: Ord a => [a] -> [a]
msort =
msort xs = concat . merge . split $ xs
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge (l1:l2:ls) = merge $ mpair l1 l2 : merge ls
mpair :: Ord a => [a] -> [a] -> [a]
mpair l2 = l2
mpair l1 = l1
mpair l1@(x:xs) l2@(y:ys) | x >= y = x : mpair xs l2
| otherwise = y : mpair l1 ys
split :: [a] -> [[a]]
split xs = [[x]| x<-xs]
haskell mergesort
asked Jul 11 at 22:45
newbie123
111
111
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
0
down vote
You've spotted the problem. Your merge
function is flawed. For each pair it processes, it introduces an extra unnecessary call to merge. That is, for a list like [1,2,3,4,5,6]
, instead of your first merge
call expanding directly to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : mpair [3] [4] : mpair [5] [6] :
it expands to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : merge $ mpair [3] [4]
: merge $ mpair [5] [6] : merge
As a result, your count of merge
calls is O(n)
and your count of mpair
calls is O(n^2)
(or similar -- I didn't check exactly). when they should be O(log n)
and O(n log n)
respectively.
Instead, you want to split merge
up into two functions:
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge ls = merge (mergePairs ls)
mergePairs :: Ord a => [[a]] -> [[a]]
mergePairs (l1:l2:ls) = mpair l1 l2 : mergePairs ls
mergePairs ls = ls
This will speed up the algorithm enormously, and it will now run on tens of millions of integers.
add a comment |Â
up vote
-1
down vote
See mergeAll
.
They insert a bang to adjust the evaluation order, and push the second recursion down into the next definition.
You could experiment with the mutant offspring of the two implementations to try and understand reasons for their difference.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
You've spotted the problem. Your merge
function is flawed. For each pair it processes, it introduces an extra unnecessary call to merge. That is, for a list like [1,2,3,4,5,6]
, instead of your first merge
call expanding directly to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : mpair [3] [4] : mpair [5] [6] :
it expands to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : merge $ mpair [3] [4]
: merge $ mpair [5] [6] : merge
As a result, your count of merge
calls is O(n)
and your count of mpair
calls is O(n^2)
(or similar -- I didn't check exactly). when they should be O(log n)
and O(n log n)
respectively.
Instead, you want to split merge
up into two functions:
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge ls = merge (mergePairs ls)
mergePairs :: Ord a => [[a]] -> [[a]]
mergePairs (l1:l2:ls) = mpair l1 l2 : mergePairs ls
mergePairs ls = ls
This will speed up the algorithm enormously, and it will now run on tens of millions of integers.
add a comment |Â
up vote
0
down vote
You've spotted the problem. Your merge
function is flawed. For each pair it processes, it introduces an extra unnecessary call to merge. That is, for a list like [1,2,3,4,5,6]
, instead of your first merge
call expanding directly to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : mpair [3] [4] : mpair [5] [6] :
it expands to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : merge $ mpair [3] [4]
: merge $ mpair [5] [6] : merge
As a result, your count of merge
calls is O(n)
and your count of mpair
calls is O(n^2)
(or similar -- I didn't check exactly). when they should be O(log n)
and O(n log n)
respectively.
Instead, you want to split merge
up into two functions:
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge ls = merge (mergePairs ls)
mergePairs :: Ord a => [[a]] -> [[a]]
mergePairs (l1:l2:ls) = mpair l1 l2 : mergePairs ls
mergePairs ls = ls
This will speed up the algorithm enormously, and it will now run on tens of millions of integers.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
You've spotted the problem. Your merge
function is flawed. For each pair it processes, it introduces an extra unnecessary call to merge. That is, for a list like [1,2,3,4,5,6]
, instead of your first merge
call expanding directly to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : mpair [3] [4] : mpair [5] [6] :
it expands to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : merge $ mpair [3] [4]
: merge $ mpair [5] [6] : merge
As a result, your count of merge
calls is O(n)
and your count of mpair
calls is O(n^2)
(or similar -- I didn't check exactly). when they should be O(log n)
and O(n log n)
respectively.
Instead, you want to split merge
up into two functions:
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge ls = merge (mergePairs ls)
mergePairs :: Ord a => [[a]] -> [[a]]
mergePairs (l1:l2:ls) = mpair l1 l2 : mergePairs ls
mergePairs ls = ls
This will speed up the algorithm enormously, and it will now run on tens of millions of integers.
You've spotted the problem. Your merge
function is flawed. For each pair it processes, it introduces an extra unnecessary call to merge. That is, for a list like [1,2,3,4,5,6]
, instead of your first merge
call expanding directly to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : mpair [3] [4] : mpair [5] [6] :
it expands to:
merge [[1],[2],[3],[4],[5],[6]]
= merge $ mpair [1] [2] : merge $ mpair [3] [4]
: merge $ mpair [5] [6] : merge
As a result, your count of merge
calls is O(n)
and your count of mpair
calls is O(n^2)
(or similar -- I didn't check exactly). when they should be O(log n)
and O(n log n)
respectively.
Instead, you want to split merge
up into two functions:
merge :: Ord a => [[a]] -> [[a]]
merge =
merge [x] = [x]
merge ls = merge (mergePairs ls)
mergePairs :: Ord a => [[a]] -> [[a]]
mergePairs (l1:l2:ls) = mpair l1 l2 : mergePairs ls
mergePairs ls = ls
This will speed up the algorithm enormously, and it will now run on tens of millions of integers.
edited Jul 17 at 23:21
answered Jul 17 at 22:56
K. A. Buhr
2263
2263
add a comment |Â
add a comment |Â
up vote
-1
down vote
See mergeAll
.
They insert a bang to adjust the evaluation order, and push the second recursion down into the next definition.
You could experiment with the mutant offspring of the two implementations to try and understand reasons for their difference.
add a comment |Â
up vote
-1
down vote
See mergeAll
.
They insert a bang to adjust the evaluation order, and push the second recursion down into the next definition.
You could experiment with the mutant offspring of the two implementations to try and understand reasons for their difference.
add a comment |Â
up vote
-1
down vote
up vote
-1
down vote
See mergeAll
.
They insert a bang to adjust the evaluation order, and push the second recursion down into the next definition.
You could experiment with the mutant offspring of the two implementations to try and understand reasons for their difference.
See mergeAll
.
They insert a bang to adjust the evaluation order, and push the second recursion down into the next definition.
You could experiment with the mutant offspring of the two implementations to try and understand reasons for their difference.
answered Jul 12 at 11:14
Gurkenglas
2,648411
2,648411
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198330%2fbottom-up-merge-sort-in-haskell%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password