Java中实现大/小根堆

用一道算法题来说明堆的使用场景
leetecode-215

堆的介绍

小根堆:父节点的值小于或等于子节点的值
大根堆:父节点的值大于或等于子节点的值
在这里插入图片描述

堆的存储

这个是特别值得一说的,因为跟后面的实现相关。一般都是用数组来存储的,Java中的优先队列就是用Object[]数组存储;尽管堆是一个完全二叉树,但一般不用树结构来存储,正因为是完全二叉树,有非常多特殊的性质,正好可以用数组来存储。
这里最关键的性质是:

1)i结点的父结点下标就为(i–1)/2;
2)i节点左右子结点下标分别为2 * i + 1和2 * i + 2
在这里插入图片描述

堆的操作

插入:插入在堆尾,然后从下往上进行调整;调整一遍即可变有序,时间复杂度为o(logn)

private static void siftUp(int[] heap, int i) {
    
    
    if (i <= 0) return;
    // 父节点
    int parent = (i - 1) / 2;
    if (heap[parent] > heap[i]) {
    
    
        int t = heap[i];
        heap[i] = heap[parent];
        heap[parent] = t;
        siftUp(heap, parent); // 递归往上
    }
}

删除:一般是弹出堆顶元素,然后用末尾元素替换堆顶元素,然后进行向下调整。时间复杂度也为o(logn)

    private static void siftDown(int[] heap, int i) {
    
    
        // 写一个递归的方式
        int left = i * 2 + 1;
        int right = i * 2 + 2;
        int minIndex = getMinIndex(heap, i, left, right);
        if (minIndex != i) {
    
    
            int tem = heap[i];
            heap[i] = heap[minIndex];
            heap[minIndex] = tem;
            // 递归调整子节点
            siftDown(heap, minIndex);
        }
    }
    private static int getMinIndex(int[] heap, int i, int left, int right) {
    
    
        int minIndex = i;
        if (left < size && heap[left] < heap[i]) {
    
    
            minIndex = left;
        }
        if (right < size && heap[right] < heap[minIndex]) {
    
    
            minIndex = right;
        }
        return minIndex;
    }

堆的实现

调整堆/构造堆
从i = n/2 - 1节点开始调整,这之后的都是叶节点

    private static void heapIfy(int[] heap) {
    
    
        // 最后一个非叶子节点开始调整
        int i = size / 2 - 1;
        for (; i >= 0; i--) {
    
    
            siftDown(heap, i);
        }
    }

总结

堆这种结构看似很吓人,感觉很难得样子。但真正理解了会发现很好实现得,它本质上就只有两种操作:
1)向下调整
2)向上调整
另外,这两种操作还有非递归实现方式,有兴趣得可以思考并实现一下

猜你喜欢

转载自blog.csdn.net/weixin_42541360/article/details/114478453