【问题标题】:How to balance a Max Heap Tree in Elixir?如何在 Elixir 中平衡最大堆树?
【发布时间】:2019-03-04 22:46:59
【问题描述】:

我已经实现了最大堆树,但是在创建新节点时,树变得不平衡。例如,如果插入的大多数值都小于根值,则它成为左重树。这是因为 if-else 比较,但是还有其他方法可以平衡树吗?提前致谢。

defmodule MaxHeap do

  defstruct value: nil, right: nil, left: nil

  def new(value), do: %MaxHeap{value: value}

  def insert(newValue=%MaxHeap{value: rootValue}, nextValue) do
    if nextValue <= rootValue do
      %MaxHeap{newValue | left: insert(newValue.left, nextValue)}
    else
      temp=rootValue #save old rootValue in temp, before editing it
      rootValue=nextValue
      nextValue=temp
      %MaxHeap{newValue | right: insert(newValue.right, nextValue), value: rootValue}
    end
  end

  def insert(nil, value) do
    %MaxHeap{value: value}
  end
end

Output tree in Elixir iex:

【问题讨论】:

    标签: functional-programming tree elixir heap balance


    【解决方案1】:

    如果您真正想要的是堆,您可以使用一种稍微不同的数据结构,称为左派树 - 它是一棵树 这总是以特定方式不平衡,允许您进行O(log(N)) 堆操作。你可以看到一个 in this blog post about leftist trees 的描述。

    一种易于理解的平衡树的策略是所谓的 AVL 树。 AVL 树是二叉树 树,其中任何节点的两个子节点之间的高度差不能大于一。这棵树差不多 平衡在于它的高度在任何时候最多可以是2log(N)。这里实现它的方法是:

    1. 在节点中存储树的高度:

      defstruct value: nil, right: nil, left: nil, height: 1
      
    2. 插入后更新树高然后平衡:

      def insert(newValue = %MaxHeap{value: rootValue}, nextValue) do
        if nextValue <= rootValue do
          %MaxHeap{newValue | left: insert(newValue.left, nextValue)}
        else
          %MaxHeap{newValue | right: insert(newValue.right, nextValue)}
        end
        |> set_height()
        |> balance()
      end
      
    3. 有一个处理空树的height 函数:

      def height(nil), do: 0
      def height(tree), do: tree.height
      
    4. 有一个set_height 函数可以根据孩子的身高设置父母的身高:

      defp set_height(tree) do
        %{tree | height: max(height(tree.left), height(tree.right)) + 1}
      end
      
    5. balance 函数中,如果子树的高度变化超过 1,则应用向左或向右旋转:

      defp balance(tree) do
        cond do
          height(tree.left) > height(tree.right) + 1 -> rotate_right(tree)
          height(tree.right) > height(tree.left) + 1 -> rotate_left(tree)
          true -> tree
        end
      end
      
    6. 有一个rotate_left 函数(和一个类似的rotate_right 函数):

      defp rotate_right(tree) do
        %{tree.left | right: set_height(%{tree | left: tree.left.right})}
        |> set_height()
      end
      
      defp rotate_left(tree) do
        %{tree.right | left: set_height(%{tree | right: tree.right.left})}
        |> set_height()
      end
      

    关于这些旋转需要注意的重要一点是它们保持二叉树不变性。

    您可以阅读有关此方法的更多信息in this geeksforgeeks post about AVL trees

    【讨论】:

      猜你喜欢
      • 2013-11-06
      • 1970-01-01
      • 1970-01-01
      • 2017-10-07
      • 2011-04-26
      • 2014-04-07
      • 1970-01-01
      • 1970-01-01
      • 2015-08-17
      相关资源
      最近更新 更多