数据结构之堆练习题及PriorityQueue深入讲解!

题外话

上午学了一些JavaEE初阶知识,下午继续复习数据结构内容

正题

本篇内容把堆的练习题做一下

第一题

1.下列关键字序列为堆的是:( A )

A: 100,60,70,50,32,65  

B: 60,70,65,50,32,100  

C: 65,100,70,32,50,60

D: 70,65,100,32,50,60  

E: 32,50,100,70,65,60  

F: 50,100,70,65,60,32

第一题解析

堆分为大根堆小根堆,

而且堆是完全二叉树,

只需要从上到下从左到右建立一个完全二叉树再判断是否是大根堆或者是小根堆即可

A 画出图是一个大根堆

其余画出图既不是大根堆也不是小根堆

第二题

2.已知小根堆为8,15,10,21,34,16,12,删除关键字8之后需重建堆,在此过程中,关键字之间的比较次数是( C )

A: 1     B: 2     C: 3   D: 4

第二题解析

先画图,然后运用堆的删除,将8和最后一个元素12交换位置删除,再调整位置变成小根堆计数关键字比较次数即可

12先和15,10比较,和10交换位置,然后再和16比较调整为小根堆,一共比较三次

第三题

3.最小堆[0,3,2,5,7,4,6,8],在删除堆顶元素0之后,其结果是( C )

A: [3,2,5,7,4,6,8]

B: [2,3,5,7,4,6,8]

C: [2,3,4,5,7,8,6]

D: [2,3,4,5,6,7,8]

第三题解析

和第二题一样,先画图,0与8交换,然后调整为小根堆即可

结果为2,3,4,5,7,8,6

PriorityQueue

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,

PriorityQueue是线程不安全的

PriorityBlockingQueue是线程安全的

本文主要介绍PriorityQueue。

1.使用时必须导入PriorityQueue所在的包

import java.uitl.PriorityQueue;

2.PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException异常

3. 不能插入null对象,否则会抛出NullPointerException

4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容

5.PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素,如果需要大堆需要用户提供比较器

用比较器创建大根堆

先说下Prriority常用构造方法,

PriorityQueue() 创建一个空的优先级队列,默认容量是11

PriorityQueue(int initialCapacity) 创建一个初始容量为initialCapacity的优先级队列,注意: initialCapacity不能小于1,否则会抛IllegalArgumentException异常

PriorityQueue(Collection c) 用一个集合来创建优先级队列

我们可以自己传一个比较器,创建大根堆,代码如下

class IntCmp implements Comparator<Integer>

{    

@Override    

public int compare(Integer o1, Integer o2)

{        return o2.compareTo(o1) 

}

}

这样插入元素的时候都会是以大根堆的方式插入

相关练习题

第一题

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

第一题思路

1.创建一个大根堆,把数组前k个元素添加进去

2.因为是大根堆,用数组剩余元素与堆顶元素进行比较,堆顶元素是大根堆中最大的,如果比堆顶元素小就删除堆顶元素,插入当前数组元素,会自动调整为大根堆

3.当数组全部遍历完成,大根堆的k个元素就是最小的k个元素

第一题代码详解
 public int[] smallestK(int[] arr, int k) {
        //创建数组ret,容量为k
        int[] ret=new int[k];
        //如果数组为空,或者k小于等于0,说明根本找不到最小的k个元素,不合法
        if(arr==null||k<=0)
        {
            //直接返回ret
            return ret;
        }
        //创建优先级队列PriorityQueue,使用匿名内部类传入比较器
        PriorityQueue<Integer> p=new PriorityQueue<>(new Comparator<Integer>() {
//将比较器设置成满足大根堆的形式
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        //添加前k个元素
        for (int i=0;i<k;i++)
        {
            p.offer(arr[i]);
        }
        //比较k以后元素是否比堆顶元素小
        for (int i = k; i <arr.length ; i++) {
            int top=p.peek();
            //如果比堆顶元素小
            if (arr[i]<top)
            {
                //删除堆顶元素
                p.poll();
                //添加当前数组元素
                p.offer(arr[i]);
            }

        }

        //最后将最小的k个元素传入数组ret中即可
        for (int i = 0; i < k; i++) {

            ret[i] = p.poll();

        }
        //返回ret
        return ret;
    }

第二题

堆排序,从大到小排序

第二题思路

1.我们先考虑,堆排序是建立大根堆还是建立小根堆

2.大根堆我们能保证堆顶元素是整个堆中最大的,小根堆我们能保证堆顶元素是整个堆中最小的

3.我们只需要建立大根堆,然后将堆顶元素和最后一个元素交换,然后再大根堆排序,然后再让堆顶元素和堆尾没有交换过的元素一一交换,再大堆根排序即可

第二题代码详解

//向下调整(上一篇堆的博客写过)

private void siftDown(int parent,int len)
{
    int child=parent*2+1;
//child等于len不会进入循环
    while (child<len)
    {
        if (child+1<len&&elem[child]<elem[child+1])
        {
            child=child+1;
        }
        if (elem[child]>elem[parent])
        {
         swap(parent,child);
            parent=child;
            child=parent*2+1;
        }
        else {
            break;
        }

    }

}
//堆排序,从小到大排序
public void heapSort()
{
//让end保存最后一个元素下标

    int end=usedSize-1;
//当end>0的时候就需要排序,等于零说明不需要排序了
    while(end>0)
    {
//交换堆顶和没有交换过的最后一个元素值
        swap(0,end);
//向下排序,将没交换的排序为大根堆,end下标位置不会进入排序
        siftDown(0,end);
//让末尾位置调整到前一个即可
        end--;
    }
}

小结

大家有什么意见可以在评论区说出来,我都会改进!!!

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值