📅  最后修改于: 2023-12-03 15:39:08.489000             🧑  作者: Mango
二项式堆是一种基于二项式树的数据结构,它是由多个二项式树组成的森林。和其他树型结构不同的是,二项式堆可以高效地进行合并、插入和删除等操作,并且可以维护最小堆或最大堆。
二项式树是一种特殊的树型结构,它是一棵递归定义的树,具体来说,$B_k$ 二项式树是由两个 $B_{k-1}$ 二项式树组成的,其中一个是它的左子树,另一个是它的根节点的兄弟节点,而且这两个子树的根节点的度数相同,都是 $k-1$。
二项式树的度数是指它的子节点个数,二项式堆可以高效地维护和维护度数相同的二项式树。
二项式堆的实现需要两个重要的数据结构:
BNode
:它包含一个元素节点和指向其父节点、最左边的子节点和右兄弟节点的指针。BHeap
:它包含一个指向最小节点的指针和一个指向堆的根节点的指针。/**
* 二项式堆节点
*/
class BNode<T> {
T data;
int degree = 0;
BNode<T> parent = null;
BNode<T> leftChild = null;
BNode<T> rightSibling = null;
BNode(T data) {
this.data = data;
}
}
/**
* 二项式堆
*/
public class BHeap<T extends Comparable<? super T>> {
private BNode<T> minRoot = null;
private BNode<T> root = null;
}
为了插入元素,需要创建一个只有根节点的二项式堆,然后将它和一个只有一个元素的二项式堆合并起来。
/**
* 插入元素
*
* @param data 插入的元素
*/
public void insert(T data) {
BHeap<T> newHeap = new BHeap<>();
newHeap.root = new BNode<>(data);
minRoot = union(newHeap).minRoot;
}
最小值即为 minRoot
指向的节点。
/**
* 查找最小值
*
* @return 找到的最小值节点的数据
* @throws NoSuchElementException 如果堆为空
*/
public T findMin() throws NoSuchElementException {
if (isEmpty()) {
throw new NoSuchElementException("BHeap is empty!");
}
return minRoot.data;
}
为了删除最小值,需要找到最小值所在的树,然后将它从树中删除,并将其子树合并到新的二项式堆中,最后再将新的二项式堆合并到原始的堆中。
/**
* 删除最小值
*
* @return 已删除的最小值节点的数据
* @throws NoSuchElementException 如果堆为空
*/
public T deleteMin() throws NoSuchElementException {
if (isEmpty()) {
throw new NoSuchElementException("BHeap is empty!");
}
BNode<T> minNode = minRoot;
BHeap<T> newHeap = new BHeap<>();
BNode<T> temp = minNode.leftChild;
// 从堆中删除最小值所在的树
if (minNode == root) {
root = minNode.rightSibling;
} else {
minNode.parent.leftChild = minNode.rightSibling;
}
// 将最小值的子树合并到新堆中
while (temp != null) {
BNode<T> next = temp.rightSibling;
temp.parent = null;
temp.rightSibling = newHeap.root;
newHeap.root = temp;
temp = next;
}
// 合并新堆到原始的堆
minRoot = union(newHeap).minRoot;
return minNode.data;
}
合并两个二项式堆需要以递增的顺序将度数相同的二项式树合并成一个更大的二项式树,最终得到一个新的二项式堆。
/**
* 合并两个二项式堆
*
* @param heap 要合并的二项式堆
* @return 合并后的二项式堆
*/
public BHeap<T> union(BHeap<T> heap) {
BHeap<T> newHeap = new BHeap<>();
newHeap.root = merge(this.root, heap.root);
if (newHeap.root == null) {
return newHeap;
}
BNode<T> prev = null;
BNode<T> curr = newHeap.root;
BNode<T> next = curr.rightSibling;
while (next != null) {
if (curr.degree != next.degree/* || (next.rightSibling != null && next.rightSibling.degree == curr.degree)*/) {
prev = curr;
curr = next;
} else if (curr.data.compareTo(next.data) <= 0) {
curr.rightSibling = next.rightSibling;
next.parent = curr;
next.leftChild = curr.rightSibling;
curr.rightSibling = next;
curr.degree++;
} else {
if (prev == null) {
newHeap.root = next;
} else {
prev.rightSibling = next;
}
curr.parent = next;
curr.rightSibling = next.leftChild;
next.leftChild = curr;
next.degree++;
curr = next;
}
next = curr.rightSibling;
}
return newHeap;
}
/**
* 合并两个二项式树
*
* @param h1 要合并的第一个二项式树
* @param h2 要合并的第二个二项式树
* @return 合并后的二项式树
*/
private BNode<T> merge(BNode<T> h1, BNode<T> h2) {
if (h1 == null) {
return h2;
}
if (h2 == null) {
return h1;
}
if (h1.degree <= h2.degree) {
h1.rightSibling = merge(h1.rightSibling, h2);
return h1;
} else {
h2.rightSibling = merge(h2.rightSibling, h1);
return h2;
}
}
本文介绍了二项式堆的实现,包括数据结构定义和方法实现,可以进行插入、查找最小值和删除最小值等操作,并且具有高效性和可维护性。