二叉堆 Binary Heap

二叉堆:https://blog.csdn.net/qq_40794973/article/details/102532323


1 二叉堆底层实现

1.1 定义二叉堆

public class MaxHeap<E extends Comparable<E>> {
    private ArrayList<E> data;
    public MaxHeap(int capacity) {
        data = new ArrayList<>(capacity);
    }
    public MaxHeap() {
        data = new ArrayList<>();
    }
    public MaxHeap(E[] arr) {
        this(arr.length);
        data.addAll(Arrays.asList(arr));
        for (int i = parent(arr.length - 1); i >= 0; i--) {
            siftDown(i);
        }
    }

1.2 辅助函数 

// 返回堆中的元素个数
public int size() {
    return data.size();
}
// 返回一个布尔值, 表示堆中是否为空
public boolean isEmpty() {
    return data.isEmpty();
}
// 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
private int parent(int index) {
    if (index == 0) {
        throw new IllegalArgumentException("index-0 doesn't have parent.");
    }
    return (index - 1) / 2;
}
// 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
private int leftChild(int index) {
    return index * 2 + 1;
}
// 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
private int rightChild(int index) {
    return index * 2 + 2;
}
//交换data里面的索引为a和b的值
private void swap(int a, int b) {
    E temp = data.get(a);
    data.set(a, data.get(b));
    data.set(b, temp);
}
//删除data里面的最后一个元素
private void removeLast() {
    data.remove(data.size() - 1);
}
//往data末尾添加一个元素
private void addLast(E e) {
    data.add(data.size(), e);
}

1.3 siftUp

private void siftUp(int k) {
    // data[k] > data[parent(k)]
    while (k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0) {
        swap(k, parent(k));
        k = parent(k);
    }
}

1.4 siftDown 

private void siftDown(int k) {
    // 有左节点
    while (leftChild(k) < data.size()) {
        // 在此轮循环中,data[k]和data[j]交换位置
        int j = leftChild(k);
        // 左节点 < 右节点
        if (j + 1 < data.size() && data.get(j + 1).compareTo(data.get(j)) > 0) {
            j++;
        }
        // data[j] 是 leftChild 和 rightChild 中的最大值
        // data[k] > data[j]
        if (data.get(k).compareTo(data.get(j)) >= 0) {
            break;
        }
        swap(k, j);
        k = j;
    }
}

1.5 添加元素

// 向堆中添加元素
public void add(E e) {
    addLast(e);
    siftUp(data.size() - 1);
}

1.6 最大元素相关

// 看堆中的最大元素
public E findMax() {
    if (data.size() == 0) {
        throw new IllegalArgumentException("Can not findMax when heap is empty.");
    }
    return data.get(0);
}
// 取出堆中最大元素
public E extractMax() {
    E ret = findMax();
    swap(0, data.size() - 1);
    removeLast();
    siftDown(0);
    return ret;
}
// 取出堆中的最大元素,并且替换成元素e
public E replace(E e) {
    E ret = findMax();
    data.set(0, e);
    siftDown(0);
    return ret;
}

2 测试代码 

2.1 测试是否正确

//int n = 1000000;
//MaxHeap<Integer> maxHeap = new MaxHeap<>();
//Random random = new Random();
//for (int i = 0; i < n; i++) {
//    maxHeap.add(random.nextInt(Integer.MAX_VALUE));
//}
//int[] arr = new int[n];
//for (int i = 0; i < n; i++) {
//    arr[i] = maxHeap.extractMax();
//}
//System.out.println(Arrays.toString(arr));
//for (int i = 1; i < n; i++) {
//    if (arr[i - 1] < arr[i]) {
//        throw new IllegalArgumentException("Error");
//    }
//}
//System.out.println("Test MaxHeap completed.");

2.2 测试heapify 

//public class Main {
//    private static double testHeap(Integer[] testData, boolean isHeapify) {
//        long startTime = System.nanoTime();
//        MaxHeap<Integer> maxHeap;
//        if (isHeapify) {
//            maxHeap = new MaxHeap<>(testData);
//        } else {
//            maxHeap = new MaxHeap<>(testData.length);
//            for (int num : testData) {
//                maxHeap.add(num);
//            }
//        }
//        int[] arr = new int[testData.length];
//        for (int i = 0; i < testData.length; i++) {
//            arr[i] = maxHeap.extractMax();
//        }
//        for (int i = 1; i < testData.length; i++) {
//            if (arr[i - 1] < arr[i]) {
//                throw new IllegalArgumentException("Error");
//            }
//        }
//        System.out.println("Test MaxHeap completed.");
//        long endTime = System.nanoTime();
//        return (endTime - startTime) / 1000000000.0;
//    }
//    /**
//     * Test MaxHeap completed.
//     * Without heapify: 7.572264 s
//     * Test MaxHeap completed.
//     * With heapify: 4.5880423 s
//     */
//    public static void main(String[] args) {
//        int n = 5000000;
//        Random random = new Random();
//        Integer[] testData1 = new Integer[n];
//        for (int i = 0; i < n; i++) {
//            testData1[i] = random.nextInt(Integer.MAX_VALUE);
//        }
//        Integer[] testData2 = Arrays.copyOf(testData1, n);
//        double time1 = testHeap(testData1, false);
//        System.out.println("Without heapify: " + time1 + " s");
//
//        double time2 = testHeap(testData2, true);
//        System.out.println("With heapify: " + time2 + " s");
//    }
//}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值