From cb5defe3f4e7bf080905087785225574f546f2a2 Mon Sep 17 00:00:00 2001 From: Mitchell Rosen Date: Mon, 8 Jan 2024 18:46:55 -0500 Subject: [PATCH] slightly optimize deque smart construction --- src/Deque.hs | 23 +++++++++++++++-------- src/Deque/RealTime.hs | 30 +++++++++++++++++++----------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/Deque.hs b/src/Deque.hs index 9de68e7..08a7350 100644 --- a/src/Deque.hs +++ b/src/Deque.hs @@ -117,10 +117,17 @@ pattern Back xs x <- {-# COMPLETE Empty, Back #-} --- Deque smart constructor. -makeDeque :: [a] -> Int -> [a] -> Int -> Deque a -makeDeque xs xlen ys ylen - | xlen > (3 * ylen + 1) = Q (List.take xlen1 xs) xlen1 (ys ++ List.reverse (List.drop xlen1 xs)) ylen1 +-- Deque smart constructor, to use when it is possible the front list is too long. +makeDeque1 :: [a] -> Int -> [a] -> Int -> Deque a +makeDeque1 xs xlen ys ylen + | xlen > (3 * ylen + 1) = Q (List.take xlen1 xs) xlen1 (ys ++ List.reverse (List.drop xlen1 xs)) (xlen + ylen - xlen1) + | otherwise = Q xs xlen ys ylen + where + xlen1 = (xlen + ylen) `unsafeShiftR` 1 + +-- Deque smart constructor, to use when it is possible the back list is too long. +makeDeque2 :: [a] -> Int -> [a] -> Int -> Deque a +makeDeque2 xs xlen ys ylen | ylen > (3 * xlen + 1) = Q (xs ++ List.reverse (List.drop ylen1 ys)) xlen1 (List.take ylen1 ys) ylen1 | otherwise = Q xs xlen ys ylen where @@ -135,26 +142,26 @@ empty = -- | \(\mathcal{O}(1)^*\). Enqueue an element at the back of a double-ended queue. enqueue :: a -> Deque a -> Deque a enqueue y (Q xs xlen ys ylen) = - makeDeque xs xlen (y : ys) (ylen + 1) + makeDeque2 xs xlen (y : ys) (ylen + 1) -- | \(\mathcal{O}(1)^*\). Enqueue an element at the front of a double-ended queue. enqueueFront :: a -> Deque a -> Deque a enqueueFront x (Q xs xlen ys ylen) = - makeDeque (x : xs) (xlen + 1) ys ylen + makeDeque1 (x : xs) (xlen + 1) ys ylen -- | \(\mathcal{O}(1)\) front, \(\mathcal{O}(1)^*\) rest. Dequeue an element from the front of a double-ended queue. dequeue :: Deque a -> Maybe (a, Deque a) dequeue = \case Q [] _ [] _ -> Nothing Q [] _ (y : _) _ -> Just (y, empty) - Q (x : xs) xlen ys ylen -> Just (x, makeDeque xs (xlen - 1) ys ylen) + Q (x : xs) xlen ys ylen -> Just (x, makeDeque2 xs (xlen - 1) ys ylen) -- | \(\mathcal{O}(1)\) back, \(\mathcal{O}(1)^*\) rest. Dequeue an element from of the back of a double-ended queue. dequeueBack :: Deque a -> Maybe (Deque a, a) dequeueBack = \case Q [] _ [] _ -> Nothing Q (x : _) _ [] _ -> Just (empty, x) - Q xs xlen (y : ys) ylen -> Just (makeDeque xs xlen ys (ylen - 1), y) + Q xs xlen (y : ys) ylen -> Just (makeDeque1 xs xlen ys (ylen - 1), y) -- | \(\mathcal{O}(1)\). Is a double-ended queue empty? isEmpty :: Deque a -> Bool diff --git a/src/Deque/RealTime.hs b/src/Deque/RealTime.hs index a62ffe0..1346df0 100644 --- a/src/Deque/RealTime.hs +++ b/src/Deque/RealTime.hs @@ -129,13 +129,20 @@ pattern Back xs x <- {-# COMPLETE Empty, Back #-} --- Deque smart constructor. -makeDeque :: [a] -> Int -> [Any] -> [a] -> Int -> [Any] -> RealTimeDeque a -makeDeque xs xlen xc ys ylen yc +-- Deque smart constructor, to use when it is possible the front list is too long. +makeDeque1 :: [a] -> Int -> [Any] -> [a] -> Int -> [Any] -> RealTimeDeque a +makeDeque1 xs xlen xc ys ylen yc | xlen > (3 * ylen + 1) = let xs1 = List.take xlen1 xs ys1 = rotate1 xlen1 ys xs - in Q xs1 xlen1 (schedule xs1) ys1 ylen1 (schedule ys1) + in Q xs1 xlen1 (schedule xs1) ys1 (xlen + ylen - xlen1) (schedule ys1) + | otherwise = Q xs xlen xc ys ylen yc + where + xlen1 = (xlen + ylen) `unsafeShiftR` 1 + +-- Deque smart constructor, to use when it is possible the back list is too long. +makeDeque2 :: [a] -> Int -> [Any] -> [a] -> Int -> [Any] -> RealTimeDeque a +makeDeque2 xs xlen xc ys ylen yc | ylen > (3 * xlen + 1) = let xs1 = rotate1 ylen1 xs ys ys1 = List.take ylen1 ys @@ -147,11 +154,12 @@ makeDeque xs xlen xc ys ylen yc rotate1 :: Int -> [a] -> [a] -> [a] rotate1 i (x : xs) ys | i >= 3 = x : rotate1 (i - 3) xs (List.drop 3 ys) -rotate1 i xs ys = rotate2 xs (List.drop i ys) [] +rotate1 i xs ys = rotate2 (List.drop i ys) [] xs rotate2 :: [a] -> [a] -> [a] -> [a] -rotate2 [] ys zs = List.reverse ys ++ zs -rotate2 (x : xs) ys zs = x : rotate2 xs (List.drop 3 ys) (List.reverse (List.take 3 ys) ++ zs) +rotate2 ys zs = \case + [] -> List.reverse ys ++ zs + x : xs -> x : rotate2 (List.drop 3 ys) (List.reverse (List.take 3 ys) ++ zs) xs -- | An empty double-ended queue. empty :: RealTimeDeque a @@ -161,26 +169,26 @@ empty = -- | \(\mathcal{O}(1)\). Enqueue an element at the back of a double-ended queue. enqueue :: a -> RealTimeDeque a -> RealTimeDeque a enqueue y (Q xs xlen xc ys ylen yc) = - makeDeque xs xlen (execute1 xc) (y : ys) (ylen + 1) (execute1 yc) + makeDeque2 xs xlen (execute1 xc) (y : ys) (ylen + 1) (execute1 yc) -- | \(\mathcal{O}(1)\). Enqueue an element at the front of a double-ended queue. enqueueFront :: a -> RealTimeDeque a -> RealTimeDeque a enqueueFront x (Q xs xlen xc ys ylen yc) = - makeDeque (x : xs) (xlen + 1) (execute1 xc) ys ylen (execute1 yc) + makeDeque1 (x : xs) (xlen + 1) (execute1 xc) ys ylen (execute1 yc) -- | \(\mathcal{O}(1)\) front, \(\mathcal{O}(1)\) rest. Dequeue an element from the front of a double-ended queue. dequeue :: RealTimeDeque a -> Maybe (a, RealTimeDeque a) dequeue = \case Q [] _ _ [] _ _ -> Nothing Q [] _ _ (y : _) _ _ -> Just (y, empty) - Q (x : xs) xlen xc ys ylen yc -> Just (x, makeDeque xs (xlen - 1) (execute2 xc) ys ylen (execute2 yc)) + Q (x : xs) xlen xc ys ylen yc -> Just (x, makeDeque2 xs (xlen - 1) (execute2 xc) ys ylen (execute2 yc)) -- | \(\mathcal{O}(1)\) back, \(\mathcal{O}(1)\) rest. Dequeue an element from of the back of a double-ended queue. dequeueBack :: RealTimeDeque a -> Maybe (RealTimeDeque a, a) dequeueBack = \case Q [] _ _ [] _ _ -> Nothing Q (x : _) _ _ [] _ _ -> Just (empty, x) - Q xs xlen xc (y : ys) ylen yc -> Just (makeDeque xs xlen (execute2 xc) ys (ylen - 1) (execute2 yc), y) + Q xs xlen xc (y : ys) ylen yc -> Just (makeDeque1 xs xlen (execute2 xc) ys (ylen - 1) (execute2 yc), y) -- | \(\mathcal{O}(1)\). Is a double-ended queue empty? isEmpty :: RealTimeDeque a -> Bool