Sie sind auf Seite 1von 6

Sorts Explained with Scala

Anybody who has attended interviews will agree that the most important skill that we possess is to know algorithms and
solve various real world problems using them. And whenever someone asks you whether you are comfortable with
algorithms, they start with the sorts and then proceed towards trees,graphs and other more complicated data structures.
So its imperative that we at least know how these sorts work
1. Insertion Sort
2. Quick Sort
3. Merge Sort
So in this post my intention is just to give the algorithm for each of these sorts, and then write working code for the same
using scala. When we are finished with this post, i am sure you would also appreciate how intuitive coding in scala is.
Lets get started

Insertion sort
The idea behind insertion sort is to have 2 regions 1. A sorted region 2. An unsorted region and then insertion sort is all
about taking each element in the unsorted region and putting that at the correct place of the sorted region.
So how does this work.
1. We assume that for the N element list the Nth element is sorted.
2. The elements from N-1 to 1 constitute the unsorted region.
3. We take each element from N-1 to 1 and insert that element into its proper place in the already sorted list.
And thats it we are done. Wish it was same way with coding this. I assure you its as easy as the above steps. Lets see
what the code for the same is

/**
sl means sortedlist
hsl means head of sorted list
tsl means tail of sorted list
**/
def insertionSort(list: List[Int]) : List[Int] = {
def insert(element : Int, sl: List[Int]) : List[Int] = {
sl match {
case List() => List(element)
case hsl::tsl => if (element < hsl) element :: sl else hsl:: insert(element, tsl)
}
}
list match {

case List()
=> List()
case head::tail => insert(head, insertionSort(tail))

}
}
println(insertionSort(List(2,1,5,3,4)))

And thats it. There is no for loops or break conditions. People who are comfortable coding in pseudo code would have
already understood the program. If not lets just go through the same
1. The function insertionSort takes a list of integers and returns a list of integers which is sorted
2. Inside insertionSort we have defined a function insert,to which we will come later
3. Next we use the pattern matching capability of scala We match the list in our hand and check for 2 cases
a) If its an emply list we return the same
b) If there is a head element followed by tail of the list we insert head into a list which is already sorted using, yes you
guessed it the insertion sort
4. And what does insert do.To it we have passed an element and a sorted list. We need to insert the element into its
proper place in sorted list. It again uses pattern matching. We check 2 cases
a) If the sorted list is an empty list we return a list with only the element (List with only one element is sorted)
b) If there is a head element followed by tail of the list, we check if the element is lesser that the head element. If lesser
we return a list with element appended to the sorted list. Else we proceed to insert the element into its proper place
in the tail of the list using, yes you guessed it the insert function
We print the sorted list and we get List(1,2,3,4,5)
To understand the pattern matching better a list List(2,3,4) is 2 appended to List(3,4). So here head is 2 tail is list (3,4).
So if we proceed like this we can represent
List(2,3,4) => 2 :: List(3,4) => 2 :: 3 :: List(4) => 2 :: 3 :: 4 :: List()
Lets just see one example of sort in action
insertionSort(List(2,1,3,5,4)) => insert(2, insertionSort(List(1,3,5,4))) =>insert(2, insert(1,insertionSort(List(3,5,4)))) =>
insert(2,insert(1, insert(3,insertionSort(List(5,4))))) => insert(2,insert(1, insert(3,insert(5, insertionSort(List(4)))))) =>
insert(2,insert(1, insert(3,insert(5, insert(4,insertionSort(List())))) =>insert(2,insert(1, insert(3,insert(5, insert(4,List())))))
=> insert(2,insert(1, insert(3,insert(5, List(4))))) => insert(2,insert(1, insert(3,4 :: insert(5, List())))) => insert(2,insert(1,
insert(3,4::List(5)))) => insert(2,insert(1, 3::4::List(5)))
and so on till we get List(1,2,3,4,5)

Quick Sort
The algorithm for quick sort is
1. If the size of list is less that 2 return the list its already sorted
2. Else take a pivot element. We can take any element. But lets take the element(list.length/2) as the pivot element.
3. We filter all elements that are smaller that pivot and put it to its left
4. Then comes pivot element
5. We filter all elements that are bigger that pivot and put it to its right
6. Sort left and right using quicksort
Again wishing it would have been as easy as the algorithm lets get to the code

def quickSort(list: List[Int]): List[Int] = {


if (list.length <2) list
else {
val pivot = list(list.length/2)
quickSort(list.filter(element=> element < pivot)) ++
list.filter(element=> element == pivot) ++
quickSort(list.filter(element => element > pivot))
}
}
println(quickSort(List(2,1,5,3,4)))
Lets go through the code
1. If list size is less than 2 its sorted, just return it
2. Else pivot is the element at list.length/2
3. We filter all elements less than pivot to its left
4. We filter all the elements equal to pivot (It should just have been pivot but the pivot elements could occur multiple
times)
5. We filter all elements greater than pivot to its right
6. Sort 3 and 5 using quicksort
7. Return all these 3 appended (++ does that)

MergeSort
The merge sort algorithm says
1. Divide the list into left and right
2. Sort left and right using merge sort
3. Merge the two sorted arrays to give one single sorted array.

/**
sl1issortedList1

sl2issortedList2
headsl1isheadofsortedList1
tailsl1istailofsortedList1
headsl2isheadofsortedList2
tailsl2istailofsortedList2
**/
defmergeSort(list:List[Int]):List[Int]={
defmerge(sl1:List[Int],sl2:List[Int]):List[Int]={
(sl1,sl2)match{
case(sl1,Nil)=>sl1
case(Nil,sl2)=>sl2
case(headsl1::tailsl1,headsl2::tailsl2)=>
if(headsl1<headsl2)headsl1::merge(tailsl1,sl2)
elseheadsl2::merge(sl1,tailsl2)
}
}
if(list.length<2)list
else{
val(fst,sec)=list.splitAt(list.length/2)
merge(mergeSort(fst),mergeSort(sec))
}
}

println(mergeSort(List(2,1,3,5,4)))
Now as we go through the code it does
1. If list length is less that 2 return it
2. else split at length/2
3. MergeSort first list
4. MegeSort second list
5. Merge these using merge function.
It works as given below. We take the case of 2 sorted lists List(2,3,7) and List(1,5,6) and see how it works
merge(List(2,3,7),List(1,5,6)) = 1 :: merge(List(2,3,7), List(5,6)) => 1 :: 2 :: merge(List(3,7),List(5,6) => 1 :: 2 :: 3
merge(List(7), List(5,6)) => 1 : 2 :: 3 :: 5 :: merge(List(7), List(6)) => 1 : 2 :: 3 :: 5 :: 6 merge(List(7), Nil) => 1 :: 2 :: 3 :: 5::
6 :: List(7) => List(1,2,3,5,6,7)
Now that we have seen all the 3 algorithms one thing that we could see is
1. When we write in scala the code is written just like what our psuedo code would look like
2. It provides all the constructs which help us to work with numbers just the way we do that in our mind.
3. No looping, breaking makes sure we just concentrate on the algorithms and not the edge conditions that may creep
up
Before we wind up lets make these algorithms generic. Just sorting numbers is not fun. These algorithms should be able
to sort any objects right. So it should be parametrised by object T. And what extra would we need. We need a function
which given two objects of type T says which one is smaller. We can use this function to compare 2 objects and put
them in their right place in the list. Lets see how we could rewrite insertion sort to make it generic

/**
sl means sortedlist
hsl means head of sorted list
tsl means tail of sorted list
**/
def insertionSort[T](list: List[T], lt: (T, T) => Boolean) : List[T] = {
def insert(element : T, sl: List[T]) : List[T] = {
sl match {
case List() => List(element)
case hsl::tsl => if (lt(element,hsl)) element :: sl else hsl:: insert(element, tsl)
}
}
list match {

case List()
=> List()
case head::tail => insert(head, insertionSort(tail,lt))

}
}
insertionSort(List(2,1,3,5,4), ((a:Int,b:Int) => a < b))

What we have done is to parametrise the function with type T. Now we can see it also takes lt : (T,T) => Boolean. It
means it takes a function which takes 2 parameters of type T and returns a boolean. Means it takes 2 objects of type T
and returns true if first object is less that second object.
And thats it now,we can sort on any objects. All we need to pass is the function which can compare 2 objects of the
same type.
Happy sorting and welcome to world of functional programming :

Das könnte Ihnen auch gefallen