左式堆--优先队列

1:在前面提到过的二叉堆的优先队列的插入操作是O(logN)的时间复杂度,删除操作因为需要将最后一个元素提到最前面,所以时间复杂度也是O(logN)的时间复杂度。构建二叉堆的时候,如果是单独一个个的插入,那么将花费O(N)的时间复杂度。而且如果想要合并连个二叉堆,必须在申请一个新的数组来存储,所以合并操作也会花费O(N)的时间复杂度。

2:左式堆也像二叉堆那样具有结构性和有序性。但是左式堆是趋向于不平衡的。但是左式堆的合并操作时间复杂度是O(logN),删除和插入操作也是O(logN)的时间复杂度。

 性质:我们把任意节点X的零路径长(null path length)npl(x)定义为从X到一个不具有两个儿子节点的最短路径长,因此具有0个或者1个节点的npl为0,而npl(null) = -1。对于堆中的每一个节点X,左儿子的零路径长至少与右儿子的零路径长相等。因此左式堆是一种偏向于使树向左增加深度----左式堆。

左式堆递归的合并的方法:如果有一个堆是空的,那么直接返回另一个堆。否则比较两个堆的根节点。首先递归的将具有较大值的根节点与具有较小值的根节点的右子堆进行合并。具体算法见程序:

节点TreeNode:

public class TreeNode {
	//定义存储元素值的变量
	public int val;
	//定义节点的左孩子
	public TreeNode left;
	//定义节点的右孩子
	public TreeNode right;
	//还要定义一个节点的npl值
	public int npl;
	
	public TreeNode(int val) {
		this.val = val;
		this.left = null;
		this.right = null;
		this.npl = 0;
	}

}
import java.util.LinkedList;
import java.util.Queue;

public class LeftHeap {
	
	//定义开始的根节点
	private TreeNode root;
	//定义节点的个数
	private int size;
	
	//构造函数
	public LeftHeap() {
		root = null;
	}
	
	//返回节点的个数
	public int getSize() {
		return size;
	}
	//判断是否为空
	public boolean isEmpty() {
		return size == 0;
	}
	
	//进行合并
	public void merge(LeftHeap right) {
		if(this == right) {
			return ;
		}
		root = merge(this.root,right.root);
		right.root = null;
	}
	
	//避免一些特殊情况,而且保证返回的是h1
	public TreeNode merge(TreeNode h1,TreeNode h2) {
		if(h1 == null) {
			return h2;
		}
		else if(h2 == null) {
			return h1;
		}
		else if(h1.val<h2.val) {
			return merge1(h1,h2);
		}
		else {
			return merge1(h2,h1);
		}
	}
	//保证了h1是一直有最小值的,这样可以避免讨论过多的情况
	private TreeNode merge1(TreeNode h1,TreeNode h2) {
		if(h1.left == null) {
			h1.left = h2;
		}
		else {
			h1.right = merge(h1.right,h2);
			if(h1.left.npl<h1.right.npl) {
				swapChild(h1.left,h1.right);
			}
			h1.npl = h1.right.npl+1;
		}
		return h1;
	}
	//交换左右孩子
	private  void swapChild(TreeNode left,TreeNode right) {
		TreeNode temp = null;
		temp = left;
		left = right;
		right = temp;
	}
	
	
	//插入操作,其实就是一颗一个节点的堆和已有的堆进行合并
	public void insert(int val) {
		root = merge(new TreeNode(val),root);
		size++;
	}
	
	//删除操作就是返回根节点的值,然后合并左右子树
	public int  deleteMin() {
		if(isEmpty()) {
			throw new IllegalArgumentException("已空");
		}
		int temp = root.val;
		root = merge(root.left,root.right);
		size--;
		return temp;
	}
	
	//重写toString'()方法
	public String toString() {
		StringBuilder res = new StringBuilder();
		res.append("LeftHeap:");
		Queue<TreeNode> queue = new LinkedList<>();
		queue.add(root);
		while(!queue.isEmpty()) {
			TreeNode node = queue.poll();
			if(node!=null) {
				res.append(node.val+",");
				queue.add(node.left);
				queue.add(node.right);
			}
		}
		return res.toString();
	}
	
	
	public static void main(String[] args) {
		LeftHeap heap = new LeftHeap();
		heap.insert(10);
		heap.insert(21);
		heap.insert(14);
		heap.insert(23);
		heap.insert(3);
		System.out.println(heap);
		
		LeftHeap heap1 = new LeftHeap();
		heap1.insert(12);
		heap1.insert(6);
		heap1.insert(18);
		heap1.insert(24);
		heap1.insert(7);
		heap1.insert(37);
		heap1.insert(8);
		
		
		heap.merge(heap1);
		heap.deleteMin();
		System.out.println(heap);
		heap.deleteMin();
		System.out.println(heap);
		heap.deleteMin();
		System.out.println(heap);
		heap.deleteMin();
		System.out.println(heap);
		heap.deleteMin();
		System.out.println(heap);
	}

}

结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值