Skip to content

Commit

Permalink
Refined to generic tournament tree by abstract min/inf
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxinyu95 committed Apr 18, 2023
1 parent 907991c commit cccabe6
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 26 deletions.
60 changes: 36 additions & 24 deletions sorting/select-sort/src/TournamentTr.hs
Original file line number Diff line number Diff line change
@@ -1,61 +1,73 @@
-- TournamentTr.hs
-- Copyright (C) 2013 Liu Xinyu (liuxinyu95@gmail.com)
--
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.

-- Tournament tree based selection sort
-- [1] Donald E. Knuth. ``The Art of Computer Programming, Volume 3: Sorting and Searching (2nd Edition)''.
-- [1] Donald E. Knuth. ``The Art of Computer Programming, Volume 3: Sorting and Searching (2nd Edition)''.
-- Addison-Wesley Professional; 2 edition (May 4, 1998) ISBN-10: 0201896850 ISBN-13: 978-0201896855

module TrounamentTr where

import Test.QuickCheck -- for verification purpose only
import Data.List(sort) -- for verification purpose only
import Test.QuickCheck -- for verification
import Data.List (sort, sortBy) -- for verification

-- Note: in order to derive from Ord for free, the order must be:
-- Note: in order to derive from Ord for free, the order must be:
-- negative infinity, regular, then positive infinity
data Infinite a = NegInf | Only a | Inf deriving (Eq, Show, Ord)

only (Only x) = x

data Tr a = Empty | Br (Tr a) a (Tr a) deriving Show
data Tr a = Empty | Br (Tr a) (Infinite a) (Tr a) deriving Show

key (Br _ k _ ) = k

wrap x = Br Empty (Only x) Empty

branch t1 t2 = Br t1 (min (key t1) (key t2)) t2
only (Only x) = x

minBy p a b = if p a b then a else b

branch p t1 t2 = Br t1 (minBy p (key t1) (key t2)) t2

fromList :: (Ord a) => [a] -> Tr (Infinite a)
fromList = build . (map wrap) where
-- fromList :: (Ord a) => (Infinite a -> Infinite a -> Bool) -> [a] -> Tr a
fromList p xs = build $ map wrap xs where
build [] = Empty
build [t] = t
build ts = build $ pair ts
pair (t1:t2:ts) = (branch t1 t2):pair ts
build ts = build $ pair ts
pair (t1:t2:ts) = (branch p t1 t2) : pair ts
pair ts = ts

pop (Br Empty _ Empty) = Br Empty Inf Empty
pop (Br l k r) | k == key l = let l' = pop l in Br l' (min (key l') (key r)) r
| k == key r = let r' = pop r in Br l (min (key l) (key r')) r'

pop p inf = delMin where
delMin (Br Empty _ Empty) = Br Empty inf Empty
delMin (Br l k r) | k == key l = let l' = delMin l in Br l' (minBy p (key l') (key r)) r
| k == key r = let r' = delMin r in Br l (minBy p (key l) (key r')) r'

top = only . key

tsort :: (Ord a) => [a] -> [a]
tsort = sort' . fromList where
-- tsortBy :: (Ord a) => (Infinite a -> Infinite a -> Bool) -> Infinite a -> [a] -> [a]
tsortBy p inf xs = sort' $ fromList p xs where
sort' Empty = []
sort' (Br _ Inf _) = []
sort' t = (top t) : (sort' $ pop t)
sort' t | inf == key t = []
| otherwise = (top t) : (sort' $ pop p inf t)

tsort = tsortBy (<=) Inf

prop_tsort :: [Int]->Bool
prop_tsort :: [Int] -> Bool
prop_tsort xs = (sort xs) == (tsort xs)

prop_tsort_des :: [Int] -> Bool
prop_tsort_des xs = (sortBy (flip compare) xs) == (tsortBy (>=) NegInf xs)

testAll = do
quickCheck prop_tsort
quickCheck prop_tsort_des
2 changes: 1 addition & 1 deletion sorting/select-sort/ssort-en.tex
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ \subsection{Performance}
min'\ as\ m\ [\ ] & = & (m, A) \\
min'\ as\ m\ (b:bs) & = & \begin{cases}
b < m: & min'\ (as \doubleplus [m])\ b\ bs \\
\text{否则}: & min'\ (as \doubleplus [b])\ m\ bs \\
\text{otherwise}: & min'\ (as \doubleplus [b])\ m\ bs \\
\end{cases}
\end{array}
\]
Expand Down
13 changes: 12 additions & 1 deletion sorting/select-sort/ssort-zh-cn.tex
Original file line number Diff line number Diff line change
Expand Up @@ -540,13 +540,24 @@ \subsection{锦标赛淘汰法}
\label{eq:tsort}
\ee

\begin{Exercise}
\begin{Exercise}\label{ex:tournament-tree-sort}
\Question{将递归的锦标赛排序实现为升序。}
\Question{锦标赛树排序可以处理相等元素么?它是稳定排序么?}
\Question{比较锦标赛树排序和二叉搜索树排序,它们的时间和空间效率如何。}
\Question{比较堆排序和锦标赛树排序,它们的时间和空间效率如何。}
\end{Exercise}

\begin{Answer}[ref = {ex:tournament-tree-sort}]
\Question{将递归的锦标赛排序实现为升序。

$max$$-\infty$替换为$min$$\infty$就可以实现升序排序。我们可以进一步把它们抽象成参数:
}
\Question{锦标赛树排序可以处理相等元素么?它是稳定排序么?}
\Question{比较锦标赛树排序和二叉搜索树排序,它们的时间和空间效率如何。}
\Question{比较堆排序和锦标赛树排序,它们的时间和空间效率如何。}
\end{Answer}


\subsection{改进为堆排序}

锦标赛树淘汰法将基于选择的排序算法时间复杂度提高到$O(n \lg n)$,达到了基于比较的排序算法上限\cite{TAOCP}。这里仍有改进的空间。排序完成后,锦标赛树的所有节点都变成了负无穷,这棵二叉树不再含有任何有用的信息,但却占据了空间。有没有办法在弹出后释放节点呢?如果待排序的元素有$n$个,锦标赛树实际上占用了$2n$个节点。其中有$n$个叶子和$n$个分支。有没有办法能节约一半空间呢?如果认为根节点的元素为负无穷,则树为空,并将$key$重命名为$top$,那么上一节最后给出的\cref{eq:tsort}就可以进一步转化为更通用的形式:
Expand Down

0 comments on commit cccabe6

Please sign in to comment.