sorter: add some sorters
authorAlexandre Terrasa <alexandre@moz-code.org>
Thu, 8 May 2014 04:02:40 +0000 (00:02 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 8 May 2014 04:02:40 +0000 (00:02 -0400)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

lib/standard/collection/sorter.nit

index beca2ca..b6319e1 100644 (file)
@@ -4,7 +4,7 @@
 #
 # This file is free software, which comes along with NIT.  This software is
 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
+# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A
 # PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
 # is kept unaltered, and a notification of the changes is added.
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # a custom `Comparator::compare` function.
 module sorter
 
+import range
 import array
 
 # This abstract class generalizes ways to sort an array
 interface Comparator[E]
        # Compare `a` and `b`.
        # Returns:
-       #       -1 if a < b
+       #       -1 if a < b
        #       0  if a = b
        #       1  if a > b
        fun compare(a: E, b: E): Int is abstract
 
        # Sort `array` using the `compare` function.
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.sort(a)
+       #     assert a == [1, 2, 3, 4, 5]
        fun sort(array: Array[E]) do sub_sort(array, 0, array.length-1)
 
        # Sort `array` between `from` and `to` indices
@@ -42,8 +48,13 @@ interface Comparator[E]
        end
 
        # Quick-sort `array` between `from` and `to` indices
-       private fun quick_sort(array: Array[E], from: Int, to: Int)
-       do
+       # Worst case: O(n^2), Average case: O(n lg n)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.quick_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun quick_sort(array: Array[E], from: Int, to: Int) do
                var pivot = array[from]
                var i = from
                var j = to
@@ -61,9 +72,15 @@ interface Comparator[E]
                sub_sort(array, from, i-2)
                sub_sort(array, i, to)
        end
-       
+
        # Bubble-sort `array` between `from` and `to` indices
-       private fun bubble_sort(array: Array[E], from: Int, to: Int)
+       # Worst case: O(n^2), average case: O(n^2)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.bubble_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun bubble_sort(array: Array[E], from: Int, to: Int)
        do
                var i = from
                while i < to do
@@ -84,6 +101,108 @@ interface Comparator[E]
                        i += 1
                end
        end
+
+       # Insertion-sort `array` between `from` and `to` indices
+       # Worst case: O(n^2), average case: O(n^2)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.insertion_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun insertion_sort(array: Array[E], from: Int, to: Int) do
+               var last = array.length
+               for i in [from..to] do
+                       var j = i
+                       while j > 0 and compare(array[j], array[j - 1]) < 0 do
+                               array.swap_at(j, j - 1)
+                               j -= 1
+                       end
+               end
+       end
+
+       # Merge-sort `array` between `from` and `to` indices
+       # Worst case: O(n lg n), average: O(n lg n)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.merge_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun merge_sort(array: Array[E], from, to: Int) do
+               if from >= to then return
+               var mid = (to + from) / 2
+               merge_sort(array, from, mid)
+               merge_sort(array, mid + 1, to)
+               merge(array, from, mid, to)
+       end
+
+       private fun merge(array: Array[E], from, mid, to: Int) do
+               var l = new Array[E]
+               for i in [from..mid] do l.add array[i]
+               var r = new Array[E]
+               for i in [mid + 1..to] do r.add array[i]
+               var i = 0
+               var j = 0
+               for k in [from..to] do
+                       if i >= l.length then
+                               array[k] = r[j]
+                               j += 1
+                       else if j >= r.length then
+                               array[k] = l[i]
+                               i += 1
+                       else if compare(l[i], r[j]) <= 0 then
+                               array[k] = l[i]
+                               i += 1
+                       else
+                               array[k] = r[j]
+                               j += 1
+                       end
+               end
+       end
+
+       # Heap-sort `array` between `from` and `to` indices
+       # Worst case: O(n lg n), average: O(n lg n)
+       #
+       #     var s = new DefaultComparator[Int]
+       #     var a = [5, 2, 3, 1, 4]
+       #     s.heap_sort(a, 0, a.length - 1)
+       #     assert a == [1, 2, 3, 4, 5]
+       fun heap_sort(array: Array[E], from, to: Int) do
+               var size = build_heap(array)
+               for j in [from..to[ do
+                       array.swap_at(0, size)
+                       size -= 1
+                       heapify(array, 0, size)
+               end
+       end
+
+       private fun build_heap(array: Array[E]): Int do
+               var size = array.length - 1
+               var i = size / 2
+               while i >= 0 do
+                       heapify(array, i, size)
+                       i -= 1
+               end
+               return size
+       end
+
+       private fun heapify(array: Array[E], from, to: Int) do
+               var l = from * 2
+               var r = l + 1
+               var largest: Int
+               if l < to and compare(array[l], array[from]) > 0 then
+                       largest = l
+               else
+                       largest = from
+               end
+               if r < to and compare(array[r], array[largest]) > 0 then
+                       largest = r
+               end
+               if largest != from then
+                       array.swap_at(from, largest)
+                       heapify(array, largest, to)
+               end
+       end
+
 end
 
 # Deprecated class, use `Comparator` instead