1. 优先队列(自己实现的堆)用于Prim
package heap;
import java.util.Scanner;
public class MST {
static int[] dis;
static int[] graph_heap; //映射数组 graph-->heap
private static final int MAX = 999999;
static class Heap{
int[] h;
int size; //size == (heap的元素个数)
Heap(int size) {
this.size = size;
h = new int[size+1]; //你的数组都是从1开始的
}
void siftDown(int i){
int t;
boolean flag = true; //标记是否需要继续往下移
while (i * 2 <= size && flag) { //如果有儿子(至少有一个左儿子)
if (dis[h[i]] > dis[h[2 * i]]) {
t = 2 * i;
}
else
t = i;
//如果i还有右儿子
if ((i * 2 + 1) <= size) {
if (dis[h[t]] > dis[h[2 * i + 1]]) {
t = 2*i+1;
}
}
if (t != i) {
swap(t, i);
i = t; //更新i为它的儿子的编号, 因为接下来要继续调整
}
else if (t == i )// 说明父亲比孩子小, 满足最小堆, 不需要再继续向下调整
flag = false;
}
}
void siftUp(int i){
boolean flag = true;
if (i == 1) return; //i==1, 表明是堆顶
while (i != 1 && flag) {
//System.out.println(i); //debug
if (dis[h[i]] < dis[h[i / 2]]) {
swap(i, i/2);
i = i/2; //更新i为他的父亲编号, 以便下一次进行调整操作
}
else //儿子比父亲大, 满足最小堆, 不需要再向上调整了
flag = false;
}
}
//交换堆数组俩个元素的值
void swap(int a, int b){
int tmp = h[a];
h[a] = h[b];
h[b] = tmp;
//同步更新映射数组graph_heap
tmp = graph_heap[h[a]];
graph_heap[h[a]] = graph_heap[h[b]];
graph_heap[h[b]] = tmp;
}
int pop(){
int ans = h[1]; //ans表示在graph中的编号
h[1] = h[size]; //把堆中最后一个元素赋值给第一个元素
graph_heap[h[size]] = 1; //更新映射数组, 把堆中编号最大的node对应的graph, 映射数组
size--;
siftDown(1);
return ans;
}
void createHeap(){
for (int i = size / 2; i >= 1; i--) {
siftDown(i);
}
}
}
static class Node{
int idx;
int weight;
Node next;
Node(int idx, int weight) {
this.idx = idx;
this.weight = weight;
}
}
/*
邻接表存储图
*/
static class Graph{
int num_ver;
int num_edge;
Node[] links;
Graph(int num_ver, int num_edge) {
this.num_ver = num_ver;
this.num_edge = num_edge;
links = new Node[num_ver+1]; //你的数组都是从1开始的
for (int i = 1; i <= num_ver; i++) { //i从1开始, i<=num_ver
links[i] = new Node(i,0);
}
}
void createGraph(int u, int v, int w) { //u---->v
Node n = new Node(v,w);
Node tmp = links[u].next; //链表, 用一个临时变量存数据, 防止丢失
links[u].next = n;
n.next = tmp; //头插法
Node m = new Node(u,w);
Node tmp_ = links[v].next; //链表, 用一个临时变量存数据, 防止丢失
links[v].next = m;
m.next = tmp_; //头插法
}
Node getLink(int i) {
return links[i];
}
}
public static void main(String[] args) {
int a,b; //a:node个数, b:边数
Scanner in = new Scanner(System.in);
a= in.nextInt();
b= in.nextInt();
Graph graph = new Graph(a,b);
int n,m,w;
while (b != 0) {
b--;
n = in.nextInt();
m = in.nextInt();
w = in.nextInt();
graph.createGraph(n,m,w);
}
//初始化dis数组, 刚开始生成树只有node(1)
dis = new int[a+1];
dis[1] = 0;
for (int i = 2; i <= a; i++) { //i=2从node(2)开始
dis[i] = MAX;
}
Node tmp_ = graph.links[1].next;
while (tmp_ != null) {
dis[tmp_.idx] = tmp_.weight; //刚开始从node(1)开始生成最小生成树
tmp_ = tmp_.next;
}
//建立堆
graph_heap = new int[a+1];
Heap heap = new Heap(a);
for (int i = 1; i <= a; i++) {
heap.h[i] = i;
graph_heap[i] = i;
}
heap.createHeap();
heap.pop(); //把node(1)弹出,
int cnt = 1;
boolean[] book = new boolean[a+1];
book[1] = true;
//for (int i=1; i< book.length; i++) book[i] = false; //boolean数组初始值都是false
int sum = 0;
while (cnt < a) { //a:num_node
int g_idx = heap.pop(); //第一次循环,
System.out.println("here is: "+g_idx); //Debug
book[g_idx] = true;
cnt++;
sum += dis[g_idx];
Node tmp = graph.links[g_idx].next;
while (tmp != null) {
if (!(book[tmp.idx]) && dis[tmp.idx] > tmp.weight) { //idx: node在graph中的索引或者说编号
dis[tmp.idx] = tmp.weight;
//dis[tmp.idx] 变小, 向上调整
//System.out.println("here is childs:"+tmp.idx); //for testing
//System.out.println(graph_heap[tmp.idx]); //for testing
//System.out.println("here is dis["+tmp.idx+"]: " + dis[tmp.idx]);
heap.siftUp(graph_heap[tmp.idx]); //把graph里面Node的编号, 转化为heap的node的编号
}
tmp = tmp.next;
}
}
System.out.println(sum);
} //close main()
}
input: 无向图,6和9表示这个图6个node, 9个edge 举个例子: 测试用例2 4 11, 表示编号为2与编号为4的边权重为11
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
output:
19
2. 斐波那契堆
2.1 二项树与二项堆(二项队列)