数据结构之左式堆java实现

优先队列之左式堆

什么叫做左式堆呢?他就是跟二叉堆一样具有结构性和有序性,也就是说它是基于二叉堆的一个提升,他们的唯一区别就是左式堆是非常不平衡的。左式堆是一个有效支持合并操作的数据结构。

关于二叉堆可以看我之前写的博文二叉堆的实现

左式堆的性质

首先我们要知道,左式堆有一个npl值null path length,也就是任意节点到一个没有两个孩子节点的最短路径。

而他的性质则是 对于任意一个节点左子树的npl值至少等于右子树的npl值。也就是说左孩子的npl大于等于右孩子的npl值。

节点具有一个孩子节点或者没有孩子的节点的npl值为0。且npl(null)=-1.

左式堆左式堆 顾名思义我们要保证根节点的左子树长度大于右子树!!
如图在这里插入图片描述
在这个图片当中 左边的是左式堆,右边的不是

左边的为什么是呢?我们看1这个根节点,左孩子2的npl为1,右孩子的为0,左大于右成立,再往下走2,他的左孩子没有孩子所以npl=0,而他的右孩子5有一个孩子所以npl也等于0成立,所以对于任意一个节点他的左孩子的npl大于等于右孩子的npl成立,所以为左式堆。

再者我们看右边这个,1那个根节点都是一样的,所以我们直接看2这个节点,他的左孩子的没有孩子节点所以npl=0,而右孩子5有两个孩子节点所以5这个节点的npl=1.即右孩子的npl大于左孩子的npl不符合左式堆的性质,所以不是。

算法实现

因为左式堆的基本操作是合并,所以我们可以把插入看作为合并的一种特殊情形。

接下来我们看具体实现,首先我们要创建一个内部类当作节点,他又左孩子有孩子还有npl。

public class MyLeftHeap<AnyType extends Comparable<? super AnyType>> {
    private class HeapNode<AnyType>{
        AnyType data;
        HeapNode<AnyType> left;
        HeapNode<AnyType> right;
        int npl;      //npl 是节点到下一个不具有两孩子节点的最短路径长
        public HeapNode(AnyType data){this(data,null,null);}
        public HeapNode(AnyType data,HeapNode<AnyType> left,HeapNode<AnyType> right){
            this.data=data;
            this.left=left;
            this.right=right;
            npl=0;
        }
    }

接着我们进行初始化操作,也就是产生一个根节点但是没插入之前他是空的。

    private HeapNode<AnyType> root;
    public MyLeftHeap(){root=null;}
    public boolean isEmpty(){return root==null;}
    public void makeEmpty(){root=null;}

合并

接下来的就是合并,我们把一个新的左式堆放入,如果这俩是一个堆则不操作。我们把加入合并的那个堆的根与我们原本的堆的根进行合并判断,并返回给我们原本的根。

    //merge 合并
    public void merge(MyLeftHeap<AnyType> heap){
        if(this==heap)
            return;
        root=merge(root,heap.root);
        heap.root=null;
    }

根据输入的节点信息,判断是否哪个节点为空,一个空则返回另一个节点。若都不为空,则比较两个节点的数据谁大,把大的放在小的右子树空的位置。

    private HeapNode<AnyType> merge(HeapNode<AnyType> node1,HeapNode<AnyType> node2){
        if(node1==null)
            return node2;
        if(node2==null)
            return node1;
        if(node1.data.compareTo(node2.data)<0)
            return merge_operate(node1,node2);
        else
            return merge_operate(node2,node1);
    }

判断他是不是一个没有孩子的节点,没有孩子则放到左子树上,否则把右子树和要合并的堆进行递归操作直到把合并的树放上去。如果右子树的nol大于左子树了,则交换左右子树位置达到要求。

    private HeapNode<AnyType> merge_operate(HeapNode<AnyType> n1,HeapNode<AnyType> n2){
        if(n1.left==null)
            n1.left=n2;
        else {
            n1.right=merge(n1.right,n2);
            if(n1.left.npl<n1.right.npl)
                swapNode(n1);
            n1.npl=n1.right.npl+1;
        }
        return n1;
    }
    private void swapNode(HeapNode<AnyType> node){
        HeapNode<AnyType> temp=node.right;
        node.right=node.left;
        node.left=temp;
    }

之前我们说过插入是一种特殊的合并,那么删除最小的何尝又不是呢?插入的时候我们把一个新的节点归并到原本的堆当中,而删除最小的也就是当我们把根节点去掉之后,我们把他左右孩子节点进行归并不就是又得到了一个新的左式堆?

    //insert
    public void insert(AnyType data){root=merge(new HeapNode<>(data),root);}
    //deleteMin
    public AnyType deleteMin(){
        AnyType min=root.data;
        root=merge(root.left,root.right);
        return min;
    }
}

测试

public class test {
    public static void main(String[] args) {
       MyLeftHeap<Integer> a=new MyLeftHeap<>();
       a.insert(1);
       a.insert(2);
       a.insert(3);
       a.insert(4);

        MyLeftHeap<Integer> b=new MyLeftHeap<>();
        b.insert(11);
        b.insert(21);
        b.insert(31);
        b.insert(41);
        a.merge(b);
        while (!a.isEmpty())
            System.out.println(a.deleteMin());
    }
}

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TanGBx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值