Insertion sort implementation in scala

不打扰是莪最后的温柔 提交于 2019-12-07 10:28:01

问题


I'm trying out Scala and I want to see how one would implement insertion sort in scala with the following requirements:

  1. Nested for loops
  2. Array[Int] for input
  3. If possible a way to modify the contents of the function in a call by reference way otherwise return an Array[Int]

If this isn't the Scala way of implementing insertion sort can you still provide code for the above and explain what is wrong with the approach. edit: This is an attempt using a while loop (doest work) and no it isn't a homework question, why the hostility?

def insert_sort(a:Array[Int]):Array[Int]={
for(i <- 0 until a.length)
{
  var j=i+1

  while(j>1&&a(j)<a(j-1)&&j<a.length)
  {
      var c=a(j)
      a(j)=a(j-1)
      a(j-1)=c
      j-=1
  }
}
return a
}

回答1:


The implementation given in the wikipedia article fits your bill. Here it is, copied, pasted, and converted to Scala syntax:

def insertionSort(a: Array[Int]): Array[Int] = {
  for (i <- 1 until a.length) {
    // A[ i ] is added in the sorted sequence A[0, .. i-1]
    // save A[i] to make a hole at index iHole
    val item = a(i)
    var iHole = i
    // keep moving the hole to next smaller index until A[iHole - 1] is <= item
    while (iHole > 0 && a(iHole - 1) > item) {
      // move hole to next smaller index
      a(iHole) = a(iHole - 1)
      iHole = iHole - 1
    }
    // put item in the hole
    a(iHole) = item
  }
  a
}



回答2:


This is what I came up with, which seems to be functional, generic, tail-recursive (foldLeft is tail-recursive)...:

def insertionSort[A](la: List[A])(implicit ord: Ordering[A]): List[A] = {
  def insert(la: List[A], a: A) = {
    val (h, t) = la.span(ord.lt(_, a))
    h ::: (a :: t)
  }

  la.foldLeft(List[A]()) {(acc, a) => insert(acc, a)}
}



回答3:


My version of the insertion sort procedure is the following. It consists of two functions, isort and insert which have the following signatures:

  • isort(xs: List[int]) : List[int]: Takes an input list of integers and outputs a list of integers.
  • insert(x: Int, xs: List[int]) : List[int] Takes a sorted input list and an integer x and adds x to the right position in the list to maintain the invariant that the list is sorted. Example: insert(3, [1, 2]) = [1, 2, 3]

First let us code up the insert function.

  1. If the list is empty, return a list of the integer to be added.
  2. Otherwise, there are two possible cases. The head of the list is greater or equal to the given input integer, in which case we simply append the input integer to the beginning of the list and return it. The other case is when the input integer is greater than the head of the input list. In this case, we recursively insert the input integer into the tail of the list.

    def insert(x : Int, xs : List[Int]) : List[Int] = {
    
    xs match{
        case Nil => List(x)
        case y :: xs1 =>
            if(y >= x) x :: xs
            else y :: insert(x,  xs1)
     }
    
    }
    

The second function is isort, which takes an input list and sorts it. The algorithm is as follows:

  1. If the input list is equal to Nil, return Nil.
  2. Otherwise, recursively sort the tail of the list, and add the head at the right position in the (sorted) tail (using the insert procedure)

     def isort(xs : List[Int]) : List[Int] = {
      xs match{
        case Nil => Nil
        case x :: xs1 => insert(x, isort(xs1))
    
       }
    
     } 
    

We can test this as isort(List(1, 6, 4, -2, 5, 12)) and we get the correct expected output.




回答4:


The most elegant insertion sort algorithm implementation that I'we seen so far:

val rand = List(5,3,1,2)

def isort(xs: List[Int]): List[Int] =
  if (xs.isEmpty) Nil
  else insert(xs.head, isort(xs.tail))

def insert(x: Int, xs: List[Int]): List[Int] =
  if (xs.isEmpty || x <= xs.head) x :: xs
  else xs.head :: insert(x, xs.tail)

isort(rand) // Produces List(1,2,3,5)

Algorithm implementation is taken from this great book: https://www.artima.com/shop/programming_in_scala_3ed




回答5:


Nested for loops are probably not the answer in Scala, whatever is the problem. They make sense in languages where for loops stand for "repeat until condition, changing this each iteration", which is not what for loops or for comprehensions are in Scala (a for comprehension is a for loop which yields something for each iteration).

In Scala, for loops and for comprehensions are iterations over the elements of a collection (or weirder things for non-collection monads), but for insertion sort you want to find a position, either swapping places up to that position, or inserting the element at that position. Finding stuff should not be done with for loops or for comprehensions.

Also, there's no pass-by-reference in Scala. And, in fact, Array is not even a Scala collection, but a Java thingy which has unique characteristics granted to it by the JVM that are not reproducible with classes, so it can't be replaced.




回答6:


here's another generic version of insertion sort:

  def less[T <: Comparable[T]](i: T, j: T) = i.compareTo(j) < 0

  def swap[T](xs: Array[T], i: Int, j: Int) { val tmp = xs(i); xs(i) = xs(j); xs(j) = tmp }

  def insertSort[T <: Comparable[T]](xs: Array[T]) {
    for { i <- 1 to xs.size
          j <- List.range(1, i).reverse
          if less(xs(j),xs(j - 1)) } swap(xs, j, j -1)
  }



回答7:


What do you need it for?
If you just want a sorted Array I would prefer: def sortArray(a: Array[Int]): Array[Int] = a.sortWith(_ < _).




回答8:


At the beginning don't forget to add:

import scala.util.control.Breaks._

This is my solution, using a list as an input

def insertionSortLoop(list :List[Int]) : List[Int] = {
      val intArray: Array[Int] = list.toArray
      for ( j <- 1 until intArray.length ) {
          breakable {
            for ( i <- (1 to j).reverse ) {
              if (intArray(i-1) < intArray(i)) {
                break
              } else {
                  val temp = intArray(i)
                  intArray(i) = intArray(i-1)
                  intArray(i-1) = temp
              }
            }
        }
      }
      intArray.toList
    }

I have the implementation here at github.




回答9:


Here is a code sample written using foldLeft.

def insertionSort(input: List[Int]): List[Int] = {

  input.foldLeft(List[Int]())( (acc, element) => {

    val (firstHalf, secondHalf) = acc.span(_ < element)

    //inserting the element at the right place
    firstHalf ::: element :: secondHalf
  })
}

The example can be found in this github repo.




回答10:


Even though, when coding Scala, I'm used to prefer functional programming style (via combinators or recursion) over imperative style (via variables and iterations), THIS TIME, for this specific problem, old school imperative nested loops result in simpler code for the reader. I don't think falling back to imperative style is a mistake for certain classes of problems (such as sorting algorithms which usually mutate a buffer of items passed as input rather than resulting to a new sorted collection)

Here it is my solution:

package bitspoke.algo

import scala.math.Ordered
import scala.collection.mutable.Buffer

abstract class Sorter[T <% Ordered[T]] {

  // algorithm provided by subclasses
  def sort(buffer : Buffer[T]) : Unit

  // check if the buffer is sorted
  def sorted(buffer : Buffer[T]) = buffer.isEmpty || buffer.view.zip(buffer.tail).forall { t => t._2 > t._1 }

  // swap elements in buffer
  def swap(buffer : Buffer[T], i:Int, j:Int) {
    val temp = buffer(i)
    buffer(i) = buffer(j)
    buffer(j) = temp
  }
}

class InsertionSorter[T <% Ordered[T]] extends Sorter[T] {
  def sort(buffer : Buffer[T]) : Unit = {
    for {
      i <-  1 until buffer.length
      j <-  i until 0 by -1
      if (buffer(j) < buffer(j - 1))
    }
    swap(buffer, j, j - 1)
  }
}

As you can see, rather than using java.lang.Comparable, I preferred scala.math.Ordered and Scala View Bounds rather than Upper Bounds. That's certainly works thanks to many Scala Implicit Conversions of primitive types to Rich Wrappers.

You can write a client program as follows:

import bitspoke.algo._
import scala.collection.mutable._

val sorter = new InsertionSorter[Int]
val buffer = ArrayBuffer(3, 0, 4, 2, 1)
sorter.sort(buffer)

assert(sorter.sorted(buffer))



回答11:


Github link to Scala implementation

Pseudo Code:

Algorithm Insertion-Sort-Descending(A)
    for j <- 2 to length[A]
        key <- A[j]                 // element we wish to insert
        i <- j - 1                  // position to the left side
        while i > 0 and A[i] < key  // while has not found correct position <-- difference between Ascending and Descending
            A[i + i] = A[i]         // right shift element
            i = i - 1               // decrement i
        A[i + 1] = key              // found position, place key


来源:https://stackoverflow.com/questions/10406064/insertion-sort-implementation-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!