一、前言

堆的历史

堆的数据结构有很多种体现形式,包括;2-3堆、B堆、斐波那契堆,而在 Java API 中最常用的是用于实现优先队列的二叉堆,它是由 JWJ Williams 在 1964 年引入的,作为堆排序算法的数据结构。另外在 Dijkstra 算法等几种高效的图算法中,堆也是非常重要的。

二、堆的数据结构

在计算机科学中,堆(heap) 的实现是一种基于树的特殊的数据结构,它可以在数组上构建出树的结构体,并满足堆的属性;

最小堆:如果P​ 是C​ 的一个父级节点, 那么P​ 的key(或value)应小于或等于C 的对应值。

最大堆:与最小堆的定义正好相反,最大堆(max heap) ,P​ 的key(或value)大于C 的对应值。

三、堆的代码实现

1. 实现介绍

堆的实现在 Java API 中主要体现在延迟队列的实现二叉堆上,这里小傅哥单独把这部分代码拆分出来,了解下关于小堆和大堆的实现。

从对堆的数据结构介绍上可以看到,小堆和大堆的唯一区别仅是对元素的排序方式不同。所以也就是说在存放和获取元素的时候对元素的填充和摘除时,排序方式不同而已。

2. 入堆实现

堆的在存放元素时,以遵循它的特点,会在存放过程中,通过队尾元素向上比对迁移。

private void siftUpComparable(int k, E x) {
    logger.info("【入队】元素:{} 当前队列:{}", JSON.toJSONString(x), JSON.toJSONString(queue));
    while (k > 0) {
        // 获取父节点Idx,相当于除以2
        int parent = (k - 1) >>> 1;
        logger.info("【入队】寻找当前节点的父节点位置。k:{} parent:{}", k, parent);
        Object e = queue[parent];
        // 如果当前位置元素,大于父节点元素,则退出循环
        if (compareTo(x, (E) e) >= 0) {
            logger.info("【入队】值比对,父节点:{} 目标节点:{}", JSON.toJSONString(e), JSON.toJSONString(x));
            break;
        }
        // 相反父节点位置大于当前位置元素,则进行替换
        logger.info("【入队】替换过程,父子节点位置替换,继续循环。父节点值:{} 存放到位置:{}", JSON.toJSONString(e), k);
        queue[k] = e;
        k = parent;
    }
    queue[k] = x;
    logger.info("【入队】完成 Idx:{} Val:{} \r\n当前队列:{} \r\n", k, JSON.toJSONString(x), JSON.toJSONString(queue));
}

入堆的实现 add 方法最终会调用到 siftUpComparable 方法,进行排序的方式进行处理。而这个排序 compareTo 方法是由具体的 MinHeap、MaxHeap 来做实现。

以入堆元素2举例,如图所示入堆过程。

首先将元素2挂到队列尾部,之后通过 (k - 1) >>> 1 计算父节点位置,与对应元素进行比对和判断交换。

交换过程包括 2->6、2->5,以此交换结束后元素保存完毕。

3. 出堆实现

元素的出堆其实很简单,只要把根元素直接删除弹出即可。但剩余接下里的步骤才是复杂的,因为需要在根元素迁移走后,寻找另外的最小元素迁移到对头。这个过程与入堆正好相反,这是一个不断向下迁移的过程。

private void siftDownComparable(int k, E x) {
    // 先找出中间件节点
    int half = size >>> 1;
    while (k < half) {
        // 找到左子节点和右子节点,两个节点进行比较,找出最大的值
        int child = (k << 1)   1;
        Object c = queue[child];
        int right = child   1;
        // 左子节点与右子节点比较,取最小的节点
        if (right < size && compareTo((E) c, (E) queue[right]) > 0) {
            logger.info("【出队】左右子节点比对,获取最小值。left:{} right:{}", JSON.toJSONString(c), JSON.toJSONString(queue[right]));
            c = queue[child = right];
        }
        // 目标值与c比较,当目标值小于c值,退出循环。说明此时目标值所在位置适合,迁移完成。
        if (compareTo(x, (E) c) <= 0) {
            break;
        }
        // 目标值小于c值,位置替换,继续比较
        logger.info("【出队】替换过程,节点的值比对。上节点:{} 下节点:{} 位置替换", JSON.toJSONString(queue[k]), JSON.toJSONString(c));
        queue[k] = c;
        k = child;
    }
    // 把目标值放到对应位置
    logger.info("【出队】替换结果,最终更换位置。Idx:{} Val:{}", k, JSON.toJSONString(x));
    queue[k] = x;
}

不断地向下迁移元素。这个过程会比对左右子节点的值,找到最小的。所以整个过程会比入堆麻烦一些。

这里以弹出元素1举例,之后将堆尾元素替换到相应的位置。整个过程分为6张图表述。

  • 图1到图2,找出根元素弹出。
  • 图3到图4,将根元素向下迁移,与子元素比对,并替换位置。如果这个位置与8相比,小于8则继续向下迁移。
  • 图4到图5,继续迁移,在原节点4的位置对应的两个子元素,都比8大,这个时候就可以停下来了。
  • 图5到图6,更换元素位置,把队尾的元素替换到对应元素1向下迁移检测的位置。

4. 小堆实现

小堆是一个正序比对

public class MinHeap extends Heap<Integer> {

    @Override
    public int compareTo(Integer firstElement, Integer secondElement) {
        return firstElement.compareTo(secondElement);
    }

}

测试

@Test
public void test_min_heap() {
    MinHeap heap = new MinHeap();
    // 存入元素
    heap.add(1);
    heap.add(3);
    heap.add(5);
    heap.add(11);
    heap.add(4);
    heap.add(6);
    heap.add(7);
    heap.add(12);
    heap.add(15);
    heap.add(10);
    heap.add(9);
    heap.add(8);
    // 弹出元素
    while (heap.peek() != null){
        logger.info("测试结果:{}", heap.poll());
    }
}

结果

17:21:30.053 [main] INFO queue.PriorityQueue - 【入队】元素:3 当前队列:[1,null,null,null,null,null,null,null,null,null,null]
17:21:30.055 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:1 parent:0
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:1 目标节点:3
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:1 Val:3 
当前队列:[1,3,null,null,null,null,null,null,null,null,null] 

17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:5 当前队列:[1,3,null,null,null,null,null,null,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:2 parent:0
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:1 目标节点:5
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:2 Val:5 
当前队列:[1,3,5,null,null,null,null,null,null,null,null] 

17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:11 当前队列:[1,3,5,null,null,null,null,null,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:3 parent:1
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:3 目标节点:11
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:3 Val:11 
当前队列:[1,3,5,11,null,null,null,null,null,null,null] 

17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:4 当前队列:[1,3,5,11,null,null,null,null,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:4 parent:1
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:3 目标节点:4
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:4 Val:4 
当前队列:[1,3,5,11,4,null,null,null,null,null,null] 

17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:6 当前队列:[1,3,5,11,4,null,null,null,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:5 parent:2
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:5 目标节点:6
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:5 Val:6 
当前队列:[1,3,5,11,4,6,null,null,null,null,null] 

17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:7 当前队列:[1,3,5,11,4,6,null,null,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:6 parent:2
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:5 目标节点:7
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:6 Val:7 
当前队列:[1,3,5,11,4,6,7,null,null,null,null] 17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:12 当前队列:[1,3,5,11,4,6,7,null,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:7 parent:3
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:11 目标节点:12
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:7 Val:12 
当前队列:[1,3,5,11,4,6,7,12,null,null,null] 

17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】元素:15 当前队列:[1,3,5,11,4,6,7,12,null,null,null]
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:8 parent:3
17:21:30.056 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:11 目标节点:15
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:8 Val:15 
当前队列:[1,3,5,11,4,6,7,12,15,null,null] 

17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】元素:10 当前队列:[1,3,5,11,4,6,7,12,15,null,null]
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:9 parent:4
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:4 目标节点:10
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:9 Val:10 
当前队列:[1,3,5,11,4,6,7,12,15,10,null] 

17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】元素:9 当前队列:[1,3,5,11,4,6,7,12,15,10,null]
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:10 parent:4
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:4 目标节点:9
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:10 Val:9 
当前队列:[1,3,5,11,4,6,7,12,15,10,9] 

17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】元素:8 当前队列:[1,3,5,11,4,6,7,12,15,10,9,null,null,null,null,null,null,null,null,null,null,null,null,null]
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:11 parent:5
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:6 目标节点:8
17:21:30.057 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:11 Val:8 
当前队列:[1,3,5,11,4,6,7,12,15,10,9,8,null,null,null,null,null,null,null,null,null,null,null,null] 

17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:1 下节点:3 位置替换
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:11 right:4
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:3 下节点:4 位置替换
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:10 right:9
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:4 Val:8
17:21:30.057 [main] INFO heap.__test__.HeapTest - 测试结果:1
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:3 下节点:4 位置替换
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:11 right:8
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:4 下节点:8 位置替换
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:4 Val:9
17:21:30.057 [main] INFO heap.__test__.HeapTest - 测试结果:3
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:8 right:5
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:4 下节点:5 位置替换
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:5 下节点:6 位置替换
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:5 Val:10
17:21:30.057 [main] INFO heap.__test__.HeapTest - 测试结果:4
17:21:30.057 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:8 right:6
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:5 下节点:6 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:10 right:7
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:6 下节点:7 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:6 Val:15
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:5
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:8 right:7
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:6 下节点:7 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:7 下节点:10 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:5 Val:12
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:6
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:7 下节点:8 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:11 right:9
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:8 下节点:9 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:4 Val:15
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:7
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:8 下节点:9 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:9 下节点:11 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:3 Val:12
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:8
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:11 right:10
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:9 下节点:10 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:2 Val:15
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:9
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:10 下节点:11 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:1 Val:12
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:10
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:11 下节点:12 位置替换
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:1 Val:15
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:11
17:21:30.058 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:0 Val:15
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:12
17:21:30.058 [main] INFO heap.__test__.HeapTest - 测试结果:15

Process finished with exit code 0
小堆就是一个正序的输出结果,从小到大的排序和输出。
小堆空间:[1,3,5,11,4,6,7,12,15,10,9,8,null,null,null,null,null,null,null,null,null,null,null,null]

  • 小堆就是一个正序的输出结果,从小到大的排序和输出。
  • 小堆空间:[1,3,5,11,4,6,7,12,15,10,9,8,null,null,null,null,null,null,null,null,null,null,null,null]

5. 大堆实现

小堆是一个反序比对

public class MaxHeap extends Heap<Integer> {

    @Override
    public int compareTo(Integer firstElement, Integer secondElement) {
        return secondElement.compareTo(firstElement);
    }

}

测试

@Test
public void test_max_heap() {
    MaxHeap heap = new MaxHeap();
    // 存入元素
    heap.add(1);
    heap.add(3);
    heap.add(5);
    heap.add(11);
    heap.add(4);
    heap.add(6);
    heap.add(7);
    heap.add(12);
    heap.add(15);
    heap.add(10);
    heap.add(9);
    heap.add(8);
    // 弹出元素
    while (heap.peek() != null){
        logger.info("测试结果:{}", heap.poll());
    }
}

结果

17:23:45.079 [main] INFO queue.PriorityQueue - 【入队】元素:3 当前队列:[1,null,null,null,null,null,null,null,null,null,null]
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:1 parent:0
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:1 存放到位置:1
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:0 Val:3 
当前队列:[3,1,null,null,null,null,null,null,null,null,null] 

17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】元素:5 当前队列:[3,1,null,null,null,null,null,null,null,null,null]
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:2 parent:0
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:3 存放到位置:2
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:0 Val:5 
当前队列:[5,1,3,null,null,null,null,null,null,null,null] 

17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】元素:11 当前队列:[5,1,3,null,null,null,null,null,null,null,null]
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:3 parent:1
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:1 存放到位置:3
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:1 parent:0
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:5 存放到位置:1
17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:0 Val:11 
当前队列:[11,5,3,1,null,null,null,null,null,null,null] 

17:23:45.081 [main] INFO queue.PriorityQueue - 【入队】元素:4 当前队列:[11,5,3,1,null,null,null,null,null,null,null]
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:4 parent:1
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:5 目标节点:4
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:4 Val:4 
当前队列:[11,5,3,1,4,null,null,null,null,null,null] 

17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】元素:6 当前队列:[11,5,3,1,4,null,null,null,null,null,null]
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:5 parent:2
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:3 存放到位置:5
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:2 parent:0
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:11 目标节点:6
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:2 Val:6 
当前队列:[11,5,6,1,4,3,null,null,null,null,null] 

17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】元素:7 当前队列:[11,5,6,1,4,3,null,null,null,null,null]
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:6 parent:2
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:6 存放到位置:6
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:2 parent:0
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:11 目标节点:7
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:2 Val:7 
当前队列:[11,5,7,1,4,3,6,null,null,null,null] 

17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】元素:12 当前队列:[11,5,7,1,4,3,6,null,null,null,null]
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:7 parent:3
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:1 存放到位置:7
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:3 parent:1
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:5 存放到位置:3
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:1 parent:0
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:11 存放到位置:1
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:0 Val:12 
当前队列:[12,11,7,5,4,3,6,1,null,null,null] 

17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】元素:15 当前队列:[12,11,7,5,4,3,6,1,null,null,null]
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:8 parent:3
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:5 存放到位置:8
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:3 parent:1
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:11 存放到位置:3
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:1 parent:0
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:12 存放到位置:1
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:0 Val:15 
当前队列:[15,12,7,11,4,3,6,1,5,null,null] 

17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】元素:10 当前队列:[15,12,7,11,4,3,6,1,5,null,null]
17:23:45.082 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:9 parent:4
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:4 存放到位置:9
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:4 parent:1
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:12 目标节点:10
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:4 Val:10 
当前队列:[15,12,7,11,10,3,6,1,5,4,null] 

17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】元素:9 当前队列:[15,12,7,11,10,3,6,1,5,4,null]
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:10 parent:4
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:10 目标节点:9
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:10 Val:9 
当前队列:[15,12,7,11,10,3,6,1,5,4,9] 

17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】元素:8 当前队列:[15,12,7,11,10,3,6,1,5,4,9,null,null,null,null,null,null,null,null,null,null,null,null,null]
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:11 parent:5
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:3 存放到位置:11
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:5 parent:2
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】替换过程,父子节点位置替换,继续循环。父节点值:7 存放到位置:5
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】寻找当前节点的父节点位置。k:2 parent:0
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】值比对,父节点:15 目标节点:8
17:23:45.083 [main] INFO queue.PriorityQueue - 【入队】完成 Idx:2 Val:8 
当前队列:[15,12,8,11,10,7,6,1,5,4,9,3,null,null,null,null,null,null,null,null,null,null,null,null] 

17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:15 下节点:12 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:12 下节点:11 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:1 right:5
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:11 下节点:5 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:8 Val:3
17:23:45.083 [main] INFO heap.__test__.HeapTest - 测试结果:15
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:12 下节点:11 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:5 right:10
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:11 下节点:10 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:4 Val:9
17:23:45.083 [main] INFO heap.__test__.HeapTest - 测试结果:12
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:11 下节点:10 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:5 right:9
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:10 下节点:9 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:4 Val:4
17:23:45.083 [main] INFO heap.__test__.HeapTest - 测试结果:11
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:10 下节点:9 位置替换
17:23:45.083 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:9 下节点:5 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:3 Val:3
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:10
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:5 right:8
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:9 下节点:8 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:8 下节点:7 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:5 Val:1
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:9
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:5 right:7
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:8 下节点:7 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:2 Val:6
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:8
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】左右子节点比对,获取最小值。left:5 right:6
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:7 下节点:6 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:2 Val:1
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:7
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:6 下节点:5 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:1 Val:4
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:6
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:5 下节点:4 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:1 Val:3
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:5
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换过程,节点的值比对。上节点:4 下节点:3 位置替换
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:1 Val:1
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:4
17:23:45.084 [main] INFO queue.PriorityQueue - 【出队】替换结果,最终更换位置。Idx:0 Val:1
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:3
17:23:45.084 [main] INFO heap.__test__.HeapTest - 测试结果:1

Process finished with exit code 0

大堆就是一个反序的输出结果,从大到小的排序和输出。

大堆空间:[15,12,8,11,10,7,6,1,5,4,9,3,null,null,null,null,null,null,null,null,null,null,null,null]

以上就是Java数据结构之最小堆和最大堆的原理及实现详解的详细内容,更多关于Java数据结构 堆的资料请关注Devmax其它相关文章!

Java数据结构之最小堆和最大堆的原理及实现详解的更多相关文章

  1. swift篇第一期:简单的数据结构

    首先我们可以去使用Playground来编码,并且会实时的显示对应的编码信息,这样我们就不用每次都去运行程序来显示输出的东西了哦,也方便了我们对某些语句的验证,这个是比较赞的var与let前者为可变修饰符,后者为不可变从字面意思我们就可以很好的区分了常用的类型呢,跟其他语言基本相同啦,主要有几种:1.int类型2.Float,Double类型3.String类型4.Boolean类型当我们去声明一

  2. Swift 集合数据结构性能分析

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  3. Swift中的集合类数据结构

    在那种情况下,你将会需要一种基本的集合类数据结构。继续学习,你将会比较成熟的Cocoa数据结构与对应的纯Swift结构的性能。常见iOS数据结构iOS中三种最常用的数据结构是arrays,dictionaries和sets。除了在Swift和Objective-C中旧的Foundation框架中的数据结构,现在又有了新的仅支持Swift版本的数据结构与语言紧密结合在一起。Swift数组是同质的,意味着每一个Swift数组都只包含一种类型的对象。

  4. 11.Swift 中的类和结构体

    举例来说,以下情境中适合使用结构体:1.几何形状的大小,封装一个width属性和height属性,两者均为Double类型。这次就讲到这里,下次我们继续

  5. a place you can learn algorithms and data structures(算法和数据结构) in swift

    https://github.com/raywenderlich/swift-algorithm-club

  6. Swift3.0 类和结构体的选择

    结构体实例总是通过值传递,类实例总是通过引用传递先说说值类型和引用类型的区别值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝在Swift中,所有的结构体和枚举类型都是值类型。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体”Swift中,许多基本类型,诸如String,Array和Dictionary类型均以结构体的形式实现。Objective-C中Nsstring,NSArray和NSDictionary类型均以类的形式实现,而并非结构体。

  7. 【Swift】结构体和类

    Swift中结构体和类有很多共同点与结构体相比,类还有如下的附加功能:结构体和枚举是值类型值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。为了达到这个目的,Swift内建了两个恒等运算符:类和结构体的选择在你的代码中,你可以使用类和结构体来定义你的自定义数据类型。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。Swift中,许多基本类型,诸如String,Array和Dictionary类型均以结构体的形式实现。

  8. 如何在Swift中创建打包数据结构?

    我正在将一个项目从Objective-C转换为Swift,我正在使用一个打包的结构来输入通过套接字发送的转换二进制消息:我不确定Swift中最好的方法是什么,我能得到的最接近的近似值是:翻译中丢失了两个重要的细节:没有保证整数类型的比特,并且没有结构打包.我不认为这可以在Swift中表达,但如果是这样,怎么样?

  9. android – 如何正确删除保留的实例片段

    解决方法正如@Luksprog所建议的,以下方法有效.但是,它仍然无法解释为什么通过onDetach完成的先前清理不起作用.如果有人能解释为什么这个解决方案有效,而以前没有,我会非常感激.版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  10. android – 数组适配器notifyDataSetChanged()将无法正常工作

    .有任何想法吗?

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部