测试两棵树是否相等以及Haskell中的二叉搜索树

时间:2017-06-27 14:04:07

标签: haskell tree binary-search-tree equality

我有点坚持为二叉搜索树实现一个Eq实例。我想检查两棵树中的值是否相同,但我真的不知道如何正确地做到这一点。由于两个二叉搜索树的结构可能不同,我不能直接比较节点。我的想法是将它们转换为列表,对列表进行排序并对它们进行比较,但这看起来非常复杂,我想知道是否还有其他方法可以做到这一点。这是我到目前为止所得到的:

data BB a = L | K a (BB a) (BB a) deriving (Show)

instance Eq BB where
  not (isBinarySearchTree t1 && isBinarySearchTree t2) = False
  inOrder t1 == inOrder t2 = True

1 个答案:

答案 0 :(得分:2)

接受的答案对我来说是错误的,因为你说你想根据树的概念内容而不是它们的确切结构进行比较。也就是说,您希望以下内容为真:

K 1 L (K 2 L L) == K 2 (K 1 L L) L

两个BST具有相同的两个元素,正确排序但结构不同。在结构上比较它们,如在severij的答案中,产生False,但你希望它是True

那么,如何按内容而不是按结构进行比较?那么,具有相同项目集的任何两个BST将具有相同的有序遍历。因此,您可以完全按照您在问题中的说法进行操作:将它们转换为列表,并比较列表。但是你不必对它们进行排序:因为它们是BST,你可以保证你可以按照相同的顺序遍历它们。将它们转换为列表并不是非常昂贵,所以不要担心:懒惰和流融合会使其成本与手动编写遍历相同。

如果你的树类型有一个可折叠的实例,那将会容易得多,无论如何树都是一件好事。要定义可折叠,您只需要定义foldr,这很容易:

import Prelude hiding (foldr)
import Data.Foldable (Foldable, foldr, toList)

instance Foldable BB where
  foldr f init L = init
  foldr f init (K x left right) = foldr f (f x (foldr f init right)) left

然后你可以用toList:

来定义Eq
instance Eq (BB a) where
  x == y = toList x == toList y

之后,您可以根据需要

*Main> (K 1 L (K 2 L L)) == (K 2 (K 1 L L) L)
True

但这是相当多的工作,不是吗?在写这个答案时,我多次错误地定义了foldr。事实证明,有一种方法可以避免自己编写:DeriveFoldable语言扩展允许GHC为您导出可折叠,就像它派生Show一样容易。但由于它按顺序折叠数据类型中的字段,因此您必须稍微更改它,以便左子树出现在根节点之前:

{-# LANGUAGE DeriveFoldable #-}

import Prelude hiding (foldr)
import Data.Foldable (Foldable, foldr, toList)

data BB a = L | K (BB a) a (BB a) deriving (Show, Foldable)

instance Eq (BB a) where
  x == y = toList x == toList y

事实上,我们仍然拥有所需的相等属性(尽管我们必须以不同方式编写节点,因为我们更改了字段顺序):

*Main> (K L 1 (K L 2 L)) == (K (K L 1 L) 2 L)
True

还有一个最后的改进:如果导入Data.Function.on,Eq定义也可以更简单。你可以简单地用on来比较两个树的相等性,将每个树转换成一个列表并比较这些列表是否相等"而不是手工拼写全部。让树定义和其他导入保持不变,我们终于获得了所需特征的非常简洁的定义,所有实际工作都是由已编写的库函数完成的:

{-# LANGUAGE DeriveFoldable #-}

import Prelude hiding (foldr)
import Data.Foldable (Foldable, foldr, toList)
import Data.Function (on)

data BB a = L | K (BB a) a (BB a) deriving (Show, Foldable)

instance Eq a => Eq (BB a) where
  (==) = (==) `on` toList