斐波那契堆的java实现

介绍

斐波那契堆的基础理论在算法导论第三版第19章有详细介绍,这里不再赘述。

斐波那契堆 VS 二项堆

斐波那契堆与二项堆相比,在插入和堆合并上,有显著优势。
在这里插入图片描述

代码实现


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;
import java.util.function.Consumer;

/**
 * 斐波那锲堆
 *
 * @author: zyp
 * @since: 2022/1/18 上午10:36
 */
public class FibHeap<T> {
    private TreeMap<Integer, Node> indexMap = new TreeMap<>();
    private int fib1 = 1;
    private int fib2 = 2;
    private Node<T> min;
    private int size; // 节点数
    private int degree;


    /**
     * O(1)
     */

    public void insert(int key, T value) {
        Node node = indexMap.get(key);
        if (node != null) {
            return;
        }
        node = new Node(key, value);
        indexMap.put(key, node);
        if (min == null) {
            min = node;
        } else {
            min.insertLeft(node);
            if (node.key < min.key) {
                min = node;
            }
        }
        addSize();
    }

    /**
     * O(1)
     */

    public void clear() {
        fib1 = 1;
        fib2 = 2;
        size = 0;
        degree = 0;
        min = null;
        indexMap.clear();
    }

    /**
     * O(1)
     */
    public void union(FibHeap heap) {
        if (heap == null || heap.min == null) {
            return;
        }
        min.insertLeft(heap.min);
        if (heap.min.key < min.key) {
            min = heap.min;
        }
        if (size > heap.size) {
            addSize(heap.size);
        } else {
            fib1 = heap.fib1;
            fib2 = heap.fib2;
            degree = heap.degree;
            int tn = size;
            size = heap.size;
            addSize(tn);
        }
    }

    /**
     * O(1)
     */

    public Integer peek() {
        if (min == null) {
            return null;
        }
        return min.key;
    }

    public Entry<T> peekEntry() {
        if (min == null) {
            return null;
        }
        return min.toEntry();
    }

    /**
     * O(lgn)
     */

    public Integer poll() {
        Node node = popMinNode();
        if (node == null) {
            return null;
        }
        return node.key;
    }

    public Entry<T> pollEntry() {
        Node node = popMinNode();
        if (node == null) {
            return null;
        }
        return node.toEntry();
    }

    public int size() {
        return size;
    }

    /**
     * O(1)
     */

    public void decreaseBy(int key, int change) {
        if (change == 0) {
            return;
        }
        if (change < 0) {
            throw new IllegalArgumentException("change不能为负数");
        }
        Node node = indexMap.get(key);
        if (node == null) {
            return;
        }
        decreaseKey(node, key - change);
    }

    /**
     * O(lgn)
     */

    public boolean delete(int key) {
        Node node = indexMap.get(key);
        if (node == null) {
            return false;
        }
        delete(node);
        return true;
    }


    public void validate() {
        if (size != indexMap.size()) {
            throw new RuntimeException("size 错误");
        }
        if (size != count()) {
            throw new RuntimeException(String.format("size 错误, size=%s, count=%s", size, count()));
        }
        if (size > 0) {
            if (peek().intValue() != indexMap.firstKey()) {
                throw new RuntimeException("peek 错误");
            }
        }
    }


    public void print() {
        System.out.println(String.format("============ size=%s,degree=%s ============", size, degree));
        StringBuilder sb = new StringBuilder();
        print(sb, min);
        print(sb.toString());
    }

    private void print(String str) {
//        System.out.println(str);
        List<char[]> lines = new ArrayList<>();
        int len = str.length();
        int line = -1;
        for (int pos = 0; pos < len; pos++) {
            char c = str.charAt(pos);
            if (c == '(') {
                line++;
                getLine(lines, len, line)[pos] = c;
            } else if (c == ')') {
                getLine(lines, len, line)[pos] = c;
                line--;
            } else {
                getLine(lines, len, line)[pos] = c;
            }
        }
        for (char[] chars : lines) {
            System.out.println(new String(chars));
        }
    }

    private char[] getLine(List<char[]> lines, int len, int line) {
        if (line < lines.size()) {
            return lines.get(line);
        } else {
            char[] data = new char[len];
            Arrays.fill(data, ' ');
            lines.add(data);
            return data;
        }
    }

    private void print(StringBuilder sb, Node node) {
        if (node == null) {
            return;
        }
        sb.append("(");
        Node first = node;
        Node cur = first;
        do {
            sb.append(cur.key);
            if (cur.child != null) {
                print(sb, cur.child);
            }
            sb.append(",");
            cur = cur.right;
        } while (cur != first);
        if (sb.charAt(sb.length() - 1) == ',') {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append(")");
    }

    /**
     * 将node作为环形链表的中间节点, 返回环形链表最左边的节点
     * 如果节点数是偶数, 右边会多一个节点
     */
    private Node findLeft(Node node) {
        if (node.left == node) {
//            1个节点
            return node;
        }
        Node left = node.left;
        Node right = node.right;
//        3个及以上
        do {
            if (left == right) {
                return left.right;
            }
            if (left.left == right) {
                return left;
            }
            left = left.left;
            right = right.right;
        } while (true);
    }


    private void changeNodeKey(Node node, int key) {
        indexMap.remove(node.key);
        node.key = key;
        indexMap.put(key, node);
    }

    private void delete(Node node) {
        decreaseKey(node, Integer.MIN_VALUE); // 减到最小值, min也不一定是这个节点
        min = node; // 最小节点设置为node
        popMinNode(); // 弹出最小节点
    }

    private int count() {
        if (min == null) {
            return 0;
        }
        return count(null, min);
    }

    private int count(Node parent, Node node) {
        if (node == null) {
            return 0;
        }
        int count = 0;
        Node cur = node;
        do {
            if (cur.parent != parent) {
                throw new RuntimeException(String.format("parent错误. parent=%s, child=%s, child.parent=%s", parent, cur, cur.parent));
            }
            count++;
            count += count(cur, cur.child);
            cur = cur.right;
        } while (cur != node);
        return count;
    }

    private void addSize() {
        addSize(1);
    }

    private void addSize(int inc) {
        size += inc;
        while (size >= fib2) {
            int t2 = fib2;
            fib2 = fib1 + fib2;
            fib1 = t2;
            degree++;
        }
    }

    private void subSize() {
        if (size == 1) {
            clear();
            return;
        }
        size--;
        if (size < fib1) {
            int t1 = fib1;
            fib1 = fib2 - fib1;
            fib2 = t1;
            degree--;
        }
    }


    //    将node.key减小到key
    private void decreaseKey(Node node, int decreaseTo) {
        Node exist = indexMap.get(decreaseTo);
        if (exist != null) {
            delete(node);
            return;
        }
        changeNodeKey(node, decreaseTo);
        if (node == min) {
            return;
        }
        Node parent = node.parent;
        removeFromList(node);
        min.insertLeft(node);
        if (parent != null && node.key < parent.key) {
            cut(node);
        }
        if (node.key < min.key) {
            min = node;
        }
    }

    //    级联切断
    private void cascadingCut(Node node) {
        Node parent = node.parent;
        if (parent == null) {
            return;
        }
        if (!node.mark) {
            node.mark = true;
            return;
        }
        cut(node);
    }

    //    切断
    private void cut(Node node) {
        Node parent = node.parent;
        if (parent == null) {
            return;
        }
        node.parent = null;
        if (node.isSingle()) {
            parent.degree--;
            parent.child = null;
        } else {
            if (parent.child == node) {
                parent.child = node.right;
            }
            removeFromList(node);
        }
        min.insertLeft(node);
        node.mark = false;
        cascadingCut(parent);
    }

    //    提取最小节点
    private Node popMinNode() {
        Node z = min;
        if (z == null) {
            return null;
        }
        indexMap.remove(z.key);
        if (z.child != null) {
            z.insertLeft(z.child); // 把z的所有孩子插入到根链表
            min = z.right;
            z.child = null;
        }
        removeFromList(z);
        consolidate();
        subSize();
        return z;
    }

    private void removeFromList(Node node) {
        Node parent = node.parent;
        if (parent == null) {
//            在根链表上
            if (node.isSingle()) {
//                只有一个节点
                min = null;
                return;
            }
            if (min == node) {
                min = node.right;
            }
        } else {
            parent.degree--;
//            不在根链表上
            if (node.isSingle()) {
//                只有一个节点
                parent.child = null;
                node.parent = null;
                return;
            }
            if (parent.child == node) {
                parent.child = node.right;
            }
            node.parent = null;
        }
        Node left = node.left;
        Node right = node.right;
        left.right = right;
        right.left = left;
        node.left = node;
        node.right = node;
    }

    //    把child设置成parent的孩子, child链表只允许1个元素
    private void link(Node parent, Node child) {
        if (child.left != child) {
            throw new IllegalArgumentException("link.child只允许1个元素");
        }
        if (parent.child == null) {
            parent.child = child;
            parent.degree = 1;
            loopList(child, i -> i.parent = parent);
        } else {
            parent.child.insertLeft(child);
            parent.degree++;
        }
        child.mark = false;
    }

    private void consolidate() {
        if (min == null) {
            return;
        }
        Node[] degrees = new Node[degree + 1];
        Node cur = min;
        while (true) {
            int degree = cur.degree;
            Node node = degrees[degree];
            if (node == null) {
                degrees[degree] = cur;
                cur = cur.right;
            } else if (node == cur) {
                break;
            } else {
                while (node != null) {
                    degrees[degree] = null;
                    if (node.key > cur.key) {
                        removeFromList(node);
                        link(cur, node);
                    } else {
                        removeFromList(cur);
                        link(node, cur);
                        cur = node;
                    }
                    degree++;
                    node = degrees[degree];
                }
            }
        }
        min = findMinNodeInList(cur);
    }

    //    从环形链表上找到最小节点
    private Node findMinNodeInList(Node node) {
        Node min = node;
        Node cur = node.right;
        while (cur != node) {
            if (cur.key < min.key) {
                min = cur;
            }
            cur = cur.right;
        }
        return min;
    }

    public static class Entry<T> {
        private int key;
        private T value;

        public Entry(int key, T value) {
            this.key = key;
            this.value = value;
        }
    }

    public static class Node<T> {
        private Node parent;
        private Node left;
        private Node right;
        private Node child;
        private int degree;
        private boolean mark;
        private int key;
        private T value;

        public Node(int key, T value) {
            this.key = key;
            this.value = value;
            left = this;
            right = this;
        }

        public Entry<T> toEntry() {
            return new Entry<>(key, value);
        }

        //        将环形链表node插入到当前节点的左边
//        node是环形链表的最右边节点, node.right是环形链表的最左边节点
        public void insertLeft(Node node) {
            loopList(node, i -> i.parent = this.parent);
            if (node.isSingle()) {
//               单个节点
                left.right = node;
                node.left = left;
                node.right = this;
                left = node;
            } else {
//                多个节点
                Node first = node.right;
                Node last = node;
                left.right = first;
                first.left = left;
                last.right = this;
                left = last;
            }
        }


        //        是否是单个节点
        public boolean isSingle() {
            return left == this;
        }


        public String toString() {
            return String.format("%s,%s", key, degree);
        }
    }

    //        遍历环形链表
    private static void loopList(Node node, Consumer<Node> consumer) {
        if (node == null) {
            return;
        }
        Node cur = node;
        do {
            consumer.accept(cur);
            cur = cur.right;
        } while (cur != node);
    }

}
斐波那契是一种数据结构,用于实现优先级队列。下面是一个简单的斐波那契Java 实现: ```java import java.util.*; public class FibonacciHeap<T> { private Node<T> maxNode; private int size; // 节点定义 private static class Node<T> { T key; int degree; boolean marked; Node<T> parent; Node<T> child; Node<T> left; Node<T> right; public Node(T key) { this.key = key; left = this; right = this; } } // 插入节点 public void insert(T key) { Node<T> node = new Node<>(key); if (maxNode != null) { node.left = maxNode; node.right = maxNode.right; maxNode.right = node; node.right.left = node; if (compare(node, maxNode) > 0) { maxNode = node; } } else { maxNode = node; } size++; } // 合并两个斐波那契 private void merge(FibonacciHeap<T> other) { if (other.maxNode == null) { return; } if (maxNode == null) { maxNode = other.maxNode; size = other.size; return; } Node<T> leftNode = maxNode.left; Node<T> rightNode = other.maxNode.right; maxNode.left = rightNode; rightNode.left = leftNode; leftNode.right = rightNode; rightNode.right = maxNode; if (compare(other.maxNode, maxNode) > 0) { maxNode = other.maxNode; } size += other.size; } // 提取最大节点 public T extractMax() { Node<T> max = maxNode; if (max != null) { // 将最大节点的子节点移动到根列表中 Node<T> child = max.child; while (child != null) { Node<T> nextChild = child.right; child.left = maxNode; child.right = maxNode.right; maxNode.right = child; child.right.left = child; child.parent = null; child = nextChild; } // 从根列表中移除最大节点 max.left.right = max.right; max.right.left = max.left; if (max == max.right) { maxNode = null; } else { maxNode = max.right; consolidate(); } size--; return max.key; } return null; } // 合并度数相同的树 private void consolidate() { int maxSize = (int) Math.floor(Math.log(size) / Math.log(2)) + 1; List<Node<T>> degreeTable = new ArrayList<>(maxSize); for (int i = 0; i < maxSize; i++) { degreeTable.add(null); } List<Node<T>> roots = new ArrayList<>(); Node<T> current = maxNode; Node<T> start = maxNode; do { roots.add(current); current = current.right; } while (current != start); for (Node<T> root : roots) { Node<T> node = root; int degree = node.degree; while (degreeTable.get(degree) != null) { Node<T> other = degreeTable.get(degree); if (compare(node, other) < 0) { Node<T> temp = node; node = other; other = temp; } link(other, node); degreeTable.set(degree, null); degree++; } degreeTable.set(degree, node); } maxNode = null; for (Node<T> root : roots) { if (root != null) { if (maxNode == null) { maxNode = root; } else { if (compare(root, maxNode) > 0) { maxNode = root; } } } } } // 连接两个节点 private void link(Node<T> child, Node<T> parent) { child.left.right = child.right; child.right.left = child.left; child.parent = parent; if (parent.child == null) { parent.child = child; child.right = child; child.left = child; } else { child.left = parent.child; child.right = parent.child.right; parent.child.right = child; child.right.left = child; } parent.degree++; child.marked = false; } // 比较节点 private int compare(Node<T> x, Node<T> y) { return ((Comparable<T>) x.key).compareTo(y.key); } // 获取的大小 public int getSize() { return size; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值