In this homework you will write write a set of functions to implement Queues using arrays, and you will will use the Queues to implement Radix sort.
What to do
To give you some idea of how array based queues work study the data declaration. A Queue as six components.
data ArrQueue a = ArrQueue Int -- index just to the left of the front element (if one exists) Int -- index of the last element (if one exists) Int -- low bound of the array Int -- high bound of the array Bool -- is the Queue full (Array a) -- the array that stores the elements
A Queue represetned as follows:
ArrQueue 1 3 0 3 False (listArray [undefined,undefined,5,6])
Might be visualized as:
front = 1 | [_,_,5,6] not full | rear = 3To see how a sequence of operations modify the queue study the illustration below that starts with an empty Queue and then enQueuies and deQueues a number of elements. The pictures illustrate the state of the Queue, and what elements are actually in the queue.
------- enQueue 4 ------- front = 0 | [_,4,_,_] not full | rear = 1 elements = [4] ------- deQueue ------- front = 1 | [_,_,_,_] not full | rear = 1 elements = [] ------- enQueue 5 ------- front = 1 | [_,_,5,_] not full | rear = 2 elements = [5] ------- enQueue 6 ------- front = 1 | [_,_,5,6] not full | rear = 3 elements = [5,6] ------- enQueue 7 ------- front = 1 | [7,_,5,6] not full | rear = 0 elements = [5,6,7] ------- enQueue 8 ------- front = 1 | [7,8,5,6] full | rear = 1 elements = [5,6,7,8]It is your job to fill in the template below to implement queues and radix sort. Be sure your tests of the queue demonstrate that you handle full and empty queues correctly.
-- Author : _________________ module RadixSortArrayStack where import ArrCommands data ArrQueue a = ArrQueue Int -- index just to the left of the front element (if one exists) Int -- index of the last element (if one exists) Int -- low bound of the array Int -- high bound of the array Bool -- is the Queue full (Array a) -- the array that stores the elements -- Next avaiblable slot to store an element after "i" in an -- array with low bound "lo" and high bound "hi" incr lo hi i = if i==hi then lo else i+1 -- Add element "a" to the Q. Raise an error if its full enQueue :: (Show a) => a -> ArrQueue a -> IO (ArrQueue a) enQueue a (ArrQueue front rear low hi full arr) | rear==front && full = error ("Queue full "++show a) | True = undefined -- Remove an element from the Queue, return a pair containing the -- removed element and the new Q. Raise an error if the Queue is empty deQueue :: ArrQueue t -> IO (t, ArrQueue t) deQueue (ArrQueue front rear low hi full arr) | undefined = error "Queue empty" | True = undefined -- Return a list of all the lements in the Queue. Does not change the Q qAll :: ArrQueue t -> IO [t] qAll (ArrQueue front rear low hi full arr) = undefined -- Create a new Queue with slots numbered from 0..n. Fill each -- slot with "init". Its good practice to use a strange "init" value -- (like -99) when writing the code, to help you discover errors. newQ :: Int -> a -> IO (ArrQueue a) newQ n init = undefined -- Reset a Queue to the empty state. resetQ :: ArrQueue t -> ArrQueue t resetQ (ArrQueue front rear low hi full arr) = ArrQueue low low low hi False arr ----------------------------------------------- -- testing testQ = do { q <- newQ 3 (-99) ; showQ q ; undefined } ------------------------------------------------ -- Displaying Q's -- I have written showQ to help you test your code. showQ :: (Show b) => ArrQueue b -> IO () showQ (ArrQueue front rear low hi full arr) = do { elems <- toListArr arr ; let xs = zipWith (showSlot front rear full) [0..] elems status True = " full\n" status False = " not full\n" ; let fpos = pos front xs rpos = pos rear xs str = tag fpos ("front = "++show front++ "\n") ++ tag fpos "|\n[" ++ plistf id xs ++ "]" ++ (status full) ++ tag rpos "|\n" ++ tag rpos ("rear = "++show rear++ "\n") ; putStrLn str } pos 0 xs = 1 pos n (x:xs) = length x +1 + pos (n-1) xs showSlot f r full n x | f==r = if full then show x else "_" | ff && n<=r = show x | f>r && (n<=r || n>f) = show x | True = "_" tag n s = replicate n ' '++s plistf f [x] = f x plistf f [] = "" plistf f (x:xs) = f x ++ "," ++ plistf f xs ------------------------------------------------------------ -- A radix sort for (key,satellite) -- where key is a 3 digit Int ----------------------------------------- -- Break a 3 digit Int into a list of Int -- digits 345 = [3,4,5] -- digits 976 = [9,7,6] digits:: Int -> [Int] digits 0 = [] digits n = digits (n `div` 10) ++ [n `mod` 10] ---------------------------------------------------- -- Using zero based indexing, get the bucket number -- from the key and digit position -- bucketFromKey 2 345 ---> 5 -- bucketFromKey 1 345 ---> 4 -- bucketFromKey 0 345 ---> 3 bucketFromKey :: Int -> Int -> Int bucketFromKey digitPosition key = undefined ------------------------------------------------------------- -- Make a pass for digit position "n". enQueue each element -- into the Queue in the correct location in the array using -- the key and the digit position. You will need to read the -- Queue from the array, enQueue the element into the Queue -- then write the new Queue back into the array. pass :: (Show t) => Int -> Array (ArrQueue (Int, t)) -> [(Int, t)] -> IO () pass n arr [] = return () pass n arr ((key,value):more) = do { let bucketNumber = bucketFromKey n key ; undefined } ---------------------------------------------------------- -- For each Queue in the array. Get a list of all the elements from that -- Queue and append them (from left to right) into one large -- list. Besure and reset the Queue, and write the reset Q back into the array. collectAndReset :: Show a => (Int, Int) -> Array (ArrQueue a) -> IO [a] collectAndReset (index,high) arr | index > high = return [] | True = undefined ------------------------------------------------------------- -- makes three passes. One for each digit position. Starts with the -- least significant digit (the ones digit, then the tens digit, -- then the hundreds digit). For each pass, distributes the list -- across the Queues in the array, then collects the elements from -- the Queues, then resets each Queue, and than makes the next pass. passes:: Show t => Int -> Array (ArrQueue (Int, t)) -> [(Int, t)] -> IO [(Int, t)] passes n arr elems | n < 0 = return elems passes n arr elems = undefined ---------------------------------------------------- -- Performs a radix sort for keys of three digits. Allocates -- an Array of Queues to use as buckets. I have made a list -- of Queues you can use to fill the array. Then makes three -- passes. The result of the last pass should be sorted. radixSort :: forall t. (Show t) => [(Int, t)] -> IO [(Int, t)] radixSort [] = return [] radixSort elems = do { qs <- mapM (\ x -> newQ 5 (head elems)) [0..9] ; undefined } -------------------------------------------------------------- testRadix = radixSort [(123,1),(345,2),(452,3),(945,4),(923,5),(641,6)]