├── .gitignore ├── LICENSE ├── README.md ├── search └── binarysearch.scala └── sort ├── README.md ├── bubblesort.scala ├── bucketsort.scala ├── countingsort.scala ├── heapsort.scala ├── insertionsort.scala ├── mergesort.scala ├── quicksort.scala ├── radixsort.scala └── selectionsort.scala /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | .cache 6 | .history 7 | .lib/ 8 | dist/* 9 | target/ 10 | lib_managed/ 11 | src_managed/ 12 | project/boot/ 13 | project/plugins/project/ 14 | 15 | # Scala-IDE specific 16 | .scala_dependencies 17 | .worksheet 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Christopher Bunn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Scala Algorithms 2 | Practice implementations of some algorithms in Scala! 3 | -------------------------------------------------------------------------------- /search/binarysearch.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Binary search. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Given a sorted array 'a', find the midpoint. If the target is less than 6 | * the midpoint, repeat on the left half of the array. If the target is 7 | * greater than the midpoint, repeat on the right half of the array. If 8 | * the target is the midpoint, return the midpoint location. If the subarray 9 | * has no length, stop (we haven't found the target). 10 | **/ 11 | 12 | object BinarySearch { 13 | def main(args: Array[String]) { 14 | val sorted = Array(2, 3, 4, 5, 8, 9, 13) 15 | 16 | println(search(sorted, 13, 0, sorted.length-1)) 17 | } 18 | 19 | def search(a: Array[Int], target: Int, lo: Int, hi: Int): Int = { 20 | if(hi < lo) return -1 21 | val mid = (hi-lo)/2 + lo 22 | 23 | target match { 24 | case t if t < a(mid) => return search(a, target, lo, mid-1) 25 | case t if t > a(mid) => return search(a, target, mid+1, hi) 26 | case t if t == a(mid) => return mid 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /sort/README.md: -------------------------------------------------------------------------------- 1 | # sorts 2 | Practice implementations of classic sort algorithms, for the sake of (re)learning some algorithms and Scala. 3 | 4 | #Quicksort 5 | 6 | ##Summary: 7 | Quicksort is a divide and conquer comparison sort that exhibits O(n*log(n)) behavior on average. Its worst case O(n^2) occurs when sorting an already-sorted list. Quicksort is unstable. 8 | 9 | ##Use Cases: 10 | A high performance sort, Quicksort is versatile and widely used. Typically 2x-3x faster than merge sort and heapsort, except in worst cases where these alrogirthms operate in O(n*log(n)). Because it operates in-place, auxiliary space complexity can be limited to O(log(n)). Performs poorly on already-sorted lists, since partitioning can be lopsided in these cases. For very small data sets, insertion sort can be faster. Can be parallelized due to divide and concquer setup. 11 | 12 | #Insertion Sort 13 | 14 | ##Summary: 15 | Insertion sort is a simple, in-place comparison sort that exhibits O(n^2) behavior on average and worst case. Insertion sort is stable. 16 | 17 | ##Use Cases: 18 | An inefficient sort, Insertion sort is most frequently used on very small datasets due to its low constants, and can be faster than quicksort in these cases. Best case performance O(n) occurs when sorting already-sorted or nearly-sorted data. This algorithm can sort stream data and requires O(n) auxiliary space. 19 | 20 | #Merge Sort 21 | 22 | ##Summary: 23 | Merge sort is a divide an conquer comparison sort that exhibits O(N*log(n)) behavior in both average and worst cases. It is typically slightly slower than quicksort, and cannot be performed in-place. Merge sort is stable. 24 | 25 | ##Use Cases: 26 | Merge sort is ideal for cases where data must be accessed sequentially, such as when reading data from slow disk or linked lists. One trade-off is the need for O(n) auxiliary space in most applications. The algorithm is the default sorting mechanism in Perl, and it plays a role in the default algorithms for Python, Java, and Octave. Can be parallelized due to divide and conquer design. 27 | 28 | #Bubble Sort 29 | 30 | ##Summary: 31 | Bubble sort is an exchange sort that exhibits O(n^2) in both average and worst cases. It is rarely used due to its poor performance (worse than Insertion sort). Bubble sort is stable. 32 | 33 | ##Use Cases: 34 | Because of its terrible time complexity, Bubble sort is rarely used. One advantage is that its worst case auxiliary space complexity is O(1). It behaves reasonably fast on nearly-sorted data, but its use is rare. 35 | 36 | #Heap Sort 37 | 38 | ##Summary: 39 | Heap sort is a comparison sort that exhibits O(n*log(n)) behavior in average and worst cases. It typically uses an array to represent a complete binary tree max heap. As elements are popped off the heap, they are removed in reverse sorted order. Heap sort is not stable. 40 | 41 | ##Use Cases: 42 | Heap sort is quite efficient, sorts in place (auxiliary space complexity is O(1)), and has better worst case time complexity than quicksort. Typically, however, it is slightly slower than quicksort. Less space is required than for merge sort. 43 | 44 | #Selection Sort 45 | 46 | ##Summary: 47 | Selection sort is an in-place algorithm that exhibits O(n^2) performance in the best, average, and worst cases. Run time is actually always worst case. Though it typically runs faster than bubble sort, it is still very slow on large datasets. Basic selection sort is not stable. 48 | 49 | ##Use Cases: 50 | The low time constant makes Selection sort outperform divide-and-conquer algorithms on very small (typically < 20 elements) arrays, so it is often paired with a d&c algorithm for versatility. Because the runtime is solely determined by the length of the array, this sort could be attractive for use in real-time systems. Auxiliary space complexity is limited to O(1), but the slow general performance limits the algorithm's use. 51 | 52 | #Bucket Sort 53 | 54 | ##Summary: 55 | Bucket sort is a distribution sort that exhibits O(n^2) worst case, but O(n+k) average performance, where k is the number of buckets. While it can be extremely fast, Bucket sort requires some additional information than comparison sorts do; namely, the maximum value of the data to be sorted, and worst case space complexity is O(n*k). Bucket sort is stable. 56 | 57 | ##Use Cases: 58 | Because performance is directly correlated to how evenly data is distributed across the k buckets, Bucket sort is best deployed on values in a known domain, such as grade point averages, alphanumeric characters, etc, especially where data is uniformly distributed across the domain. It is frequently used as a first pass before then calling Insertion sort, as a way to boost the performance of the latter (which improves with nearly-sorted data). 59 | 60 | #Counting Sort 61 | 62 | ##Summary: 63 | Counting sort is a distribution sort (like Bucket sort) used to sort integers. It exhibits O(n+k) time in all cases, in exchange for using total space of O(n+k), where k is the unique number of keys between the maximum and minimum values to be sorted. Because two equivalent integers are identical, Counting sort can be considered a stable sort. 64 | 65 | ##Use Cases: 66 | Counting sort can only be used to sort integers because the result is assembled using an array index value, rather than the original elements. Because of its time and space complexities, Counting sort is most efficient when k << n (ie, when max and min values in the set n are close together, especially when there are many duplicates in n). 67 | 68 | #Radix Sort 69 | 70 | ##Summary: 71 | Radix sort is a non-comparison sort used to sort integers. It has a few flavors, the most common example of which is Least Significant Digit sort, which exhibits O(n*k) time in all cases. Space complexity is O(k+n), where k is the length of the keys to be sorted (ie, the word size). 72 | 73 | ##Use Cases: 74 | Similar to Counting sort (often a component), the Radix sort can only be used to sort data represented by integers. It can be very fast when k is limited, but this requires some advance knowledge of the dataset. If k > log(n), comparison sorts may perform better. 75 | -------------------------------------------------------------------------------- /sort/bubblesort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Bubble sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Moving left to right, compare two adjacent elements. If they are out of 6 | * order, swap them, then move one element to the right and repeat. Repeat 7 | * this whole exercise until the entire list is sorted. Note that, over time, 8 | * the greatest values race to the right and the unsorted subarray becomes 9 | * truncated. The final iteration only compares the leftmost pair. 10 | **/ 11 | 12 | object BubbleSort { 13 | def main(args: Array[String]) { 14 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 15 | 16 | sort(mess) 17 | 18 | mess.foreach( println ) 19 | } 20 | 21 | /** Executes bubble sort on an array. */ 22 | def sort(a: Array[Int]): Unit = { 23 | // Track right edge of the (shrinking) yet-unsorted region 24 | var hi = a.length-1 25 | 26 | // Once we perform a full iteration without swapping, the array is sorted. 27 | var swapped = true 28 | 29 | while (swapped) { 30 | swapped = false 31 | for (i <- 0 until hi 32 | if a(i) > a(i+1)) { 33 | swapped = true 34 | swap(a, i, i+1) 35 | hi = i 36 | } 37 | } 38 | } 39 | 40 | /** Swaps two elements in an array. */ 41 | def swap(a: Array[Int], i: Int, j: Int): Unit = { 42 | val staging: Int = a(i) 43 | a(i) = a(j) 44 | a(j) = staging 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sort/bucketsort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Bucket Sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Iterate over the input, segregating elements into a fixed number of ordinal 6 | * buckets. The sort each bucket. Iterate over the buckets in order, 7 | * reconstructing the original input in sorted order. 8 | * 9 | * Note that, rather than recursively sorting each bucket, another solution 10 | * is to concatenate the buckets and run Insertion sort on the new (nearly- 11 | * sorted) result. 12 | * 13 | * Also note that this algorithm (as implemented) only works for positive 14 | * numbers. For more versatility, a simple shift could be used to ensure 15 | * negative values are properly handled. 16 | **/ 17 | import scala.collection.mutable.ArrayBuffer 18 | 19 | object BucketSort { 20 | def main(args: Array[String]) { 21 | var mess = Array(3, 9, 8, 13, 2, 5, 4, 12); 22 | 23 | // Move contents to an ArrayBuffer since 24 | // our recursive sort requires a mutable 25 | // data structure. This could be avoided 26 | // in a hybrid bucketsort/insertionsort 27 | val ab = new ArrayBuffer[Int] 28 | val n_buckets = 5 29 | var (min, max) = (mess(0), mess(0)) 30 | for (value <- mess) { 31 | ab += value 32 | if (value < min) min = value 33 | else if (value > max) max = value 34 | } 35 | sort(ab, n_buckets, min, max) 36 | 37 | ab.foreach( println ) 38 | } 39 | 40 | def sort(a: ArrayBuffer[Int], n_buckets: Int, min: Int, max: Int) : Unit = { 41 | if (a.length < 2) return //a bucket could be empty, or have one element 42 | 43 | val buckets = ArrayBuffer.fill(n_buckets,0)(0) 44 | for (i <- 0 until n_buckets) { 45 | buckets(i) = new ArrayBuffer[Int] 46 | } 47 | 48 | for (value <- a) { 49 | val bucket_no = math.min((value - min) * n_buckets / (max - min), n_buckets - 1) 50 | buckets(bucket_no) += value 51 | } 52 | 53 | // we'll overwrite 'a' to save space 54 | val width = (max - min) / n_buckets 55 | var i = 0 56 | var b = 0 57 | for (bucket <- buckets) { 58 | sort(bucket, n_buckets, 59 | min + b * (max - min) / n_buckets, 60 | min + (b + 1) * (max - min) / n_buckets ) 61 | for (value <- bucket) { 62 | a(i) = value 63 | i+=1 64 | } 65 | b+=1 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /sort/countingsort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Counting sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Create an ordered array of all unique values (ie, keys) between min and max 6 | * of the array to be sorted. 7 | * Count the occurrences of each key, and store this value in the array. 8 | * Iterate through array, assembling each key in order, repeated once for 9 | * each occurrence. 10 | **/ 11 | 12 | object CountingSort { 13 | def main(args: Array[String]) { 14 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 15 | 16 | val result = sort(mess, mess.min, mess.max) 17 | result.foreach( println ) 18 | } 19 | 20 | def sort(a: Array[Int], min: Int, max: Int): Array[Int] = { 21 | def key(value: Int): Int = { 22 | return value - min 23 | } 24 | 25 | val result: Array[Int] = new Array[Int](a.length) 26 | 27 | // Count how many of each key we have 28 | val count: Array[Int] = new Array[Int](max - min + 1) 29 | a.foreach( (e: Int) => count(key(e)) += 1) 30 | 31 | // Add preceding counts to compute offset for each key 32 | for (i <- 1 to (max-min)) { 33 | count(i) += count(i-1) 34 | } 35 | 36 | // Assemble results using offset and sorted keys 37 | for (e <- a.reverseIterator) { 38 | count(key(e)) -= 1 39 | result(count(key(e))) = e 40 | } 41 | return result 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sort/heapsort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Heap sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Push all elements onto a max heap (in place). Then pop off the root node (ie, max 6 | * remaining value on heap) until you've popped all values off the heap. The values 7 | * leave the heap in reverse sorted order, so as the heap shrinks, we can put popped 8 | * values to the right end of the same array. 9 | **/ 10 | 11 | object HeapSort { 12 | def main(args: Array[String]): Unit = { 13 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 14 | 15 | sort(mess) 16 | // buildHeap(mess, mess.length-1) 17 | 18 | mess.foreach( println ) 19 | } 20 | 21 | def sort(a: Array[Int]): Unit = { 22 | var m = a.length - 1 23 | buildHeap(a, m) 24 | while (m >= 1) { 25 | swap(a, 0, m) 26 | m-=1 27 | heapify(a, 0, m) 28 | } 29 | } 30 | 31 | def buildHeap(a: Array[Int], m: Int): Unit = { 32 | for (i <- m/2 to 0 by -1) { 33 | heapify(a, i, m) 34 | } 35 | } 36 | 37 | /**Pushes an illegally located element down the heap to restore heap property.*/ 38 | @annotation.tailrec 39 | def heapify(a: Array[Int], loc: Int, lastLeaf: Int): Unit = { 40 | val l = left(loc) 41 | val r = right(loc) 42 | 43 | var max = loc 44 | 45 | if(l <= lastLeaf && a(l) > a(max)) max = l 46 | if(r <= lastLeaf && a(r) > a(max)) max = r 47 | 48 | if(max != loc) { 49 | swap(a, max, loc) 50 | heapify(a, max, lastLeaf) 51 | } 52 | } 53 | 54 | /**Returns position of left child (possibly empty). */ 55 | def left(loc: Int): Int = { 56 | return 2*loc 57 | } 58 | 59 | /**Returns position of right child (possibly empty). */ 60 | def right(loc: Int): Int = { 61 | return 2*loc+1 62 | } 63 | 64 | def swap(a: Array[Int], i: Int, j:Int): Unit = { 65 | val staging = a(i) 66 | a(i) = a(j) 67 | a(j) = staging 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /sort/insertionsort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Insertion Sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Moving left to right, evaluate each new value against those to its left, 6 | * all of which are already sorted. Move this value leftwards until it too is 7 | * sorted, then move on to the next. At any point in the iteration, all 8 | * elements to the left are already sorted, and an unsorted subset exists 9 | * to the right. 10 | **/ 11 | 12 | object InsertionSort { 13 | def main(args: Array[String]) { 14 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 15 | 16 | sort(mess) 17 | 18 | mess.foreach( println ) 19 | } 20 | 21 | def sort(a: Array[Int]) : Unit = { 22 | /** Recursively pushes element leftwards in a (partially) sorted array 23 | * by shifting the greater-than values to the right 24 | */ 25 | @annotation.tailrec 26 | def pushLeft(a: Array[Int], loc: Int, element: Int) : Int = { 27 | if (loc <= 0 || a(loc-1) < element){ 28 | return loc 29 | } 30 | else { 31 | // Move elements rightwards to make space on the left 32 | a(loc) = a(loc-1) 33 | pushLeft(a, loc-1, element) 34 | } 35 | } 36 | 37 | for (i <- 1 to a.length-1) { 38 | val x = a(i) 39 | a(pushLeft(a, i, x)) = x 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /sort/mergesort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Merge sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Recursively split the array in half, sort each subarray, and then merge 6 | * the sorted arrays into a single, sorted array, by traversing both arrays. 7 | * The base case occurs when the subarray is a single element (considered 8 | * sorted). 9 | **/ 10 | 11 | object MergeSort { 12 | def main(args: Array[String]) { 13 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 14 | 15 | val result = sort(mess, 0, mess.length-1) 16 | result.foreach( println ) 17 | } 18 | 19 | /** Recursively sorts a subarray via Merge Sort algorithm. 20 | * 21 | * @param a an unsorted array to be sorted 22 | * @param lo the index of the left-most edge of desired subarray 23 | * @param hi the index of the right-most edge of desired subarray 24 | * @return a sorted array containing all elements in the prescribed subarray 25 | */ 26 | def sort(a: Array[Int], lo: Int, hi: Int) : Array[Int] = { 27 | if (hi - lo < 1){ 28 | return a.slice(lo, hi+1) 29 | } 30 | val mid = (hi - lo)/2 + lo 31 | val left = sort(a, lo, mid) 32 | val right = sort(a, mid+1, hi) 33 | 34 | return merge(left, right) 35 | } 36 | 37 | /** Combines two sorted arrays into a single sorted array. 38 | * 39 | * @param a first sorted array 40 | * @param b second sorted array 41 | * @return a new sorted array containing all elements from a and b 42 | * */ 43 | def merge(a: Array[Int], b: Array[Int]): Array[Int] = { 44 | var result = Array.fill(a.length + b.length)(0) 45 | 46 | var i: Int = 0 47 | var j: Int = 0 48 | 49 | /** Note: this could also be done with recursion, 50 | * which would probably be more idiomatic of 51 | * functional programming. 52 | */ 53 | while (i < a.length || j < b.length){ 54 | if (i >= a.length){ 55 | result(i+j) = b(j) 56 | j+=1 57 | } 58 | else if (j >= b.length || a(i) <= b(j)) { 59 | result(i+j) = a(i) 60 | i+=1 61 | } 62 | else { 63 | result(i+j) = b(j) 64 | j+=1 65 | } 66 | } 67 | return result 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /sort/quicksort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Quicksort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Moving left to right, move all values less than the pivot value to the 6 | * left of a floating divide, where the divide always marks the point to 7 | * the left of which all values are less than the pivot. At the end, move 8 | * the pivot value to the divide location. Then recurse for the subarrays 9 | * on either side of the pivot. 10 | **/ 11 | 12 | object Quicksort { 13 | def main(args: Array[String]) { 14 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 15 | 16 | quicksort(mess, 0, mess.length-1); 17 | mess.foreach( println ) 18 | } 19 | 20 | /** Swaps two values in an array */ 21 | def swap(a: Array[Int], pos1: Int, pos2: Int): Unit = { 22 | val stash = a(pos1) 23 | a(pos1) = a(pos2) 24 | a(pos2) = stash 25 | } 26 | 27 | /** Performs recursive quicksort on an array 28 | * 29 | * There's an opportunity for limiting space complexity to 30 | * O(ln(n)) here if we recurse on the larger partition last 31 | * (tail recursion). 32 | * */ 33 | def quicksort(a: Array[Int], low: Int, hi: Int): Unit = { 34 | if (low < hi) { 35 | val p = partition(a, low, hi) 36 | quicksort(a, low, p-1) 37 | quicksort(a, p+1, hi) 38 | } 39 | } 40 | 41 | /** Partition an array around some pivot 42 | * 43 | * Chooses a pivot, moves all values less than 44 | * the pivot to its left, and moves all values 45 | * greater than the pivot to its right. 46 | * 47 | * To optimize: choose pivot corresponding to a median 48 | * value of some sample. This helps ensure the 49 | * partitioning results in similarly-sized sub-arrays, 50 | * and thus the optimal O(n*ln(n)) performance. 51 | * 52 | * @return index (location) of pivot in partitioned array 53 | */ 54 | def partition(subArray: Array[Int], low: Int, hi: Int): Int = { 55 | val pivot = hi; 56 | var i = low; 57 | for ( 58 | j <- low to hi 59 | if subArray(j) < subArray(pivot) 60 | ) {swap(subArray, i, j); i+=1} 61 | 62 | // Lastly, move pivot value to the dividing line at i 63 | swap(subArray, i, pivot); 64 | return i 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sort/radixsort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Radix sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Iterate over the digit places, from least significant to most. In each 6 | * iteration, perform a counting sort on the elements using base10 keys, 7 | * effectively sorting from LSD through MSD. 8 | **/ 9 | 10 | object RadixSort { 11 | def main(args: Array[String]) { 12 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 13 | 14 | val result = sort(mess, 2) 15 | 16 | result.foreach( println ) 17 | } 18 | 19 | // Base-10 counting sort 20 | def sort(a: Array[Int], max_digits: Int): Array[Int] = { 21 | 22 | /** Computes a key (base10) for an integer, given the significatn digit. 23 | * @param value the value for which to return a key 24 | * @param digit the (one-based, right-to-left) index of which digit to key 25 | */ 26 | def key(value: Int, digit: Int): Int = { 27 | return (value % (scala.math.pow(10, digit))).toInt / scala.math.pow(10, digit-1).toInt 28 | } 29 | 30 | // Each iteration, we move data from 'from' to 'to' during the sort 31 | var from = a 32 | var to = new Array[Int](a.length) 33 | 34 | for (digit <- 1 to max_digits) { 35 | val count = new Array[Int](10) 36 | // Count how many of each key we have 37 | from.foreach( (e: Int) => count(key(e, digit)) += 1 ) 38 | 39 | // Add preceding counts to compute offset for each key 40 | for (i <- 1 until 10) { 41 | count(i) += count(i-1) 42 | } 43 | 44 | // Assemble results using offset and sorted keys 45 | for (e <- from.reverseIterator) { 46 | count(key(e, digit)) -= 1 47 | to(count(key(e, digit))) = e 48 | } 49 | from = to 50 | to = new Array[Int](a.length) 51 | } 52 | return from 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sort/selectionsort.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements an example of Selection sort. 3 | * 4 | * In English, here's how the algorithm works: 5 | * Iterate left to right over the array, finding the smallest value. Swap 6 | * smallest value with leftmost unsorted value. Repeat on remaining unsorted 7 | * region of the array (shrinks towards the right). 8 | **/ 9 | 10 | object SelectionSort { 11 | def main(args: Array[String]) { 12 | var mess = Array(3, 9, 8, 13, 2, 5, 4); 13 | 14 | sort(mess) 15 | 16 | mess.foreach( println ) 17 | } 18 | 19 | /**Implements Selection sort algorithm.*/ 20 | def sort(a: Array[Int]): Unit = { 21 | val n = a.length 22 | for (i <- 0 until n) { 23 | var min = i 24 | for (j <- i+1 until n) { 25 | if (a(j) < a(min)) min = j 26 | } 27 | 28 | if (min != i) swap(a, min, i) 29 | } 30 | } 31 | 32 | /**Swaps two elements of an array.*/ 33 | def swap(a: Array[Int], i: Int, j: Int): Unit = { 34 | val staging = a(i) 35 | a(i) = a(j) 36 | a(j) = staging 37 | } 38 | 39 | } 40 | --------------------------------------------------------------------------------