堆和PriorityQueue优先级队列的创建与使用

 一.什么是堆

1.1:堆(Heaport)是数据结构的一种排序算法,满足其子节点总是大于or小于跟节点.

1.2:是一棵完全二叉树

例:

二.如何实现堆 

2.1:我们以一个数组 arr[]={7,4,10,2,8,9,10,6,12,1};来讲解如何向下调整来创建一个堆

 //初始化堆
    public void initElem(int[] array) {
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            usedSize++;
        }
    }

2.2 用向下调整的方式来构建大根堆

1. parent 标记需要调整的节点, child 标记 parent 的左孩子 ( 注意: parent 如果有孩子一定先是有左孩子 )
2. 如果 parent 的左孩子存在,即 :child < size , 进行以下操作,直到 parent 的左孩子不存在
parent 右孩子是否存在,存在找到左右孩子中最大的孩子,让 child 进行标
parent 与大的孩子 child 比较,如果:
parent大 于较大的孩子 child ,调整结束
否则:交换 parent 与较大的孩子 child ,交换完成之后, parent 中小的元素向下移动,可能导致子
树不满足对的性质,因此需要继续向下调整,即 parent = child child = parent*2+1; 然后继续 2

 //向下调整构建大根堆堆
    public void createMaxHead() {
        for (int parent = (usedSize-1-1)/2; parent >=0; parent--) {
            shiftDown(parent,usedSize);

        }
    }
    //向下调整具体实现 perent为要调整的父节点 usedSize即范围
    private void shiftDown(int parent, int usedSize) {
        int child = 2*parent + 1;
        //最起码 要有左孩子
        while (child < usedSize) {
            //一定是有右孩子的情况下
            if(child+1 < usedSize && elem[child] < elem[child+1]) {
                child++;
            }
            //child下标 一定是左右孩子 最大值的下标
            if(elem[child] > elem[parent]) {
                int tmp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = tmp;
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

2.3:堆的插入

堆的插入总共需要两个步骤:
1. 先将元素放入到底层空间中 ( 注意:空间不够时需要扩容 )
2. 将最后新插入的节点向上调整,直到满足堆的性质

 

//入堆  判断是否为空,如为空进行扩容
    public  void offer(int val) {
        if(isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
            elem[usedSize++] = val;
            shiftUp(usedSize-1);
        }
    }
//向上调整 用于插入元素 将元素放到数组最后位置 然后与节点比较 若大于节点交换彼此 直至比到头节点
    private void shiftUp(int child) {
            int parent = (child-1)/2;
            while (child > 0) {
                if(elem[child] > elem[parent]) {
                    int tmp = elem[child];
                    elem[child] = elem[parent];
                    elem[parent] = tmp;
                    child = parent;
                    parent = (child-1)/2;
                }else {
                    break;
                }
            }
        }

 2.4:堆的删除

1. 将堆顶元素对堆中最后一个元素交换
2. 将堆中有效数据个数减少一个
3. 对堆顶元素进行向下调整

 具体代码实现:


import java.util.Arrays;

public class MaxHeap {
    private static int[] elem;  //使用一个数组存储堆的元素
    private static int usedSize; //存储元素的大小

    public MaxHeap() {
        this.elem = new int[10];  //指定堆的大小
        this.usedSize = 0;
    }

    //初始化堆
    public void initElem(int[] array) {
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            usedSize++;
        }
    }


    //向下调整构建大根堆堆
    public void createMaxHead() {
        for (int parent = (usedSize-1-1)/2; parent >=0; parent--) {
            shiftDown(parent,usedSize);

        }
    }
    //向下调整具体实现 perent为要调整的父节点 usedSize即范围
    private void shiftDown(int parent, int usedSize) {
        int child = 2*parent + 1;
        //最起码 要有左孩子
        while (child < usedSize) {
            //一定是有右孩子的情况下
            if(child+1 < usedSize && elem[child] < elem[child+1]) {
                child++;
            }
            //child下标 一定是左右孩子 最大值的下标
            if(elem[child] > elem[parent]) {
                int tmp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = tmp;
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }
    //入堆  判断是否为空,如为空进行扩容
    public  void offer(int val) {
        if(isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
            elem[usedSize++] = val;
            shiftUp(usedSize-1);
        }
    }

    private boolean isFull() {
        return elem.length==usedSize;
    }

    //向上调整 用于插入元素 将元素放到数组最后位置 然后与节点比较 若大于节点交换彼此 直至比到头节点
    private void shiftUp(int child) {
            int parent = (child-1)/2;
            while (child > 0) {
                if(elem[child] > elem[parent]) {
                    int tmp = elem[child];
                    elem[child] = elem[parent];
                    elem[parent] = tmp;
                    child = parent;
                    parent = (child-1)/2;
                }else {
                    break;
                }
            }
        }
        //将要删除的头几点放到末尾 并重写向下调整
   public int pop() {
        if(isEmpty()) {
            throw new RuntimeException("堆为空,删除操作无法完成!");
        }
       //交换头节点和尾节点
        int tem =elem[usedSize-1];
        elem[usedSize-1] = elem[0];
        elem[0] = tem;
        usedSize--;
        shiftDown(0,usedSize);
        return elem[0];
   }
   public int peek(){
        return elem[0];
   }

    //判断是否为空
    public static boolean isEmpty() {
        return usedSize==0;

    }
    //打印堆
    public static void show(){
        for (int i = 0; i <usedSize; i++) {
            System.out.print(elem[i]+" ");
        }
        System.out.println();
    }
}

 效果:


public class TestMaxHead {
    public static void main(String[] args) {
       MaxHeap m =new MaxHeap();
       int[] arr={7,4,10,2,8,9,10,6,12,1};
       m.initElem(arr);
        System.out.println("将数组元素丢人堆中:");
       m.show();
       m.createMaxHead();
        System.out.println("以大根堆的形式创建堆:");
        m.show();
        m.offer(666);
        System.out.println("插入一个666");
        m.show();
        m.pop();
        System.out.println("删除表头元素:");
        m.show();
        System.out.println("此时表头元素为:"+m.peek());

    }
}

 PriorityQueue的特性

Java 集合框架中提供了 PriorityQueue PriorityBlockingQueue 两种类型的优先级队列, PriorityQueue 是线 程不安全的, PriorityBlockingQueue 是线程安全的

1. 使用时必须导入 PriorityQueue 所在的包,即:
import java . util . PriorityQueue ;
2. PriorityQueue 中放置的 元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出
ClassCastException 异常
3. 不能 插入 null 对象,否则会抛出 NullPointerException
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
5. 插入和删除元素的时间复杂度为
6. PriorityQueue 底层使用了堆数据结构
7. PriorityQueue 默认情况下是小堆 --- 即每次获取到的元素都是最小的元素

 3.常用构造器

static void TestPriorityQueue(){
// 创建一个空的优先级队列,底层默认容量是11
PriorityQueue<Integer> q1 = new PriorityQueue<>();
// 创建一个空的优先级队列,底层的容量为initialCapacity
PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
ArrayList<Integer> list = new ArrayList<>();
list.add(4);
list.add(3);
list.add(2);
list.add(1);
// 用ArrayList对象来构造一个优先级队列的对象
// q3中已经包含了三个元素
PriorityQueue<Integer> q3 = new PriorityQueue<>(list);
System.out.println(q3.size());
System.out.println(q3.peek());
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值