优先队列之左式堆(JAVA实现)

一、定义:

1.零路径长度:某节点的零路径长度为该节点到没有两个儿子的节点最短距离。

2.左式堆性质:

  • 父节点属性值小于子节点属性值;
  • 堆中的任何节点,其左儿子的零路径长>=右儿子的零路径长的二叉树。
  • 任一结点的零路径长比他的诸儿子结点的零路径长的最小值多1。

二、实现思路:

1.合并:
左式堆的合并操作基于递归实现,算法思路如下:

  1. 若有一棵树是空树,则返回另一棵树;否则将根节点较大的堆与根节点较小的堆的右子树合并。
  2. 使形成的新堆作为较小堆的右子树。
  3. 如果违反了左式堆的特性,交换两个子树的位置。
  4. 更新npl(零路径长度)。

2.插入
将需要插入的节点当做一棵左式堆树,进行合并。

3.删除最小值
删除根节点,将形成的两个堆合并

三、代码实现






public class LeftistHeap<T extends Comparable> {
    /**
     * Created by Administrator on 2017/6/13.
     */
    class Node<T> {
        T element;
        Node<T> left;//左儿子
        Node<T> right;//右儿子
        int npl;//零路径长

        Node(T element) {
            this(element, null, null);
        }

        Node(T element, Node<T> left, Node<T> right) {
            this.element = element;
            this.left = left;
            this.right = right;
            npl = 0;
        }
    }
    private Node<T> root;

    /**
     * 构造方法
     */
    public LeftistHeap() {
        root = null;
    }

    /**
     * 合并堆
     *
     * @param rhs 另一个左式堆
     */
    public void merge(LeftistHeap<T> rhs) {
        if (this == rhs) {
            return;
        }
        root = merge(root, rhs.root);
        rhs.root = null;
    }

    public void insert(T x) {
        root = merge(root, new Node(x));
    }

    /**
     * 找出最小元素
     *
     * @return
     */
    public T findmin() {
        if(isEmpty()){
            System.out.println("该左式堆为空");
        }
        return root.element;
    }

    /**
     * 删除最小元素
     *
     * @return
     */
    public T deleteMin() {
        if (isEmpty()) {
            System.out.println("该左式堆为空");
        }
        T minElement = root.element;
        root=merge(root.left, root.right);
        return minElement;
    }

    /**
     * 是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return root == null;
    }

    /**
     * 置空
     */
    public void makeEmpty() {
        this.root = null;
    }

    /**
     * 合并两个左式堆(判断过程,真正合并过程由merge1操作)
     *
     * @param h1
     * @param h2
     * @return
     */
    private Node<T> merge(Node<T> h1, Node<T> h2) {
        if (h1 == null)
            return h2;
        if (h2 == null)
            return h1;
        if (h1.element.compareTo(h2.element) > 0)
            return merge1(h2, h1);
        else
            return merge1(h1, h2);

    }

    /**
     * 合并两个左式堆的真正操作  h1的元素小于h2(即h2与h1的右子堆合并)
     *
     * @param h1
     * @param h2
     * @return
     */
    private Node<T> merge1(Node<T> h1, Node<T> h2) {
        if (h1.left == null) {//h1为单节点
            h1.left = h2;
        } else {//h1不是单节点
            h1.right = merge(h1.right, h2);
            if (h1.right.npl > h1.left.npl) {//比较零路径长,确保左式堆性质不被破坏
                swapChildren(h1);
            }
            h1.npl = h1.right.npl + 1;//零路径长为右儿子的零路径长+1
        }
        return h1;
    }

    /**
     * 交换左右儿子
     *
     * @param t
     * @return
     */
    private void swapChildren(Node<T> t) {
        Node<T> temp = t.right;
        t.right = t.left;
        t.left = temp;
    }

    private void print(Node t){
        if(t==null)
            return;
        print(t.left);
        System.out.println(t.element+":"+t.npl);
        print(t.right);
    }

    public static void main(String[] args) {
        int numItems = 100;
        LeftistHeap<Integer> h  = new LeftistHeap<>( );
        LeftistHeap<Integer> h1 = new LeftistHeap<>( );
        int i = 37;
        for( i = 37; i != 0; i = ( i + 37 ) % numItems )
            if( i % 2 == 0 )
                h1.insert( i );
            else
                h.insert( i );

        h.merge( h1 );
        for( i = 1; i < numItems; i++ )
            if( h.deleteMin( ) != i )
                System.out.println( "Oops! " + i );
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值