我創建了一個小的二叉樹「庫」,但tDelete在某些情況下運行不正常。我在簡單的樹上測試了它,它工作正常,但在這種特殊情況下,它會導致將重複節點添加到樹中。 這似乎是因爲對tDelete的遞歸調用找不到fMin值。它必須是可以找到的,或者它只是返回原始樹,而不是刪除原始目標值,但不是它的替代原始值。我的二叉樹的刪除功能偶爾會導致重複的條目
主要的程序概述了這個問題。最後打印的目標樹被刪除(992),並且被找到的最小值(993)連續替換,但是在遞歸調用中從未找到/刪除原始最小值(993)(導致兩個993條目)。 我已經通過它,我看不到問題。如果fMin發現993作爲替換,爲什麼第二次調用tDelete找不到(並刪除它)?
我原本以爲這是我的平衡算法搞亂排序,但謝天謝地,我不認爲這是可能的。如果是這樣的話,993從來就不會被發現(而且tMin至少會發現它一次)。 任何有識之士將不勝感激。我正準備嘗試將其製作成Map,但我需要首先解決所有問題。
data Tree a = ETree | Node { leftTreeOf :: Tree a, rightTreeOf :: Tree a, tLoad :: a }
instance Show s => Show (Tree s) where
show = showTree 0
showTree :: Show s => Int -> Tree s -> String
showTree depth t = "\n" ++ replicate (depth * 2) '-' ++ case t of
ETree -> "()"
(Node lT rT a) -> "(" ++ show a ++ ")" ++ showTree nD lT ++ showTree nD rT
where nD = depth + 1
tInsert :: Ord o => o -> Tree o -> Tree o
tInsert x ETree = Node ETree ETree x
tInsert x (Node lT rT a)
| x < a = Node (tInsert x lT) rT a
| x > a = Node lT (tInsert x rT) a
| otherwise = Node lT rT x
-- Replaces the L/R tree with nT
replaceL, replaceR :: Ord o => Tree o -> Tree o -> Tree o
replaceL _ ETree = ETree
replaceL nT (Node _ rT a) = Node nT rT a
replaceR _ ETree = ETree
replaceR nT (Node lT _ a) = Node lT nT a
-- Folds a list into a tree
tFromListL, tFromListR :: Ord o => [o] -> Tree o
tFromListL = foldl (flip tInsert) ETree
tFromListR = foldr tInsert ETree
leftRotation, rightRotation :: Ord o => Tree o -> Tree o
rightRotation ETree = ETree
rightRotation [email protected](Node lT _ _) = let replaced = replaceL (rightTreeOf lT) t in
replaceR replaced lT
leftRotation ETree = ETree
leftRotation [email protected](Node _ rT _) = let replaced = replaceR (leftTreeOf rT) t in
replaceL replaced rT
-- Turns a tree into a list
tToList :: Ord o => Tree o -> [o]
tToList ETree = []
tToList (Node lT rT a) = (tToList lT) ++ [a] ++ (tToList rT)
-- Splits a list roughly in half (as part of balancing)
splitInHalf :: [a] -> ([a],[a])
splitInHalf xs = splitAt (round $ (fromIntegral $ length xs)/2.0) xs
-- Returns how unbalanced a node is
tUnbalancedBy :: Tree a -> Int
tUnbalancedBy ETree = 0
tUnbalancedBy (Node lT rT _) = absDiff (tDepth lT) (tDepth rT)
-- Arranges a list in such a way that it forms a more balanced tree
balanceList :: [a] -> [a]
balanceList xs = let (fH,sH) = splitInHalf xs in (reverse fH) ++ sH
-- "Inefficient balance"
tIneffBalance :: Ord o => Tree o -> Tree o
tIneffBalance = tFromListL . balanceList . tToList
-- Finds the min/max values of a tree
tMin, tMax :: Ord o => Tree o -> o
tMin ETree = error "tMin called on an Empty Tree"
tMin (Node lT _ a) = case lT of
ETree -> a
(Node lT' _ _) -> tMin lT'
tMax ETree = error "tMax called on an Empty Tree"
tMax (Node _ rT a) = case rT of
ETree -> a
(Node _ rT' _) -> tMax rT'
-- Find the max depth of a tree
tDepth :: Tree a -> Int
tDepth ETree = 0
tDepth (Node lT rT _) = 1 + max (tDepth lT) (tDepth rT)
-- Finds how many nodes a tree contains
tSize :: Tree a -> Int
tSize ETree = 0
tSize (Node lT rT _) = 1 + (tSize lT) + (tSize rT)
absDiff :: Int -> Int -> Int
absDiff x y = abs $ x - y
exceeds :: (Num n, Ord n) => n -> n -> Bool
exceeds x y = let t = 1 in x >= (y - t)
isInRangeOf :: (Num n, Ord n) => n -> n -> Bool
isInRangeOf x y = let t = 1 in
x >= (y - t) && x <= (y + t)
-- Checks if a node is balanced
tIsBalanced :: Tree a -> Bool
tIsBalanced ETree = True
tIsBalanced [email protected](Node lT rT _) =
tUnbalancedBy n <= 1 && tIsBalanced lT && tIsBalanced rT
tBalance :: Ord o => Tree o -> Tree o
tBalance ETree = ETree
tBalance [email protected](Node lT rT a)
| lD `isInRangeOf` rD = Node (tBalance lT) (tBalance rT) a
| lD `exceeds` rD = balanceRest $ rightRotation n
| otherwise = balanceRest $ leftRotation n
where
(lD,rD) = (tDepth lT,tDepth rT)
balanceRest t = replaceR (tBalance $ rightTreeOf t) $
replaceL (tBalance $ leftTreeOf t) t
tBalanceNX :: Ord o => Int -> Tree o -> Tree o
tBalanceNX _ ETree = ETree
tBalanceNX n t = foldl (\a _-> tBalance a) t [1..n]
-- Checks if a value is an element of the tree
tElem :: Ord o => o -> Tree o -> Bool
tElem x ETree = False
tElem x (Node lT rT a)
| x < a = tElem x lT
| x > a = tElem x rT
| otherwise = True
getSubTree :: Ord o => o -> Tree o -> Tree o
getSubTree _ ETree = ETree
getSubTree e [email protected](Node lT rT a)
| e < a = getSubTree e lT
| e > a = getSubTree e rT
| otherwise = t
tDelete :: Ord o => o -> Tree o -> Tree o
tDelete _ ETree = ETree
tDelete _ [email protected](Node ETree ETree _) = n -- Or give "Not found" error?
tDelete tD [email protected](Node lT rT a)
| tD < a = Node (tDelete tD lT) rT a
| tD > a = Node lT (tDelete tD rT) a
| otherwise = case (lT,rT) of
(ETree,t) -> t
(t,ETree) -> t
(t,t') -> let fMin = tMin t' in Node t (tDelete (fMin) t') fMin
getErrorTree :: Tree Int
getErrorTree = getSubTree 992 . tBalanceNX 100 $ tFromListL [1..1000]
main = do
putStrLn "Deleting 992 yields two 993 trees"
let errorTree = getErrorTree
print errorTree
putStrLn $ "993 findable in tree? " ++ show (993 `tElem` errorTree)
print $ tDelete 992 errorTree
putStrLn "The final tree ends up containing two 993 values; one as the root (intended), and one further down (unintended. It should have been deleted in the last case of the last guard of tDelete)"
你不需要這個龐大的測試用例;即使'tDelete 1 $ tBalanceNX 1 $ tFromListL [1]'不起作用。考慮在'tDelete _ n @(Node ETree ETree _)= n'情況下會發生什麼。你返回整個樹,但可能是'tD == a'的情況。 – user2407038 2014-09-26 07:30:03
哎呀。邏輯失敗。 – Carcigenicate 2014-09-26 13:52:29