概要
前面分別通過C和C++實現了斐波那契堆,本章給出斐波那契堆的Java版本。還是那句老話,三種實現的原理一樣,擇其一瞭解即可。
目錄
1. 斐波那契堆的介紹
2. 斐波那契堆的基本操作
3. 斐波那契堆的Java實現(完整原始碼)
4. 斐波那契堆的Java測試程式
轉載請註明出處:
更多內容:資料結構與算法系列 目錄
(01) 斐波那契堆(一)之 圖文解析 和 C語言的實現
(02) 斐波那契堆(二)之 C++的實現
(03) 斐波那契堆(三)之 Java的實現
斐波那契堆的介紹
斐波那契堆(Fibonacci heap)是一種可合併堆,可用於實現合併優先佇列。它比二項堆具有更好的平攤分析效能,它的合併操作的時間複雜度是O(1)。
與二項堆一樣,它也是由一組堆最小有序樹組成,並且是一種可合併堆。
與二項堆不同的是,斐波那契堆中的樹不一定是二項樹;而且二項堆中的樹是有序排列的,但是斐波那契堆中的樹都是有根而無序的。
斐波那契堆的基本操作
1. 基本定義
public class FibHeap { private int keyNum; // 堆中節點的總數
private FibNode min; // 最小節點(某個最小堆的根節點) private class FibNode {
int key; // 關鍵字(鍵值)
int degree; // 度數
FibNode left; // 左兄弟
FibNode right; // 右兄弟
FibNode child; // 第一個孩子節點
FibNode parent; // 父節點
boolean marked; // 是否被刪除第一個孩子 public FibNode(int key) {
this.key = key;
this.degree = 0;
this.marked = false;
this.left = this;
this.right = this;
this.parent = null;
this.child = null;
}
} ...
}
FibNode是斐波那契堆的節點類,它包含的資訊較多。key是用於比較節點大小的,degree是記錄節點的度,left和right分別是指向節點的左右兄弟,child是節點的第一個孩子,parent是節點的父節點,marked是記錄該節點是否被刪除第1個孩子(marked在刪除節點時有用)。
FibHeap是斐波那契堆對應的類。min是儲存當前堆的最小節點,keyNum用於記錄堆中節點的總數,maxDegree用於記錄堆中最大度,而cons在刪除節點時來暫時儲存堆資料的臨時空間。
上面是斐波那契堆的兩種不同結構圖的對比。從中可以看出,斐波那契堆是由一組最小堆組成,這些最小堆的根節點組成了雙向連結串列(後文稱為"根連結串列");斐波那契堆中的最小節點就是"根連結串列中的最小節點"!
PS. 上面這幅圖的結構和測試程式碼中的"基本資訊"測試函式的結果是一致的;你可以通過測試程式來親自驗證!
2. 插入操作
插入操作非常簡單:插入一個節點到堆中,直接將該節點插入到"根連結串列的min節點"之前即可;若被插入節點比"min節點"小,則更新"min節點"為被插入節點。
上面是插入操作的示意圖。
斐波那契堆的根連結串列是"雙向連結串列",這裡將min節點看作雙向聯表的表頭(後文也是如此)。在插入節點時,每次都是"將節點插入到min節點之前(即插入到雙鏈表末尾)"。此外,對於根連結串列中最小堆都只有一個節點的情況,插入操作就很演化成雙向連結串列的插入操作。
此外,插入操作示意圖與測試程式中的"插入操作"相對應,感興趣的可以親自驗證。
插入操作程式碼
/*
* 將node堆結點加入root結點之前(迴圈連結串列中)
* a …… root
* a …… node …… root
*/
private void addNode(FibNode node, FibNode root) {
node.left = root.left;
root.left.right = node;
node.right = root;
root.left = node;
} /*
* 將節點node插入到斐波那契堆中
*/
private void insert(FibNode node) {
if (keyNum == 0)
min = node;
else {
addNode(node, min);
if (node.key < min.key)
min = node;
} keyNum++;
} /*
* 新建鍵值為key的節點,並將其插入到斐波那契堆中
*/
public void insert(int key) {
FibNode node; node = new FibNode(key);
if (node == null)
return ; insert(node);
}
3. 合併操作
合併操作和插入操作的原理非常類似:將一個堆的根連結串列插入到另一個堆的根連結串列上即可。簡單來說,就是將兩個雙鏈表拼接成一個雙向連結串列。
上面是合併操作的示意圖。該操作示意圖與測試程式中的"合併操作"相對應!
合併操作程式碼
/*
* 將雙向連結串列b連結到雙向連結串列a的後面
*/
private void catList(FibNode a, FibNode b) {
FibNode tmp; tmp = a.right;
a.right = b.right;
b.right.left = a;
b.right = tmp;
tmp.left = b;
} /*
* 將other合併到當前堆中
*/
public void union(FibHeap other) {
if (other==null)
return ; if((this.min) == null) { // this無"最小節點"
this.min = other.min;
this.keyNum = other.keyNum;
other = null;
} else if((other.min) == null) { // this有"最小節點" && other無"最小節點"
other = null;
} else { // this有"最小節點" && other有"最小節點"
// 將"other中根連結串列"新增到"this"中
catList(this.min, other.min) ; if (this.min.key > other.min.key)
this.min = other.min;
this.keyNum += other.keyNum;
other = null;;
}
}
4. 取出最小節點
抽取最小結點的操作是斐波那契堆中較複雜的操作。
(1)將要抽取最小結點的子樹都直接串聯在根表中;
(2)合併所有degree相等的樹,直到沒有相等的degree的樹。
上面是取出最小節點的示意圖。圖中應該寫的非常明白了,若有疑問,看程式碼。
此外,該操作示意圖與測試程式中的"刪除最小節點"相對應!有興趣的可以親自驗證。
取出最小節點程式碼
/*
* 將node連結到root根結點
*/
private void link(FibNode node, FibNode root) {
// 將node從雙鏈表中移除
removeNode(node);
// 將node設為root的孩子
if (root.child == null)
root.child = node;
else
addNode(node, root.child); node.parent = root;
root.degree++;
node.marked = false;
} /*
* 合併斐波那契堆的根連結串列中左右相同度數的樹
*/
private void consolidate() {
// 計算log2(keyNum),floor意味著向上取整!
// ex. log2(13) = 3,向上取整為4。
int maxDegree = (int) Math.floor(Math.log(keyNum) / Math.log(2.0));
int D = maxDegree + 1;
FibNode[] cons = new FibNode[D+1]; for (int i = 0; i < D; i++)
cons[i] = null; // 合併相同度的根節點,使每個度數的樹唯一
while (min != null) {
FibNode x = extractMin(); // 取出堆中的最小樹(最小節點所在的樹)
int d = x.degree; // 獲取最小樹的度數
// cons[d] != null,意味著有兩棵樹(x和y)的"度數"相同。
while (cons[d] != null) {
FibNode y = cons[d]; // y是"與x的度數相同的樹"
if (x.key > y.key) { // 保證x的鍵值比y小
FibNode tmp = x;
x = y;
y = tmp;
} link(y, x); // 將y連結到x中
cons[d] = null;
d++;
}
cons[d] = x;
}
min = null; // 將cons中的結點重新加到根表中
for (int i=0; i<D; i++) { if (cons[i] != null) {
if (min == null)
min = cons[i];
else {
addNode(cons[i], min);
if ((cons[i]).key < min.key)
min = cons[i];
}
}
}
} /*
* 移除最小節點
*/
public void removeMin() {
if (min==null)
return ; FibNode m = min;
// 將min每一個兒子(兒子和兒子的兄弟)都新增到"斐波那契堆的根連結串列"中
while (m.child != null) {
FibNode child = m.child; removeNode(child);
if (child.right == child)
m.child = null;
else
m.child = child.right; addNode(child, min);
child.parent = null;
} // 將m從根連結串列中移除
removeNode(m);
// 若m是堆中唯一節點,則設定堆的最小節點為null;
// 否則,設定堆的最小節點為一個非空節點(m.right),然後再進行調節。
if (m.right == m)
min = null;
else {
min = m.right;
consolidate();
}
keyNum--; m = null;
}
5. 減小節點值
減少斐波那契堆中的節點的鍵值,這個操作的難點是:如果減少節點後破壞了"最小堆"性質,如何去維護呢?下面對一般性情況進行分析。
(1) 首先,將"被減小節點"從"它所在的最小堆"剝離出來;然後將"該節點"關聯到"根連結串列"中。 倘若被減小的節點不是單獨一個節點,而是包含子樹的樹根。則是將以"被減小節點"為根的子樹從"最小堆"中剝離出來,然後將該樹關聯到根連結串列中。
(2) 接著,對"被減少節點"的原父節點進行"級聯剪下"。所謂"級聯剪下",就是在被減小節點破壞了最小堆性質,並被切下來之後;再從"它的父節點"進行遞迴級聯剪下操作。
而級聯操作的具體動作則是:若父節點(被減小節點的父節點)的marked標記為false,則將其設為true,然後退出。
否則,將父節點從最小堆中切下來(方式和"切被減小節點的方式"一樣);然後遞迴對祖父節點進行"級聯剪下"。
marked標記的作用就是用來標記"該節點的子節點是否有被刪除過",它的作用是來實現級聯剪下。而級聯剪下的真正目的是為了防止"最小堆"由二叉樹演化成連結串列。
(3) 最後,別忘了對根連結串列的最小節點進行更新。
上面是減小節點值的示意圖。該操作示意圖與測試程式中的"減小節點"相對應!
減小節點值的程式碼
/*
* 修改度數
*/
private void renewDegree(FibNode parent, int degree) {
parent.degree -= degree;
if (parent. parent != null)
renewDegree(parent.parent, degree);
} /*
* 將node從父節點parent的子連結中剝離出來,
* 並使node成為"堆的根連結串列"中的一員。
*/
private void cut(FibNode node, FibNode parent) {
removeNode(node);
renewDegree(parent, node.degree);
// node沒有兄弟
if (node == node.right)
parent.child = null;
else
parent.child = node.right; node.parent = null;
node.left = node.right = node;
node.marked = false;
// 將"node所在樹"新增到"根連結串列"中
addNode(node, min);
} /*
* 對節點node進行"級聯剪下"
*
* 級聯剪下:如果減小後的結點破壞了最小堆性質,
* 則把它切下來(即從所在雙向連結串列中刪除,並將
* 其插入到由最小樹根節點形成的雙向連結串列中),
* 然後再從"被切節點的父節點"到所在樹根節點遞迴執行級聯剪枝
*/
private void cascadingCut(FibNode node) {
FibNode parent = node.parent; if (parent != null) {
if (node.marked == false)
node.marked = true;
else {
cut(node, parent);
cascadingCut(parent);
}
}
} /*
* 將斐波那契堆中節點node的值減少為key
*/
private void decrease(FibNode node, int key) {
if (min==null ||node==null)
return ; if (key > node.key) {
System.out.printf("decrease failed: the new key(%d) is no smaller than current key(%d)\n", key, node.key);
return ;
} FibNode parent = node.parent;
node.key = key;
if (parent!=null && (node.key < parent.key)) {
// 將node從父節點parent中剝離出來,並將node新增到根連結串列中
cut(node, parent);
cascadingCut(parent);
} // 更新最小節點
if (node.key < min.key)
min = node;
}
6. 增加節點值
增加節點值和減少節點值類似,這個操作的難點也是如何維護"最小堆"性質。思路如下:
(1) 將"被增加節點"的"左孩子和左孩子的所有兄弟"都連結到根連結串列中。
(2) 接下來,把"被增加節點"新增到根連結串列;但是別忘了對其進行級聯剪下。
上面是增加節點值的示意圖。該操作示意圖與測試程式中的"增大節點"相對應!
增加節點值的程式碼
/*
* 將斐波那契堆中節點node的值增加為key
*/
private void increase(FibNode node, int key) {
if (min==null ||node==null)
return ; if ( key <= node.key) {
System.out.printf("increase failed: the new key(%d) is no greater than current key(%d)\n", key, node.key);
return ;
} // 將node每一個兒子(不包括孫子,重孫,...)都新增到"斐波那契堆的根連結串列"中
while (node.child != null) {
FibNode child = node.child;
removeNode(child); // 將child從node的子連結串列中刪除
if (child.right == child)
node.child = null;
else
node.child = child.right; addNode(child, min); // 將child新增到根連結串列中
child.parent = null;
}
node.degree = 0;
node.key = key; // 如果node不在根連結串列中,
// 則將node從父節點parent的子連結中剝離出來,
// 並使node成為"堆的根連結串列"中的一員,
// 然後進行"級聯剪下"
// 否則,則判斷是否需要更新堆的最小節點
FibNode parent = node.parent;
if(parent != null) {
cut(node, parent);
cascadingCut(parent);
} else if(min == node) {
FibNode right = node.right;
while(right != node) {
if(node.key > right.key)
min = right;
right = right.right;
}
}
}
7. 刪除節點
刪除節點,本文采用了操作是:"取出最小節點"和"減小節點值"的組合。
(1) 先將被刪除節點的鍵值減少。減少後的值要比"原最小節點的值"即可。
(2) 接著,取出最小節點即可。
刪除節點值的程式碼
/*
* 刪除結點node
*/
private void remove(FibNode node) {
int m = min.key;
decrease(node, m-1);
removeMin();
}
注意:關於斐波那契堆的"更新"、"列印"、"銷燬"等介面就不再單獨介紹了。後文的原始碼中有給出它們的實現程式碼,Please RTFSC(Read The Fucking Source Code)!
斐波那契堆的Java實現(完整原始碼)
斐波那契堆的實現檔案(FibHeap.java)
/**
* Java 語言: 斐波那契堆
*
* @author skywang
* @date 2014/04/07
*/ public class FibHeap { private int keyNum; // 堆中節點的總數
private FibNode min; // 最小節點(某個最小堆的根節點) private class FibNode {
int key; // 關鍵字(鍵值)
int degree; // 度數
FibNode left; // 左兄弟
FibNode right; // 右兄弟
FibNode child; // 第一個孩子節點
FibNode parent; // 父節點
boolean marked; // 是否被刪除第一個孩子 public FibNode(int key) {
this.key = key;
this.degree = 0;
this.marked = false;
this.left = this;
this.right = this;
this.parent = null;
this.child = null;
}
} public FibHeap() {
this.keyNum = 0;
this.min = null;
} /*
* 將node從雙鏈表移除
*/
private void removeNode(FibNode node) {
node.left.right = node.right;
node.right.left = node.left;
} /*
* 將node堆結點加入root結點之前(迴圈連結串列中)
* a …… root
* a …… node …… root
*/
private void addNode(FibNode node, FibNode root) {
node.left = root.left;
root.left.right = node;
node.right = root;
root.left = node;
} /*
* 將節點node插入到斐波那契堆中
*/
private void insert(FibNode node) {
if (keyNum == 0)
min = node;
else {
addNode(node, min);
if (node.key < min.key)
min = node;
} keyNum++;
} /*
* 新建鍵值為key的節點,並將其插入到斐波那契堆中
*/
public void insert(int key) {
FibNode node; node = new FibNode(key);
if (node == null)
return ; insert(node);
} /*
* 將雙向連結串列b連結到雙向連結串列a的後面
*/
private void catList(FibNode a, FibNode b) {
FibNode tmp; tmp = a.right;
a.right = b.right;
b.right.left = a;
b.right = tmp;
tmp.left = b;
} /*
* 將other合併到當前堆中
*/
public void union(FibHeap other) {
if (other==null)
return ; if((this.min) == null) { // this無"最小節點"
this.min = other.min;
this.keyNum = other.keyNum;
other = null;
} else if((other.min) == null) { // this有"最小節點" && other無"最小節點"
other = null;
} else { // this有"最小節點" && other有"最小節點"
// 將"other中根連結串列"新增到"this"中
catList(this.min, other.min) ; if (this.min.key > other.min.key)
this.min = other.min;
this.keyNum += other.keyNum;
other = null;;
}
} /*
* 將"堆的最小結點"從根連結串列中移除,
* 這意味著"將最小節點所屬的樹"從堆中移除!
*/
private FibNode extractMin() {
FibNode p = min; if (p == p.right)
min = null;
else {
removeNode(p);
min = p.right;
}
p.left = p.right = p; return p;
} /*
* 將node連結到root根結點
*/
private void link(FibNode node, FibNode root) {
// 將node從雙鏈表中移除
removeNode(node);
// 將node設為root的孩子
if (root.child == null)
root.child = node;
else
addNode(node, root.child); node.parent = root;
root.degree++;
node.marked = false;
} /*
* 合併斐波那契堆的根連結串列中左右相同度數的樹
*/
private void consolidate() {
// 計算log2(keyNum),floor意味著向上取整!
// ex. log2(13) = 3,向上取整為4。
int maxDegree = (int) Math.floor(Math.log(keyNum) / Math.log(2.0));
int D = maxDegree + 1;
FibNode[] cons = new FibNode[D+1]; for (int i = 0; i < D; i++)
cons[i] = null; // 合併相同度的根節點,使每個度數的樹唯一
while (min != null) {
FibNode x = extractMin(); // 取出堆中的最小樹(最小節點所在的樹)
int d = x.degree; // 獲取最小樹的度數
// cons[d] != null,意味著有兩棵樹(x和y)的"度數"相同。
while (cons[d] != null) {
FibNode y = cons[d]; // y是"與x的度數相同的樹"
if (x.key > y.key) { // 保證x的鍵值比y小
FibNode tmp = x;
x = y;
y = tmp;
} link(y, x); // 將y連結到x中
cons[d] = null;
d++;
}
cons[d] = x;
}
min = null; // 將cons中的結點重新加到根表中
for (int i=0; i<D; i++) { if (cons[i] != null) {
if (min == null)
min = cons[i];
else {
addNode(cons[i], min);
if ((cons[i]).key < min.key)
min = cons[i];
}
}
}
} /*
* 移除最小節點
*/
public void removeMin() {
if (min==null)
return ; FibNode m = min;
// 將min每一個兒子(兒子和兒子的兄弟)都新增到"斐波那契堆的根連結串列"中
while (m.child != null) {
FibNode child = m.child; removeNode(child);
if (child.right == child)
m.child = null;
else
m.child = child.right; addNode(child, min);
child.parent = null;
} // 將m從根連結串列中移除
removeNode(m);
// 若m是堆中唯一節點,則設定堆的最小節點為null;
// 否則,設定堆的最小節點為一個非空節點(m.right),然後再進行調節。
if (m.right == m)
min = null;
else {
min = m.right;
consolidate();
}
keyNum--; m = null;
} /*
* 獲取斐波那契堆中最小鍵值;失敗返回-1
*/
public int minimum() {
if (min==null)
return -1; return min.key;
} /*
* 修改度數
*/
private void renewDegree(FibNode parent, int degree) {
parent.degree -= degree;
if (parent. parent != null)
renewDegree(parent.parent, degree);
} /*
* 將node從父節點parent的子連結中剝離出來,
* 並使node成為"堆的根連結串列"中的一員。
*/
private void cut(FibNode node, FibNode parent) {
removeNode(node);
renewDegree(parent, node.degree);
// node沒有兄弟
if (node == node.right)
parent.child = null;
else
parent.child = node.right; node.parent = null;
node.left = node.right = node;
node.marked = false;
// 將"node所在樹"新增到"根連結串列"中
addNode(node, min);
} /*
* 對節點node進行"級聯剪下"
*
* 級聯剪下:如果減小後的結點破壞了最小堆性質,
* 則把它切下來(即從所在雙向連結串列中刪除,並將
* 其插入到由最小樹根節點形成的雙向連結串列中),
* 然後再從"被切節點的父節點"到所在樹根節點遞迴執行級聯剪枝
*/
private void cascadingCut(FibNode node) {
FibNode parent = node.parent; if (parent != null) {
if (node.marked == false)
node.marked = true;
else {
cut(node, parent);
cascadingCut(parent);
}
}
} /*
* 將斐波那契堆中節點node的值減少為key
*/
private void decrease(FibNode node, int key) {
if (min==null ||node==null)
return ; if (key > node.key) {
System.out.printf("decrease failed: the new key(%d) is no smaller than current key(%d)\n", key, node.key);
return ;
} FibNode parent = node.parent;
node.key = key;
if (parent!=null && (node.key < parent.key)) {
// 將node從父節點parent中剝離出來,並將node新增到根連結串列中
cut(node, parent);
cascadingCut(parent);
} // 更新最小節點
if (node.key < min.key)
min = node;
} /*
* 將斐波那契堆中節點node的值增加為key
*/
private void increase(FibNode node, int key) {
if (min==null ||node==null)
return ; if ( key <= node.key) {
System.out.printf("increase failed: the new key(%d) is no greater than current key(%d)\n", key, node.key);
return ;
} // 將node每一個兒子(不包括孫子,重孫,...)都新增到"斐波那契堆的根連結串列"中
while (node.child != null) {
FibNode child = node.child;
removeNode(child); // 將child從node的子連結串列中刪除
if (child.right == child)
node.child = null;
else
node.child = child.right; addNode(child, min); // 將child新增到根連結串列中
child.parent = null;
}
node.degree = 0;
node.key = key; // 如果node不在根連結串列中,
// 則將node從父節點parent的子連結中剝離出來,
// 並使node成為"堆的根連結串列"中的一員,
// 然後進行"級聯剪下"
// 否則,則判斷是否需要更新堆的最小節點
FibNode parent = node.parent;
if(parent != null) {
cut(node, parent);
cascadingCut(parent);
} else if(min == node) {
FibNode right = node.right;
while(right != node) {
if(node.key > right.key)
min = right;
right = right.right;
}
}
} /*
* 更新斐波那契堆的節點node的鍵值為key
*/
private void update(FibNode node, int key) {
if(key < node.key)
decrease(node, key);
else if(key > node.key)
increase(node, key);
else
System.out.printf("No need to update!!!\n");
} public void update(int oldkey, int newkey) {
FibNode node; node = search(oldkey);
if (node!=null)
update(node, newkey);
} /*
* 在最小堆root中查詢鍵值為key的節點
*/
private FibNode search(FibNode root, int key) {
FibNode t = root; // 臨時節點
FibNode p = null; // 要查詢的節點 if (root==null)
return root; do {
if (t.key == key) {
p = t;
break;
} else {
if ((p = search(t.child, key)) != null)
break;
}
t = t.right;
} while (t != root); return p;
} /*
* 在斐波那契堆中查詢鍵值為key的節點
*/
private FibNode search(int key) {
if (min==null)
return null; return search(min, key);
} /*
* 在斐波那契堆中是否存在鍵值為key的節點。
* 存在返回true,否則返回false。
*/
public boolean contains(int key) {
return search(key)!=null ? true: false;
} /*
* 刪除結點node
*/
private void remove(FibNode node) {
int m = min.key;
decrease(node, m-1);
removeMin();
} public void remove(int key) {
if (min==null)
return ; FibNode node = search(key);
if (node==null)
return ; remove(node);
} /*
* 銷燬斐波那契堆
*/
private void destroyNode(FibNode node) {
if(node == null)
return; FibNode start = node;
do {
destroyNode(node.child);
// 銷燬node,並將node指向下一個
node = node.right;
node.left = null;
} while(node != start);
} public void destroy() {
destroyNode(min);
} /*
* 列印"斐波那契堆"
*
* 引數說明:
* node -- 當前節點
* prev -- 當前節點的前一個節點(父節點or兄弟節點)
* direction -- 1,表示當前節點是一個左孩子;
* 2,表示當前節點是一個兄弟節點。
*/
private void print(FibNode node, FibNode prev, int direction) {
FibNode start=node; if (node==null)
return ;
do {
if (direction == 1)
System.out.printf("%8d(%d) is %2d's child\n", node.key, node.degree, prev.key);
else
System.out.printf("%8d(%d) is %2d's next\n", node.key, node.degree, prev.key); if (node.child != null)
print(node.child, node, 1); // 兄弟節點
prev = node;
node = node.right;
direction = 2;
} while(node != start);
} public void print() {
if (min==null)
return ; int i=0;
FibNode p = min;
System.out.printf("== 斐波那契堆的詳細資訊: ==\n");
do {
i++;
System.out.printf("%2d. %4d(%d) is root\n", i, p.key, p.degree); print(p.child, p, 1);
p = p.right;
} while (p != min);
System.out.printf("\n");
}
}
斐波那契堆的測試程式(Main.java)
/**
* Java 語言: 斐波那契堆
*
* @author skywang
* @date 2014/04/07
*/ public class Main { private static final boolean DEBUG = false; // 共8個
private static int a[] = {12, 7, 25, 15, 28, 33, 41, 1};
// 共14個
private static int b[] = {18, 35, 20, 42, 9,
31, 23, 6, 48, 11,
24, 52, 13, 2 }; // 驗證"基本資訊(斐波那契堆的結構)"
public static void testBasic() {
FibHeap hb=new FibHeap(); // 斐波那契堆hb
System.out.printf("== 斐波那契堆(hb)中依次新增: ");
for(int i=0; i<b.length; i++) {
System.out.printf("%d ", b[i]);
hb.insert(b[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(hb)刪除最小節點\n");
hb.removeMin();
hb.print(); // 列印斐波那契堆hb
} // 驗證"插入操作"
public static void testInsert() {
FibHeap ha=new FibHeap(); // 斐波那契堆ha
System.out.printf("== 斐波那契堆(ha)中依次新增: ");
for(int i=0; i<a.length; i++) {
System.out.printf("%d ", a[i]);
ha.insert(a[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(ha)刪除最小節點\n");
ha.removeMin();
ha.print(); // 列印斐波那契堆ha System.out.printf("== 插入50\n");
ha.insert(50);
ha.print();
} // 驗證"合併操作"
public static void testUnion() {
FibHeap ha=new FibHeap();
FibHeap hb=new FibHeap(); // 斐波那契堆ha
System.out.printf("== 斐波那契堆(ha)中依次新增: ");
for(int i=0; i<a.length; i++) {
System.out.printf("%d ", a[i]);
ha.insert(a[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(ha)刪除最小節點\n");
ha.removeMin();
ha.print(); // 列印斐波那契堆ha // 斐波那契堆hb
System.out.printf("== 斐波那契堆(hb)中依次新增: ");
for(int i=0; i<b.length; i++) {
System.out.printf("%d ", b[i]);
hb.insert(b[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(hb)刪除最小節點\n");
hb.removeMin();
hb.print(); // 列印斐波那契堆hb // 將"斐波那契堆hb"合併到"斐波那契堆ha"中。
System.out.printf("== 合併ha和hb\n");
ha.union(hb);
ha.print();
} // 驗證"刪除最小節點"
public static void testRemoveMin() {
FibHeap ha=new FibHeap();
FibHeap hb=new FibHeap(); // 斐波那契堆ha
System.out.printf("== 斐波那契堆(ha)中依次新增: ");
for(int i=0; i<a.length; i++) {
System.out.printf("%d ", a[i]);
ha.insert(a[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(ha)刪除最小節點\n");
ha.removeMin();
//ha.print(); // 列印斐波那契堆ha // 斐波那契堆hb
System.out.printf("== 斐波那契堆(hb)中依次新增: ");
for(int i=0; i<b.length; i++) {
System.out.printf("%d ", b[i]);
hb.insert(b[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(hb)刪除最小節點\n");
hb.removeMin();
//hb.print(); // 列印斐波那契堆hb // 將"斐波那契堆hb"合併到"斐波那契堆ha"中。
System.out.printf("== 合併ha和hb\n");
ha.union(hb);
ha.print(); System.out.printf("== 刪除最小節點\n");
ha.removeMin();
ha.print();
} // 驗證"減小節點"
public static void testDecrease() {
FibHeap hb=new FibHeap(); // 斐波那契堆hb
System.out.printf("== 斐波那契堆(hb)中依次新增: ");
for(int i=0; i<b.length; i++) {
System.out.printf("%d ", b[i]);
hb.insert(b[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(hb)刪除最小節點\n");
hb.removeMin();
hb.print(); // 列印斐波那契堆hb System.out.printf("== 將20減小為2\n");
hb.update(20, 2);
hb.print();
} // 驗證"增大節點"
public static void testIncrease() {
FibHeap hb=new FibHeap(); // 斐波那契堆hb
System.out.printf("== 斐波那契堆(hb)中依次新增: ");
for(int i=0; i<b.length; i++) {
System.out.printf("%d ", b[i]);
hb.insert(b[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(hb)刪除最小節點\n");
hb.removeMin();
hb.print(); // 列印斐波那契堆hb System.out.printf("== 將20增加為60\n");
hb.update(20, 60);
hb.print();
} // 驗證"刪除節點"
public static void testDelete() {
FibHeap hb=new FibHeap(); // 斐波那契堆hb
System.out.printf("== 斐波那契堆(hb)中依次新增: ");
for(int i=0; i<b.length; i++) {
System.out.printf("%d ", b[i]);
hb.insert(b[i]);
}
System.out.printf("\n");
System.out.printf("== 斐波那契堆(hb)刪除最小節點\n");
hb.removeMin();
hb.print(); // 列印斐波那契堆hb System.out.printf("== 刪除節點20\n");
hb.remove(20);
hb.print();
} public static void main(String[] args) {
// 驗證"基本資訊(斐波那契堆的結構)"
testBasic();
// 驗證"插入操作"
//testInsert();
// 驗證"合併操作"
//testUnion();
// 驗證"刪除最小節點"
//testRemoveMin();
// 驗證"減小節點"
//testDecrease();
// 驗證"增大節點"
//testIncrease();
// 驗證"刪除節點"
//testDelete();
}
}
斐波那契堆的Java測試程式
斐波那契堆的測試程式包括了"插入"、"合併"、"增大"、"減小"、"刪除"、"基本資訊"等幾種功能的測試程式碼。預設是執行的"基本資訊(驗證斐波那契堆的結構)"測試程式碼,你可以根據自己的需要來對相應的功能進行驗證!
下面是基本資訊測試程式碼的執行結果:
== 斐波那契堆(hb)中依次新增: 18 35 20 42 9 31 23 6 48 11 24 52 13 2
== 斐波那契堆(hb)刪除最小節點
== 斐波那契堆的詳細資訊: ==
1. 6(3) is root
9(0) is 6's child
18(1) is 9's next
35(0) is 18's child
20(2) is 18's next
42(0) is 20's child
23(1) is 42's next
31(0) is 23's child
2. 11(2) is root
48(0) is 11's child
24(1) is 48's next
52(0) is 24's child
3. 13(0) is root