Professional Documents
Culture Documents
Quick Sort Algorithm in Haskell
Quick Sort Algorithm in Haskell
Quick Sort Algorithm in Haskell
Pi19404
August 4, 2013
Contents
Contents
Quick Sort Algorithm using Haskell
0.1 Introduction . . . . . . . . . . . 0.2 Quick Sort . . . . . . . . . . . . 0.2.1 Partioning the List . . 0.2.2 Selecting Random Pivot 0.2.3 Implementation . . . . . References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3 3 3 6 8 8
2|8
3|8
Quick Sort Algorithm using Haskell Without loss of generality let us assume that first element of the list is choose as the pivot element. If any other element is chosen as pivot element,as initialization step replace the first element of the list with the pivot element and proceed with the present algorithm. To perform in place sorting we maintain 2 indexes i; j .The index i indicates the elements of the list that are below pivot element,from index i to j are elements above pivot element.The element above index j are elements that are yet to be analyzed. Initially the index i=-1 and j=-1 which is a trivial case.The index j is incremented Now compare the element at index i with index j .Let value of pivot element be represented as p.if p < a[j ] then we need to add a[i] .
5:
>
jj
in the above example 5 > 3,however since i and j point to same index location no swapping is performed.The i and j indexes are simply incremented by 1 and updated indexs are marked Now the pivot element is compared with 3,in this case 4 > 3 ,j is incremented by 1, and 3 is swapped with 5,ie a[i] is swapped with a[j + 1]. next the element 5 is compared with 7.5 < 7,the current index of i is kept the same while j is incremented.
5 : 3 7; 4; 10; 1; 100; 200; 2
jj
>
jj
next 5 is compared with 4.5 > 4 and i and j are 0 and 1 respectively. This elements 7 and 4 are swapped and i and j are incremented
5 : 3 7 4; 10; 1; 100; 200; 2
jj
>
jj
This process is repeated till j reaches the end of array,ie till no unobserved elements of array are remaining
5 : 3412; 710020010
These two sublists are recursively sorted and finally arrays are appended to get the result.
3 : 12; 47 :; 100; 200; 10
>
100 : 10200
However the above method is standard method described for partitioning used in quick sort algorithm.This method is useful if we are
4|8
Quick Sort Algorithm using Haskell required to perform in-place partitioning and it does not require additional memory storage. However functional language deals with immutable data type the list cannot be altered.in place operations are not allowed. We can perform transformation on the current list and return a new list. using above method of swapping and comparing proves to be more expensive. To partition a list of length N ,O(N ) comparisons are required. further each step swapping is performed which further requires N computations. and this step itself leads to O(N 2 ) computations. In which case above approach does not prove to be useful.A recursive method to partition the list is used. At each step the pivot element is compared to the head of the list and if true the element is appended to one list else it is appended to another list. Using a recursive method ,we simply perform a single comparison and single copy operations at each iteration loop.And partitioning is performed in O(N ) computations. These list are used as an accumulator.They are passed to input of the function and transformed list is expected at output of the function. The partitioning algorithm accepts the pivot element,the input list,and two accumulator sublists. The partitioning is performed recursively till all the elements of input list to be partitioned are exhausted. Let us consider a part_list1 algorithm. A stable sorting algorithm keeps the elements with same sorting key in order. They return the same output on the same input. In the present case if we have duplicate elements ,their order should be preserved. The part_list1 analyzes the list from head ,and new elements are appended to the tail of the list.Thus relative order of duplicate elements will always be reversed. This more over due to so simple way to add element to end of empty list. ie [] : 1 is not allowed while 1 : [] is allowed.Another solution would be to reverse the list.Thought it is again O(N ) additional computation. Also in program we must avoid computation of length of list which again takes O(N ) time. Using random pivot selection we can also get average case performance of O(N logN ).
5|8
-- using accumulator lists to partition a list for quick sort algorithm -- append elements less than pivot to as -- append elements greater than pivot to bs -- i is current index,to skip over pivot element -- l1 and l2 are length of array as and bs -- as are element less than or equal to pivot -- bs are elements greater than pivot part_list1 pivot pi [] as bs l1 l2 i= (as,bs,l1,l2,i) part_list1 pivot pi (y:ys) as bs l1 l2 i=case (i)==pi of flag|flag==True->part_list1 pivot pi ys as bs l1 l2 (i+1) |otherwise->f where f=case compare y pivot of LT->part_list1 pivot pi ys (y:as) bs (l1+1) l2 (i+1) EQ->part_list1 pivot pi ys (y:as) bs (l1+1) l2 (i+1) GT->part_list1 pivot pi ys as (y:bs) l1 (l2+1) (i+1)
In the above method while selecting the pivot element we need to know the length of the array.Rather than computing it every time.This is kept track of during the partitioning operation. Below is the method for basic quick sort algorithm
-- the main function to be called for -- partitioning the list for quick sort algorithm
6|8
:: Ord a =>[a]->Int->StdGen->([a]) [] l g =([]) (f) l g = case length(f)<=2 of condition if sublists are sorted f1|f1==True -> (a1 ++ pivot:b1) -- sort the sublist recursively and then append |otherwise-> (c1 ++ pivot:d1) where -- val1 is pivot,val 2 is list to be partitioned (a1,b1,l1,l2,i)=part_list1 pivot pi f [] [] 0 0 0 --- partitioning subroutine called in case of sublists --- else list is appended and returned (c1)=partition_list a1 l1 g' (d1)=partition_list b1 l2 g'' (pivotLoc,g')=next g (pivotLoc',g'')=next g' pi=pivotLoc `mod` l pivot=(f)!!pi
Typically concatinating lists are expensive operations.In case of functional language it should be avoided.As used in partitioning method a method which uses accumulator arrays would be more beneficial. Let us consider the case that we have two lists an unsorted list and accumulator list which contains the sorted portion. At each iteration we first partition unsorted list into A and B. Then recursively sort B,let S be sorted version of B and C be input accumulator and P is pivot element The sorted array at this step is P+S+C and will be the new accumulator. The sorting routine is modified to accept the accumulator as input and outputs S+C as the sorted array . At the lowest element of recursion we append the higher element of B with C At the next highest level we append the next highest element with (B+C) and so on. Thereby adding to input accumulator at each step to produce the output list.
-- the quick sort function with accumulator partition_list1 :: Ord a =>[a]->Int->StdGen->[a]->Int->([a]) partition_list1 [] l g acc la=acc partition_list1 [x] 1 g acc la=x:acc -- adding pivot to sorted to get complete sorted list -- calling quick sort on unsorted list as and input accumulator
7|8
-- as current sorted list partition_list1 f l g acc la= partition_list1 as l1 g' ([pivot] ++ sorted) (l2) --(sorted ++ [pivot] ++ as ++ [pivot] ++ bs ++ [pivot]) -where sorted=partition_list1 bs l2 g'' acc la -- partitioning the unsorted list (as,bs,l1,l2,i)=part_list1 pivot pi f [] [] 0 0 0 -- getting instance of random number generator (pivotLoc,g')=next g (pivotLoc',g'')=next g' -- index of pivot pi=pivotLoc `mod` l -- getting pivot element pivot=(f)!!pi
0.2.3 Implementation
Ill be implementing all the algorithms using haskel. Since recursion is basic mechanism to loop in Haskell ,it fits in naturally within recursive algorithmic structure of divide and conquer algorithms. The code can be found at https://github.com/pi19404/m19404/blob/ master/Algorithm/sort/sort.hs
8|8