【问题标题】:Linked list implementation of Binary Min Heap (Having trouble with manipulation...)Binary Min Heap 的链表实现(操作有问题...)
【发布时间】:2011-07-27 23:25:25
【问题描述】:

所以我正在尝试实现二进制最小堆。我了解二进制最小堆在其结构和属性方面的含义。但是,当我尝试使用指针和节点来实现它时,我碰壁了。

我使用的是Node,它有right/left and pointersint elementparent pointer。我还有一个LastNode,它指向最后插入的节点。

我的争吵是我不知道插入元素时要做什么,就最后一个节点而言。 这就是我的意思。

步骤 1.) 假设堆是空的,所以你创建一个 root 即 x 其中 x 包含元素并且你设置 root.left/right = nullLastNode = root.left

  X
 / \
0   0

这是我卡住的部分。我知道当您创建另一个节点来存储另一个元素时,它将位于 X 的左侧或 LastNode 指向的位置。我的问题我接下来用 LastNode 做什么,我是否将它指向 x.right ?我试图让insert(int x) 在 logN 中运行,并且 lastNode 操作将在每个级别变得更长和更广泛。

有人可以分解吗? 谢谢

【问题讨论】:

  • 如果这不是功课,那么二进制堆有一个更简单的实现:只需使用一个数组
  • 如果一个节点有左、右和父指针,它就不是一个LinkedList,它是一个树。
  • 是的,使用数组要容易得多,但这是功课。

标签: java binary-tree heap min


【解决方案1】:

你需要在堆的最后一层插入元素,然后从那里确定是否需要冒泡。因此,您需要 lastNode 指针来指示不是插入的最后一个元素(它很可能是最后一个插入的元素,但它可能一直上升到现在的根;这根本没有帮助),而是您将在其中插入这个新元素。这有帮助吗?

(稍后编辑):有一种更优化的方式来构建堆,但我觉得这不是你现在需要的,所以这就是为什么我假设你将使用简单的插入 O(log n)对于每一个新元素。

【讨论】:

  • 我明白你在说什么。但是,我如何解释 lastNode 的(无论它指向什么)Parent.right 节点?你能举个例子,从头开始构建它吗?
  • 看准了!这正是像常规二叉树一样存储堆的问题:) 我知道解决这个问题的最好方法是线程化树(en.wikipedia.org/wiki/Threaded_binary_tree),所以当你让它为你的下一个元素存储一个额外的指针时正在找。每次需要时都查找下一个元素对我来说似乎效率不高,因此您必须在进行时存储一些信息。
  • 或者您可以研究我之前提到的更有效的构建方式。这个想法是,您首先只需构建树而不用担心堆属性,只需在获取元素时插入元素并在插入所有元素之后,然后开始强制执行堆属性。我认为维基百科解释得很好:en.wikipedia.org/wiki/Binary_heap#Building_a_heap
  • 我采用了后一种方法。但我仍然面临同样的问题。在 parent.left 节点填充了子节点后,如何使 lastNode 指向 parent.right?我的意思是,如果只有一两个级别,我可以轻松做到,但它会呈指数级增长。
  • 这毕竟是功课,我想你必须弄清楚一些事情。有几种方法可以做到这一点。这是一个提示。我假设这是因为您已经研究了更基本的数据结构。想想你可以如何使用其中任何一个来解决你的问题。还可以考虑其他可以任意将元素放置在树中的方法。
【解决方案2】:

既然你必须在底层插入节点,即广度,如果你维护一个队列中到目前为止插入的所有节点的记录呢?当你在堆中插入一个新节点时,从队列中找到最新的位置并将数据插入那里。然后 heapify_up 那个节点。

【讨论】:

    【解决方案3】:

    我想另一种方法是保留树中每个节点的所有子元素的计数。由于二叉堆的主要目标是完全平衡,您可以决定插入新节点或它们的键,向左或向右取决于树的哪一侧不太平衡。

    我目前正在尝试使用 Java 编写 Binary Hep 代码,但同时也陷入了困境。我想出了这种平衡堆的方法,并解决了在哪里插入新节点的问题。这仍然应该保持堆实现的复杂性。

    将在某个时候发布代码。如果有人对此有任何问题或认为这不是正确的做法,请纠正我。

    更新:这是代码 (https://gist.github.com/naveenwashere/5607516):

    public class BinaryHeap {
    
    //Later you can implement a resizable array logic.
    int[] bH;
    
    public BinaryHeap(int N)
    {
        bH = new int[N + 1];
    }
    
    //Index of the root
    int k = 1;
    
    //The APIs
    public void put(int key)
    {
        //Place the element at the end of the array
        bH[this.k] = key;       
        if(bH[this.k] > bH[this.k/2])
        {
            //since the elements in an array implementation of the binary heap is put at the end of the array,
            //we must always check if the property of the tree holds true or not.
            swim(this.k);
        }
        this.k++;
    }
    
    public void deleteMax()
    {
        //Replace the element in the root with the element at the end of the array
        bH[1] = bH[k];
        //Restore the order of the tree
        sink(1);
        this.k--;
    }
    
    public void deleteMin()
    {
        bH[this.k - 1] = 0;
        this.k--;
    }
    
    public void swim(int k)
    {
        while((k != 1) && (bH[k] > bH[k/2]))
        {
            swap(k, k/2);
            k = k/2;
        }
    }
    
    public void sink(int k)
    {
        while(2*k <= this.k)
        {
            int j = 2*k;
            if(max(j, j+1)) j++;
            if(bH[k] < bH[j])
                swap(k, j);
            else if(bH[k] > bH[j]) 
                break;
            k = j;
        }
    }
    
    private boolean max(int i, int j) {
        if(bH[i] < bH[j])
            return true;
        return false;
    }
    
    private void swap(int i, int j) {
        int temp = 0;
        temp = bH[i];
        bH[i] = bH[j];
        bH[j] = temp;
    }
    
    private void printAll() {
        for(int i=1; i < this.k; i++)
        {
            System.out.print(bH[i] + " ");
        }       
        System.out.println();
    }
    
    public static void main(String[] args) throws Exception
    {
        int a[] = {6,5,7,8,2,9,8,1};
        BinaryHeap bh = new BinaryHeap(a.length);
        for(int i=0; i < a.length; i++)
        {
            bh.put(a[i]);
        }
    
        System.out.println("Elements in Binary Heap: ");
        bh.printAll();
    
        System.out.println("Deleting Minimum: ");
        bh.deleteMin();
        bh.printAll();
    
        System.out.println("Deleting Maximum: ");
        bh.deleteMax();
        bh.printAll();
    }}
    

    谢谢, ~N

    【讨论】:

      【解决方案4】:

      我有同样的家庭作业。我找到的解决方案是逐级降低二叉树,每次根据底部节点的数量决定左转或右转。我为此做了一个递归算法。

      例如,假设您想在以下树中放置一个新节点:

          A
         / \
        B   C
       / \ / \
      D  E X  X
      

      从顶部开始,您会发现底部有 2/4 个完整节点。因此,您从右分支下降并发现自己位于树的顶部,根为C。在这棵树的底部有 0/2 个完整节点,因此您从左分支下降并发现自己位于叶节点,因此这是您放置新元素的位置。

      这是我用来计算树的高度的 Java 代码,任何给定高度的树底部的可能节点数,以及树底部的完整或“已使用”节点的数量大小为size

      private int height(int size) {
          return (int) Math.ceil(log2(size + 1));
      }
      // returns the amount of space in the bottom row of a binary tree
      private int bottomRowSpace(int height) {
          return (int) Math.pow(2, height - 1);
      }
      // returns the amount of filled spots in the bottom row of a binary tree
      private int bottomRowFilled(int size) {
          return size - (bottomRowSpace(height(size)) - 1);
      }
      // log base2
      private double log2(double a) {
          return Math.log(a) / Math.log(2);
      }
      

      【讨论】:

        【解决方案5】:

        使用此函数到达所需节点:

        function find_node($n)
        {
        $current_node = $n;
        while($current_node > 1)
        {
            if($current_node % 2 == 1) // if node is odd it is a right child
            {
              push($stack,"Right");
            }
            else // otherwise it is even and left child
            {
              push($stack,"Left");
            }
            $current_node = floor($current_node / 2); // set the current node to the parent
        }
        return $stack; // this stack now contains the path to node n
        }
        

        【讨论】:

          猜你喜欢
          • 2019-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-20
          • 1970-01-01
          • 2013-12-17
          • 2017-11-28
          相关资源
          最近更新 更多