1.定义
左偏树,leftist tree。首先是一个堆,即
node<=node.leftChild
&&
node<=node.rightChild 。
对于树中任意一个节点,左孩子的distance >= 右孩子的distance。
对于树中任意一个节点,左孩子的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;