左式堆又叫做左偏树, 是一种合并高效的堆, 左式堆的insert以及
deleteMin等操做都是以merge操做为基础的。
merge时间复杂度能够达到O(logN)
左式堆使用二叉树的结构实现, 相比于二叉树,
其结点上增长了一个NPL (null path length)属性,
它指的是从该结点到达一个没有两个孩子的结点的最短距离,
叶节点的NPL为0,NULL节点的NPL为-1, 满足如下3个性质
1. 结点的键值小于等于其左右孩子的键值(小根性)
2. 结点的左孩子的npl不小于其右孩子的NPL(左偏性)
3. 结点的距离等于其右孩子的NPL+1
合并核心操作:
(1) 如果合并一个空左式堆与一个非空左式堆,返回非空左式堆。
(2) 如果两个左式堆都非空,那么比较两个根节点,取较小堆的根节点为合并后堆的根节点,
然后将这个根的左孩子作为合并后堆的左儿子,递归地合并其右儿子与另一个堆,作为合并后的堆的右孩子。
(3) 如果新堆的右孩子的NPL > 左孩子的NPL,则交换其左右孩子。
(4) 设置新堆的根节点的NPL = 右子堆NPL + 1
针对键值为正数的顺序实现
#include <iostream>
#include <queue>
#include <vector>
struct LHNode
{
int ls;
int rs;
int d;
int val;
int fa;
LHNode(int v)
: val(v), d(0), ls(0), rs(0), fa(0) {}
LHNode()
: val(0), d(-1), ls(0), rs(0), fa(0) {}
};
const int SIZE = 10e2+2;
LHNode t[SIZE];
int merge(int x, int y)
{
if (!x || !y) return x | y; // 若一个堆为空则返回另一个堆
if (t[x].val > t[y].val) // 取值较小的作为根
std::swap(x, y);
t[x].rs = merge(t[x].rs, y); // 递归合并右儿子与另一个堆
if (t[t[x].rs].d > t[t[x].ls].d)
std::swap(t[x].ls, t[x].rs); // 若不满足左偏性质则交换左右儿子
t[x].d = t[t[x].rs].d + 1; // 更新dist
return x;
}
/****************
删除任意结点的核心思想:
先将左右孩子合并,然后自底向上更新NPL,不满足左偏性时交换左右孩子,
当NPL无需更新时结束递归;
如果删除根,直接合并左右孩子就行。
****************/
void remove(int x)
{
int q = t[x].fa; // p is x's parent
int p = merge(t[x].ls, t[x].rs); // q is the new tree's root
t[p].fa = q;
if (q != 0 && t[q].ls == x) // if left, link to left
t[q].ls = p;
if (q != 0 && t[q].rs == x) // if right, link to right
t[q].rs = p;
while (q != 0)
{
if (t[t[q].ls].d < t[t[q].rs].d)
std::swap(t[q].ls, t[q].rs);
if (t[t[q].rs].d + 1 == t[q].d)
break;
else
t[q].d = t[t[q].rs].d + 1;
q = t[q].fa;
}
}
void layer(int x)
{
std::queue<int> qu;
std::vector<int> vec;
if (x != 0)
qu.push(x);
while (!qu.empty())
{
vec.clear();
int j =0 , size = qu.size();
for (j = 0; j < size; ++j)
{
int i = qu.front();
qu.pop();
vec.push_back(i);
if (i != 0)
{
//if (t[i].ls != 0)
qu.push(t[i].ls);
//if (t[i].rs != 0)
qu.push(t[i].rs);
}
}
for (j = 0; j < vec.size(); ++j)
{
if (vec[j] == 0)
std::cout << "# ";
else
std::cout << vec[j] << "(" << t[vec[j]].d << ")" << " ";
}
std::cout << std::endl;
}
}
int main()
{
int arr1[] = {10, 24, 12, 30, 36, 20, 16, 40};
int arr2[] = {11, 15, 13, 19, 21, 17, 23};
int i = 0;
int root1 = 0;
for (i = 0; i < sizeof(arr1) / sizeof(int); ++i)
{
t[arr1[i]] = LHNode(arr1[i]);
root1 = merge(root1, arr1[i]);
}
std::cout << "root1: " << root1 << std::endl;
layer(root1);
int root2 = 0;
for (i = 0; i < sizeof(arr2) / sizeof(int); ++i)
{
t[arr2[i]] = LHNode(arr2[i]);
root2 = merge(root2, arr2[i]);
}
std::cout << "root2: " << root2 << std::endl;
layer(root2);
root1 = merge(root1, root2);
std::cout << "new tree: " << root1 << std::endl;
layer(root1);
std::cout << "after remove 11,new root: " << root1 << std::endl;
remove(11);
layer(10);
return 0;
}
root1: 10
10(2)
12(1) 16(1)
30(0) 36(0) 20(0) 40(0)
# # # # 24(0) # # #
# #
root2: 11
11(2)
13(1) 15(1)
19(0) 21(0) 17(0) 23(0)
# # # # # # # #
new tree: 10
10(2)
11(2) 12(1)
13(1) 15(1) 30(0) 36(0)
19(0) 21(0) 16(1) 17(0) # # # #
# # # # 20(0) 23(0) # #
24(0) # 40(0) #
# # # #
after remove 11?new root: 10
10(2)
13(1) 12(1)
15(1) 19(0) 30(0) 36(0)
16(1) 17(0) # # # # # #
20(0) 23(0) 21(0) #
24(0) # 40(0) # # #
# # # #
左偏堆链式存储:
#include <iostream>
#include <queue>
#include <vector>
struct LLHNode
{
LLHNode *ls;
LLHNode *rs;
int d;
int val;
LLHNode *fa;
LLHNode(int v)
: val(v), d(0), ls(nullptr), rs(nullptr), fa(nullptr) {}
LLHNode()
: val(0), d(-1), ls(nullptr), rs(nullptr), fa(nullptr) {}
};
class LeftLinkHeap
{
public:
LeftLinkHeap() : m_root(nullptr) {}
~LeftLinkHeap();
void insert(int k);
void remove(int k);
void layer();
void merge(LeftLinkHeap* other);
private:
void destroy(LLHNode *t);
void swap(LLHNode* &l, LLHNode* &r);
LLHNode* merge(LLHNode* &x, LLHNode* &y);
LLHNode* search(int x);
private:
LLHNode *m_root;
};
LeftLinkHeap::~LeftLinkHeap()
{
destroy(m_root);
}
void LeftLinkHeap::destroy(LLHNode *t)
{
if (t != nullptr)
{
destroy(t->ls);
destroy(t->rs);
delete t;
t = nullptr;
}
}
void LeftLinkHeap::swap(LLHNode* &l, LLHNode* &r)
{
LLHNode* t = l;
l = r;
r = t;
}
LLHNode* LeftLinkHeap::merge(LLHNode* &x, LLHNode* &y)
{
if (x == nullptr)
return y;
if (y == nullptr)
return x;
if (x->val > y->val)
swap(x, y);
x->rs = merge(x->rs, y);
x->rs->fa = x;
if (x->ls == nullptr || x->rs->d > x->ls->d)
swap(x->ls, x->rs);
if (x->rs == nullptr)
x->d = 0;
else
x->d = x->rs->d + 1;
return x;
}
void LeftLinkHeap::merge(LeftLinkHeap* other)
{
m_root = merge(m_root, other->m_root);
}
void LeftLinkHeap::insert(int k)
{
LLHNode *pNode = new LLHNode(k);
m_root = merge(m_root, pNode);
}
void LeftLinkHeap::layer()
{
std::queue<LLHNode *> qu;
if (m_root != nullptr)
qu.push(m_root);
while (!qu.empty())
{
int size = qu.size();
for (int i = 0; i < size; ++i)
{
LLHNode *t = qu.front();
qu.pop();
if (t != nullptr)
{
std::cout << t->val << " ";
//if (t->ls != nullptr)
qu.push(t->ls);
//if (t->rs != nullptr)
qu.push(t->rs);
}
else
std::cout << "# ";
}
std::cout << std::endl;
}
}
LLHNode* LeftLinkHeap::search(int x)
{
std::queue<LLHNode *> qu;
if (m_root != nullptr)
qu.push(m_root);
while (!qu.empty())
{
LLHNode *t = qu.front();
qu.pop();
if (t->val == x)
return t;
if (t->ls != nullptr)
{
if (t->ls->val == x)
return t->ls;
else if (t->ls->val < x)
qu.push(t->ls);
}
if (t->rs != nullptr)
{
if (t->rs->val == x)
return t->rs;
else if (t->rs->val < x)
qu.push(t->rs);
}
}
return nullptr;
}
void LeftLinkHeap::remove(int k)
{
LLHNode *t = search(k);
LLHNode *parent = t->fa;
t = merge(t->ls, t->rs);
if (parent == nullptr)
m_root = t;
else
{
if (parent->ls->val == k)
parent->ls = t;
if (parent->rs->val == k)
parent->rs = t;
}
while (parent != nullptr)
{
if (parent->rs->d > parent->ls->d)
swap(parent->ls, parent->rs);
if (parent->d == parent->rs->d + 1)
break;
else
parent->d = parent->rs->d + 1;
parent = parent->fa;
}
}
int main()
{
int arr1[] = { 10, 24, 12, 30, 36, 20, 16, 40 };
int arr2[] = { 11, 15, 13, 19, 21, 17, 23 };
std::cout << "create one leftlistlheap1 " << std::endl;
LeftLinkHeap llheap;
int i = 0;
for (i = 0; i < sizeof(arr1) / sizeof(int); ++i)
llheap.insert(arr1[i]);
llheap.layer();
std::cout << "create leftlistlheap2 " << std::endl;
LeftLinkHeap other;
for (i = 0; i < sizeof(arr2) / sizeof(int); ++i)
other.insert(arr2[i]);
other.layer();
std::cout << "merge leftlistlheap1 and leftlistlheap2 " << std::endl;
llheap.merge(&other);
llheap.layer();
std::cout << "after remove 11" << std::endl;
llheap.remove(11);
llheap.layer();
return 0;
}
create one leftlistlheap1
10
12 16
30 36 20 40
# # # # 24 # # #
# #
create leftlistlheap2
11
13 15
19 21 17 23
# # # # # # # #
merge leftlistlheap1 and leftlistlheap2
10
11 12
13 15 30 36
19 21 16 17 # # # #
# # # # 20 23 # #
24 # 40 #
# # # #
after remove 11
10
13 12
15 19 30 36
16 17 # # # # # #
20 23 21 #
24 # 40 # # #
# # # #