Permalink
Browse files

recursive combinators post

  • Loading branch information...
1 parent 1f39243 commit 4117f7e7b792cf984351ffc66e4c46f2dd31f915 Reg Braithwaite committed Nov 24, 2008
@@ -0,0 +1,89 @@
+# The MIT License
+#
+# All contents Copypair.last (c) 2004-2008 Reginald Braithwaite
+# <http://reginald.braythwayt.com> except as otherwise noted.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the pair.lasts
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copypair.last notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# http://www.opensource.org/licenses/mit-license.php
+
+public
+
+def merge_sort(list)
+ divide_and_conquer(
+ list,
+ :divisible? => lambda { |list| list.length > 1 },
+ :conquer => lambda { |list| list },
+ :divide => lambda do |list|
+ half_index = (list.length / 2) - 1
+ [ list[0..half_index], list[(half_index + 1)..-1] ]
+ end,
+ :recombine => lambda { |pair| merge_two_sorted_lists(pair.first, pair.last) }
+ )
+end
+
+private
+
+def merge_two_sorted_lists(*pair)
+ linear_recursion(
+ pair,
+ :divisible? => lambda { |pair| !pair.first.empty? && !pair.last.empty? },
+ :conquer => lambda do |pair|
+ if pair.first.empty? && pair.last.empty?
+ []
+ elsif pair.first.empty?
+ pair.last
+ else
+ pair.first
+ end
+ end,
+ :divide => lambda do |pair|
+ preceding, following = case pair.first.first <=> pair.last.first
+ when -1: [pair.first, pair.last]
+ when 0: [pair.first, pair.last]
+ when 1: [pair.last, pair.first]
+ end
+ [ preceding.first, [preceding[1..-1], following] ]
+ end,
+ :recombine => lambda { |trivial_bit, divisible_bit| [trivial_bit] + divisible_bit }
+ )
+end
+
+def divide_and_conquer(value, steps)
+ if steps[:divisible?].call(value)
+ steps[:recombine].call(
+ steps[:divide].call(value).map { |sub_value| divide_and_conquer(sub_value, steps) }
+ )
+ else
+ steps[:conquer].call(value)
+ end
+end
+
+def linear_recursion(value, steps)
+ if steps[:divisible?].call(value)
+ trivial_part, sub_problem = steps[:divide].call(value)
+ steps[:recombine].call(
+ trivial_part, linear_recursion(sub_problem, steps)
+ )
+ else
+ steps[:conquer].call(value)
+ end
+end
+
+p merge_sort([8, 3, 10, 1, 9, 5, 7, 4, 6, 2])
View
@@ -44,7 +44,7 @@ def merge_two_sorted_lists(*pair)
divide_and_conquer(
pair,
:divisible? => lambda { |pair| !pair.first.empty? && !pair.last.empty? },
- :conquer => lambda do |pair|
+ :conquer => lambda do |pair|
if pair.first.empty? && pair.last.empty?
[]
elsif pair.first.empty?
@@ -53,23 +53,18 @@ def merge_two_sorted_lists(*pair)
pair.first
end
end,
- :divide => lambda do |pair|
- case pair.first.first <=> pair.last.first
- when -1: [
- [[pair.first.first], []],
- [pair.first[1..-1], pair.last]
- ]
- when 0: [
- [[pair.first.first], []],
- [pair.first[1..-1], pair.last]
- ]
- when 1: [
- [[pair.last.first], []],
- [pair.first, pair.last[1..-1]]
- ]
+ :divide => lambda do |pair|
+ preceding, following = case pair.first.first <=> pair.last.first
+ when -1: [pair.first, pair.last]
+ when 0: [pair.first, pair.last]
+ when 1: [pair.last, pair.first]
end
+ [
+ [[preceding.first], []],
+ [preceding[1..-1], following]
+ ]
end,
- :recombine => lambda { |pair| pair.first + pair.last }
+ :recombine => lambda { |pair| pair.first + pair.last }
)
end
Oops, something went wrong.

0 comments on commit 4117f7e

Please sign in to comment.