左偏树,原理及模板

1.定义

左偏树,leftist tree。首先是一个堆,即 node<=node.leftChild && node<=node.rightChild 。
对于树中任意一个节点,左孩子的distance >= 右孩子的distance。

1.1 节点的distance

将当前树补全为扩展二叉树。当前节点到最近的叶子节点的距离即为该节点的distance,维基百科中叫s-value。

1.2 用途

可以用作优先队列。
一般的堆,希望尽量平衡,这样元素调整次数少,但左偏树的特点就是不平衡,它的适用场景是什么?——用于多个堆的快速合并。

2.操作

2.1 合并

合并a与b两棵树。比较a和b的key值,若a的key值 < b的,把a的右子树和b合并,新树作为a的右子树。若此时不满足左偏定义,互换a的左右子树。
若a的key值大于b,把前面的步骤反过即可。

2.2 出队

合并左儿子和右儿子。

2.3 入队

插入点作为一棵只有一个节点的树,然后和原有的左偏树合并。

3.OJ模板

#include
    
    
     
     
using namespace std;
struct LeftistTreeNode {
	int value;
	int dist;
	int lchild, rchild;
	//node[i] means i-th node
	static LeftistTreeNode *nodes;

	LeftistTreeNode() {
		value = lchild = rchild = 0;
		dist = 1;
	}
	static void setNodes(LeftistTreeNode *tree) {
		LeftistTreeNode::nodes = tree;
	}
	/**
	 *
	 * @param a tree
	 * @param b tree
	 * @return new root
	 */
	int merge(int a, int b) {
		if (a == 0)
			return b;
		if (b == 0)
			return a;
		//大顶堆
		if (nodes[a].value < nodes[b].value)
			swap(a, b);
		nodes[a].rchild = merge(nodes[a].rchild, b);
		if (nodes[nodes[a].lchild].dist < nodes[nodes[a].rchild].dist)
			swap(nodes[a].lchild, nodes[a].rchild);
		nodes[a].dist = nodes[nodes[a].rchild].dist + 1;
		return a;
	}
	/**
	 * @param a tree
	 * @param b new node
	 * @return new root
	 */
	int insert(int a, int b) {
		return merge(a, b);
	}
	/**
	 * delete the top element and return new root
	 */
	int pop(int a) {
		return merge(nodes[a].lchild, nodes[a].rchild);
	}

};
//静态成员,类内声明类外初始化
LeftistTreeNode* LeftistTreeNode::nodes = NULL;

    
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值