Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
平衡AVL树haskell_Haskell_Avl Tree - Fatal编程技术网

平衡AVL树haskell

平衡AVL树haskell,haskell,avl-tree,Haskell,Avl Tree,我正在Haskell中创建一个AVL树,但我不确定如何平衡该树。我可以添加元素,但它们不平衡。与使用addList方法一样,我在[4,2,1,3,6,8]中添加了如下内容: 布局为:根4(根2(根1为空)(根2为空))(根6为空(根8为空)) 应打印为: 4 2 6 1 3 8 我想平衡一棵树的权利,但不知道如何实现它正确,这是我的代码到目前为止,任何帮助这将是惊人的 data AVLTree a = Empty | Root

我正在Haskell中创建一个AVL树,但我不确定如何平衡该树。我可以添加元素,但它们不平衡。与使用addList方法一样,我在[4,2,1,3,6,8]中添加了如下内容:

布局为:根4(根2(根1为空)(根2为空))(根6为空(根8为空))

应打印为:

         4
     2       6
 1       3       8
我想平衡一棵树的权利,但不知道如何实现它正确,这是我的代码到目前为止,任何帮助这将是惊人的

data AVLTree a = Empty | Root a (AVLTree a) (AVLTree a)
    deriving (Eq, Ord, Show)
leaf a = Root a Empty Empty

addNode :: Integral a => a -> AVLTree a -> AVLTree a
addNode a Empty = leaf a
addNode x (Root a left right)
  | x > a = Root a left (addNode x right)
  | x < a = Root a (addNode x left) right
  | otherwise = (Root a left right)
addList :: (Integral a) => [a] -> AVLTree a
addList [] = Empty
addList [n] = leaf n
addList (x:xs) = addNode x (addList xs)



search :: Integral a => AVLTree a -> a -> Bool
search Empty _ = False
search (Root a left right) x
  | x == a = True
  | x < a = search left x
  | x > a = search right x

-- balance :: AVLTree a -> AVLTree a
-- balance Empty = Empty
-- balance tree
-- |(Root r (Root left (Root left1 Empty Empty) Empty) Empty) = (Root left left1 r) -- left left case
-- |(Root r Empty (Root right Empty Empty) (Root right Empty Empty)) = (Root right r right1) -- right right case
-- |(Root r (Root left Empty (Root right Empty Empty)) Empty) = (Root r (Root right (Root left Empty Empty) Empty) Empty) -- left right case
-- |(Root r Empty (Root right (Root left Empty Empty) Empty)) = (Root r Empty (Root left Empty (Root right Empty Empty))) -- right left case
data AVLTree a=空|根a(AVLTree a)(AVLTree a)
推导(Eq、Ord、Show)
叶a=根a空
addNode::Integral a=>a->AVLTree a->AVLTree a
addNode a Empty=叶a
添加节点x(根a左-右)
|x>a=根a左(添加节点x右)
|x[a]->AVLTree a
addList[]=空
addList[n]=叶n
addList(x:xs)=addNode x(addList xs)
搜索::积分a=>AVLTree a->a->Bool
搜索为空uz=False
搜索(根a左-右)x
|x==a=True
|xa=搜索右x
--余额::AVLTree a->AVLTree a
--余额为空
--平衡树
--|(Root r(Root left(Root left1 Empty)Empty)Empty)=(Root left1 r)--左格
--|(Root r Empty(Root right Empty)(Root right Empty))=(Root right r right1)——右格
--|(Root r(Root left Empty(Root right Empty))Empty)=(Root r(Root right(Root left Empty)Empty)Empty)--左右格
--|(Root r Empty(Root right(Root left Empty)Empty))=(Root r Empty(Root left Empty(Root right Empty))右-左大小写

该实现仍然缺少很多内容,您应该多读一些所需内容(即使wikipedia有很好的描述,但如果您进行搜索,也会显示许多其他页面。)

编写任何(自平衡)树最棘手的部分是平衡代码。。。。正如上面所做的那样,在Haskell中创建一棵树非常容易,但是保持搜索日志(N)有点困难。在AVL的情况下,您必须添加更多代码来执行以下操作-

  • 向每个测量该节点高度的节点添加一个int。高度测量为到最远叶片的距离。AVL的工作原理是验证左侧和右侧子节点之间的高度差不会超过1。需要注意的是,此高度需要直接添加到节点,而不是在需要时计算(就像internet上的一些演示代码那样),否则即使是简单的插入也需要遍历整个树,而不再是log N

  • 添加代码,以便在插入后向上遍历节点树(最好的方法可能是在插入本身中,因为您已经沿着树遍历到插入点,所以可以在递归之后进行检查)。计算高度(只需在下面两个高度的最大值上加一个,这是您在递归调用中刚刚计算的),然后检查平衡因子(
    右高-左高
    )。如果事情不平衡(即平衡系数1),你必须

  • 调用rotate函数。旋转是一种类型为
    AVLTree->AVLTree
    的操作。直观地说,它将树中的顶部值推到左边(或右边,取决于不平衡的方向),从而恢复平衡。右侧节点将成为新的顶部节点,并将其左侧节点交给旧的顶部节点,然后旧的顶部节点将成为新的左侧节点。这是视觉效果-

  • 请注意,根据您将进行的简单检查,每次不平衡需要旋转一次或两次。。。。如果顶部不平衡(例如,向右),则在将顶部向左旋转之前,如果右节点向左有任何不平衡,则可能需要将右节点向右旋转(即使是1,与顶部不同,顶部可以有-1、0或1,并且不需要旋转)。旋转代码是相同的,因此您应该对顶部和右侧旋转使用相同的函数(尽管您可能希望使用单独的版本来向右或向左旋转)

    如果您为每个插入运行此平衡代码,就足够了。。。。如果您曾经添加节点,但没有这样做,那么在平衡树之前,您可能必须在所有节点上重复此过程几次,这将花费超过log(N)计算的时间

    当我写这篇文章时,我注意到我几乎没有写任何哈斯克尔的特定信息。。。。此信息适用于任何语言。我想这是应该的,没有理由仅仅因为我们在Haskell中,实现就应该有所不同。如果您在映射到Haskell的过程中遇到任何问题,请输入注释,我也可以填写

    另外请注意,如果您只需要一个具有Log(N)insert/delete的对象,Haskell已经具有Data.Sequence类型。如果这对你有用,你就不必自己写这些了


    编辑以回应评论-

    您提到的height函数有我上面提到的问题-您正在递归整个树以查找任何节点的高度。插入将不再具有logn复杂性,这就否定了首先拥有一棵树的全部意义。(据我所知,Haskell不会记忆这些值中的任何一个……如果有人知道其他情况,请随意插话,这会简化代码)

    更详细地说,您需要像这样扩展AVLTree的定义-

    data AVLTree a = Empty | Node a (AVLTree a) (AVLTree a) Int
    
    height (AVLTree _ _ _ height) = height
    
    现在高度就是这样得到的-

    data AVLTree a = Empty | Node a (AVLTree a) (AVLTree a) Int
    
    height (AVLTree _ _ _ height) = height
    
    那么你的平衡因子就起作用了-

    balanceFactor :: AVLTree a -> Int 
    balanceFactor Empty = 0 
    balanceFactor (Root a left right) = (height right) - (height left)
    
    缺点是,更改后,必须添加代码来重新计算整个链到根的高度

    然后需要编写另一个函数来检查是否需要旋转,并在需要时应用旋转-

    rotateIfNeeded::AVLTree->AVLTree
    rotateIfNeeded tree 
        | b > 1 = fullRotateLeft tree
        | b < -1 = fullRotateRight tree
        | otherwise = tree
           where b = balanceFactor tree
    
    rotateIfNeed::AVLTree->