1、引言
《算法竞赛进阶指南》中指出,在二叉树中,有两组非常重要的条件,分别是两类数据结构的基本性质。
其一是“堆性质”,若二叉树中的任意一个节点的权值都大于等于(小于等于)其父亲节点,则称该二叉树满足“小顶堆性质(大顶堆性质)”。
其二是“BST性质”,二叉树上的每个节点都带有一个数值,称为该节点的键值 $key$,树中的任意一个节点的 $key$ 均同时满足:大于等于其左子树中任意节点的 $key$,小于等于其右子树中任意节点的 $key$。
在日常的刷题过程中,经常会用到优先队列、set、map等STL的容器,但是实际上它们的底层实现某种程度上可以说是二叉堆或者BST,而且二叉堆和BST作为较基础的数据结构,我们应当学会如何实现。
2、二叉堆的实现
struct Heap
{
int sz;
int heap[maxn];
void up(int now)
{
while(now>1)
{
int par=now>>1;
if(heap[now]<heap[par]) //子节点小于父节点,不满足小顶堆性质
{
swap(heap[par],heap[now]);
now=par;
}
else break;
}
}
void push(int x) //插入权值为x的节点
{
heap[++sz]=x;
up(sz);
}
inline int top(){return heap[1];}
void down(int now)
{
while((now<<1)<=sz)
{
int nxt=now<<1;
if(nxt+1<=sz && heap[nxt+1]<heap[nxt]) nxt++; //取左右子节点中较小的
if(heap[now]>heap[nxt]) //子节点小于父节点,不满足小顶堆性质
{
swap(heap[now],heap[nxt]);
now=nxt;
}
else break;
}
}
void pop() //移除堆顶
{
heap[1]=heap[sz--];
down(1);
}
void del(int p) //删除存储在数组下标为p位置的节点
{
heap[p]=heap[sz--];
up(p), down(p);
}
inline void clr(){sz=0;}
};
3、二叉堆的应用
3.1、POJ 1456
3.2、二叉堆优化Dijkstra
3.3、BZOJ 1150
4、二叉搜索树
普通的二叉搜索树每次期望复杂度为 $O(\log n)$,但是非常容易退化为 $O(n)$,因此实际应用中一般使用平衡二叉查找树。
4.1、伸展树Splay
伸展树原理:
伸展树(Splay Tree)进阶 - 从原理到实现
伸展树实现:
POJ 3580 - SuperMemo - [伸展树splay]
4.2、Treap
BZOJ 3224 - 普通平衡树 - [Treap]