Created
May 31, 2014 21:47
-
-
Save jgosmann/973d70ecb87ba9ba8540 to your computer and use it in GitHub Desktop.
This file provides a Haskell module with a data type for binary trees and functions to manipulate them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- File: Tree.hs | |
| -- Date: 11-Nov-2008 | |
| -- Version: 1.0 | |
| -- | |
| -- Copyright (C) 2008 Julia Koslowski, Jan Gosmann <[email protected]> | |
| -- | |
| -- See: http://www.hyper-world.de | |
| -- | |
| -- Description: This file provides a Haskell module with a data type for binary | |
| -- trees and functions to manipulate them. | |
| module Tree where | |
| import Data.List | |
| -- Data type which represents binary trees. | |
| -- Possible constructors: | |
| -- - EmptyNode: Empty node as the name suggests. | |
| -- - Node: Normal node in the tree with a value a. | |
| -- - Left branch of the tree. | |
| -- - Value of the node. | |
| -- - Right branch of the tree. | |
| data Tree a = EmptyNode | | |
| Node (Tree a) a (Tree a) | |
| deriving (Eq) | |
| -- Use the showTree function to show the tree. | |
| -- See also: printTree, printTreeV, showTree, showTreeV | |
| instance Show a => Show (Tree a) where | |
| show t = showTree t | |
| -------------------------------------------------------------------------------- | |
| -- Functions to build a tree from a given list of elements. | |
| -------------------------------------------------------------------------------- | |
| -- Builds a new search tree from the given list and returns it. All left | |
| -- subnodes of a node will have a smaller value than this node and all right | |
| -- subnodes a greater value. | |
| -- ATTENTION: The result of this function is unclear if a value occurs more | |
| -- often than once in the list. | |
| -- Arguments: | |
| -- - List of values used to build the search tree. | |
| -- See also: newBalancedTree | |
| newSearchTree :: Ord a => [a] -> Tree a | |
| newSearchTree elements = newBalancedTree (sort elements) | |
| -- Builds a balanced tree, meaning that this function tries to give every branch | |
| -- of the tree the same number of subnodes. The resulting tree is returned. | |
| -- Arguments: | |
| -- - List with the values to build the tree from. | |
| -- See also: newSearchTree | |
| newBalancedTree :: [a] -> Tree a | |
| newBalancedTree [] = EmptyNode | |
| newBalancedTree elements = | |
| Node (newBalancedTree left) value (newBalancedTree right) | |
| -- We use the first element of the right list as node value, because if one | |
| -- part of the splitted list is shorter than the other it will be the left. | |
| where (left, (value:right)) = splitAt (div (length elements) 2) elements | |
| -------------------------------------------------------------------------------- | |
| -- Functions to retreive nodes from trees. | |
| -------------------------------------------------------------------------------- | |
| -- Searches for an element in a search tree and returns the correspondig node. | |
| -- If it is not found EmptyNode will be returned. | |
| -- Arguments: | |
| -- - Search tree to search in. | |
| -- - Element to find. | |
| -- ATTENTION: This function can only be used with search trees! You may use the | |
| -- newSearchTree function to build these. | |
| -- See also: getNode | |
| findInTree :: Ord a => Tree a -> a -> Tree a | |
| findInTree EmptyNode _ = EmptyNode | |
| findInTree (Node l value r) item | |
| | item == value = (Node l value r) | |
| | item < value = findInTree l item | |
| | item > value = findInTree r item | |
| -- Returns a node from a tree. You describe the node to return with a string | |
| -- consisting only of the letters 'l' and 'r', whereby 'l' means to go to the | |
| -- left branch of the current node and 'r' stands for the right branch. Left | |
| -- to right in the string is top to bottom in the tree. | |
| -- If passed path does not exist it will be returned EmptyNode. | |
| -- Arguments: | |
| -- - Tree to search in. | |
| -- - String describing the path to take (see description above). | |
| -- See also: findInTree | |
| getNode :: Tree a -> String -> Tree a | |
| getNode EmptyNode _ = EmptyNode | |
| getNode node "" = node | |
| getNode (Node l _ r) (p:path) | |
| | p == 'l' = getNode l path | |
| | p == 'r' = getNode r path | |
| | otherwise = error ("getNode: Path must only contain 'l' and 'r', found: '" | |
| ++ (p : "'")) | |
| -------------------------------------------------------------------------------- | |
| -- Some functions for retaining some information about a tree. | |
| -------------------------------------------------------------------------------- | |
| -- Returns the height of a tree (without EmptyNodes). | |
| -- Arguments: | |
| -- - Tree to get the height of. | |
| -- See also: countNodes | |
| treeHeight :: Tree a -> Int | |
| treeHeight EmptyNode = 0 | |
| treeHeight (Node l _ r) = max (treeHeight l) (treeHeight r) + 1 | |
| -- Returns the number of nodes in a given tree (without EmptyNodes). | |
| -- Arguments: | |
| -- - Tree to return the number of nodes of. | |
| -- See also: treeHeight | |
| countNodes :: Tree a -> Int | |
| countNodes EmptyNode = 0 | |
| countNodes (Node l _ r) = 1 + countNodes l + countNodes r | |
| -------------------------------------------------------------------------------- | |
| -- The following part contains functions to show a tree in a nice format. | |
| -------------------------------------------------------------------------------- | |
| -- The following functions do not need to check whether n < 0. This is done by | |
| -- kindly be the replicate function. | |
| -- Returns a string consisting of n spaces. | |
| -- Arguments: | |
| -- - Lenqth of the string = number of spaces. | |
| nspace :: Int -> String | |
| nspace n = replicate n ' ' | |
| -- Returns a string consisting of n underscores. | |
| -- Arguments: | |
| -- - Length of the string = number of underscores. | |
| nunderscore :: Int -> String | |
| nunderscore n = replicate n '_' | |
| -- Returns a string consisting of spaces. The length of the string is determined | |
| -- by how much space would be needed to show a. | |
| -- Arguments: | |
| -- - Something showable which is used to determine the length of the string. | |
| space :: Show a => a -> String | |
| space a = replicate (length (show a)) ' ' | |
| -- Adds the element fill the number of times to list needed to fill list up to | |
| -- the length n and returns this list. | |
| -- Arg | |
| fillList :: Int -> a -> [a] -> [a] | |
| fillList n fill list = list ++ (replicate (n - (length list)) fill) | |
| -- Fills all lists in lists with the Element fill until all lists in lists have | |
| -- the length of the longest list in lists. | |
| makeSameLength :: [[a]] -> a -> [[a]] | |
| makeSameLength lists fill = map (fillList (maximum (map length lists)) fill) | |
| lists | |
| -- This function generates a triple containing a string as third element which | |
| -- represents the passed tree as ASCII graphic. The first and second value are | |
| -- used only for internal calculation in the function. | |
| -- Arguments: | |
| -- - Tree to display. | |
| -- Returns: A triple with the following elements: | |
| -- - An index marking the center of the returned string (rounded down). | |
| -- - The number of character from the center to the end of the string | |
| -- (rounded up). | |
| -- - String representing the passed tree as ASCII graphic. | |
| -- See also: showTreeV | |
| genShowTree :: Show a => Tree a -> (Int, Int, String) | |
| genShowTree EmptyNode = (0, 1, ".") | |
| genShowTree (Node l value r) = | |
| ( center, fill, | |
| -- We use unlines to put all the lines together, but we don't want the last | |
| -- newline added by unlines. Therefore we have to delete it with init. | |
| init (unlines ( [ | |
| -- Generate a line containing the value of the current node and paths | |
| -- to both subnodes. | |
| nspace (center_l + 1) ++ nunderscore (fill_l - 1) ++ show value | |
| ++ nunderscore center_r, | |
| -- Generate a line with the path ends. | |
| nspace center_l ++ "/" ++ nspace (fill_l - 1) ++ space value | |
| ++ nspace center_r ++ "\\" ] | |
| -- Add the lines for the subtrees. To get the formatting right spaces have | |
| -- to be added to every line of the left subtree graphic, then the left | |
| -- and right lines are paired. | |
| ++ (zipWith (++) (zipWith (++) | |
| (l_lines) (replicate (length l_lines) (space value)) ) (r_lines) ) ) | |
| )) | |
| where | |
| -- Generate the output for the subtrees. | |
| (center_l, fill_l, left) = genShowTree l | |
| (center_r, fill_r, right) = genShowTree r | |
| -- We have to make sure that the number of lines for both subtrees is the | |
| -- same. Otherwise we would lose lines by the zipWidth function used above. | |
| lr_lines = makeSameLength [lines left, lines right] "" | |
| -- Moreover all lines of the left subtree have to be of the same length to | |
| -- get the formatting right. | |
| l_lines = makeSameLength (head lr_lines) ' ' | |
| r_lines = last lr_lines | |
| -- ... and finally calculate the new center and fill value. | |
| center = (center_l + fill_l + div (length (show value) ) 2) | |
| fill = (center_r + fill_r + div (length (show value) + 1) 2) | |
| -- Returns a string containing a horizontally oriented ASCII graphic of the | |
| -- given tree. | |
| -- Arguments: | |
| -- - Tree to output. | |
| -- See also: printTree, showTreeV, printTreeV | |
| showTree :: Show a => Tree a -> String | |
| showTree t = (\(a, b, c) -> c) (genShowTree t) | |
| -- Prints the tree as horizontally oriented ASCII graphic. | |
| -- Arguments: | |
| -- - The tree to print | |
| -- See also: showTree, showTreeV, printTreeV | |
| printTree :: Show a => Tree a -> IO() | |
| printTree t = putStr (showTree t) | |
| -------------------------------------------------------------------------------- | |
| -- The following part contains a function to display a tree vertically instead | |
| -- of horizontal. | |
| -------------------------------------------------------------------------------- | |
| -- Prints the tree as vertically oriented ASCII graphic. | |
| -- Arguments: | |
| -- - The tree to print. | |
| -- See also: showTreeV, showTree, printTree | |
| printTreeV :: Show a => Tree a -> IO() | |
| printTreeV t = putStr (showTreeV t) | |
| -- Returns a string containing a vertically oriented ASCII graphic of the given | |
| -- tree. | |
| -- Arguments: | |
| -- - Tree to output. | |
| -- See also: printTreeV, showTree, printTree | |
| showTreeV :: Show a => Tree a -> String | |
| showTreeV = init . unlines . (\(a, b, c) -> c) . picture | |
| -- This function is similar to genShowTree. Differens: It shows the tree | |
| -- vertically. | |
| -- Arguments: | |
| -- -Tree to display | |
| picture EmptyNode = (1, 1, ["** "]) -- end Nodes of the Tree("Leafs") | |
| picture (Node EmptyNode x EmptyNode) = (1,1,["** "++show x]) | |
| picture (Node l x r) = (hl+hr+1, hl+1, top pl ++ middle ++ bottom pr) --Node needs a | |
| -- value x and the left & right side of the Tree | |
| where (hl,bl,pl) = picture l | |
| (hr,br,pr) = picture r | |
| top = zipWith (++) (replicate (bl-1) " " ++ | |
| [" ,-"] ++ | |
| replicate (hl-bl) " | ") -- Add the lines (the way) to a new Node | |
| -- at the left or right | |
| middle = [show x] -- show value (x) in the middle | |
| bottom = zipWith (++) (replicate (br-1) " | " ++ | |
| [" `-"] ++ -- Displays a kind of edge before a new Node starts. | |
| replicate (hr-br) " ") | |
| -------------------------------------------------------------------------------- | |
| -- NOTE: Only temporary stuff for testing purposes is following. Everything | |
| -- below this mark should be removed before a release. | |
| -------------------------------------------------------------------------------- | |
| -- E.g. Trees to test the functions showTree, showTreeV, printTree, printTreeV: | |
| tree1 = Node (Node EmptyNode 4 (Node EmptyNode 5 EmptyNode)) 7 | |
| (Node (Node (Node EmptyNode 8 EmptyNode) 9 EmptyNode) | |
| 11 (Node EmptyNode 12 EmptyNode)) | |
| tree2 = Node (Node EmptyNode 1 (Node EmptyNode 2 EmptyNode)) 3 | |
| (Node (Node (Node EmptyNode 7 EmptyNode) 7 EmptyNode) | |
| 1 (Node EmptyNode 0 EmptyNode)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment