优先级队列的模拟实现(堆)

优先级队列的模拟实现

JDK1.8中的PriorityQueue底层使用了堆的数据结构,而堆实际就是在完全二叉树的基础之上进行了一些元素的调整

注意
new出的空间在堆上,优先级队列底层结构也是堆,但两个堆不是同一个概念
new 堆:指的是一块具有特殊作用的内存空间
优先级队列底层的堆:指的是一种数据结构

  • 堆是一颗完全二叉树

  • 每个节点都比他的两个孩子小,属于小根堆

  • 每个节点都比他的孩子节点大,属于大根堆

  • 由于堆是一颗完全二叉树,因此可以层序的规则采用顺序的方式来高效存储(在数组中存储)
    在这里插入图片描述

  • 在堆中一般情况下将根节点叫堆顶元素

小堆:
1. 堆顶元素一定是最小的
2. 每个节点都比其孩子小
3. 每条路径都是升序

注意:普通二叉树是不可以直接用数据按照层序的方式来进行存储
如果一定要按照顺序的方式来进行存储的话,那么要将数中空节点的位置保留出来,否则还原的时候会出错
但是这样存储效率太低了,所以不是完全二叉树不建议用顺序方式来存储
在这里插入图片描述

堆的创建

1. 堆的向下调整

注意不能先标记右孩子,而应该先标记左孩子(因为右孩子可能没有)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wRPiHfFL-1596969935019)(en-resource://database/6236:1)]

    public static void shiftDown(int[] array, int parent) {
        // child先标记parent的左孩子,因为parent可能右左没有右
        int child = 2 * parent + 1;

        while (child < array.length) {

            // 如果右孩子存在,找到左右孩子中较小的孩子,用child进行标记
            if(child+1 < array.length&& array[child+1] < array[child]){
                child += 1;
            }

            // 
            if (array[parent] > array[child]) {
                // 将双亲与较小的孩子交换
                int temp = array[parent];
                array[parent] = array[child];
                array[child] = temp;

                // parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整
                parent = child;
                child = parent * 2 + 1;
            }else{
                break;
            }
        }
    }

堆的创建

在这里插入图片描述

public static void createHeap(int[] array) {
        // 找倒数第一个非叶子节点,从该节点位置开始往前一直到根节点,遇到一个节点,应用向下调整
        int root = ((array.length-2)>>1);
        for (; root >= 0; root--) {
            shiftDown(array, root);
        }
    }

堆的插入和删除

1. 堆的插入

堆的插入总共需要两个步骤:

  1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
  2. 将最后新插入的节点向上调整,直到满足堆的性质
    // 堆的插入(按小堆)
    public void shiftUp(int[] array,int child) {
        // 找到child的双亲
        int parent = (child - 1) / 2;

        while (child > 0) {
            // 如果双亲比孩子大,parent满足堆的性质,调整结束
            if (array[parent] > array[child]) {
                break;
            }
            else{
                // 将双亲与孩子节点进行交换
                int t = array[parent];
                array[parent] = array[child];
                array[child] = t;

                // 小的元素向下移动,可能到值子树不满足堆的性质,因此需要继续向上调增
                child = parent;
                parent = (child - 1) / 1;
            }
        }
    }

2. 堆的删除

堆删除一定是删除的堆顶元素

  1. 将堆顶元素对堆中最后一个元素交换
  2. 将堆中有效数据个数减少一个
  3. 对堆顶元素进行向下调整
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43360037/article/details/107898075