java优先队列堆_玩转数据结构之优先队列(PriorityQueue)和堆(Heap)

PriorityQueue

AAffA0nNPuCLAAAAAElFTkSuQmCC

Heap

二叉堆(Binary Heap)是一棵完全二叉树

AAffA0nNPuCLAAAAAElFTkSuQmCC

public class MaxHeap> {

private Array data;

public MaxHeap(int capacity){

data = new Array<>(capacity);

}

public MaxHeap(){

data = new Array<>();

}

// 返回堆中的元素个数

public int size(){

return data.getSize();

}

// 返回一个布尔值, 表示堆中是否为空

public boolean isEmpty(){

return data.isEmpty();

}

// 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引

private int parent(int index){

if(index == 0)

throw new IllegalArgumentException("index-0 doesn't have parent.");

return (index - 1) / 2;

}

// 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引

private int leftChild(int index){

return index * 2 + 1;

}

// 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引

private int rightChild(int index){

return index * 2 + 2;

}

}

向堆中添加元素和Sift up

AAffA0nNPuCLAAAAAElFTkSuQmCC

// 向堆中添加元素

public void add(E e){

data.addLast(e);

siftUp(data.getSize() - 1);

}

private void siftUp(int k){

while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){

data.swap(k, parent(k));

k = parent(k);

}

}

}

取出堆中的最大元素和Sift Down

Sift Down

用最小元素替换堆顶元素,然后删除之前的最小元素位置

最小元素和子树中最大元素,比较,交换位置

下沉完毕

// 看堆中的最大元素

public E findMax(){

if(data.getSize() == 0)

throw new IllegalArgumentException("Can not findMax when heap is empty.");

return data.get(0);

}

// 取出堆中最大元素

public E extractMax(){

E ret = findMax();

data.swap(0, data.getSize() - 1);

data.removeLast();

siftDown(0);

return ret;

}

private void siftDown(int k){

while(leftChild(k) < data.getSize()){ // k的左子树成为叶子节点

int j = leftChild(k); // 在此轮循环中,data[k]和data[j]交换位置

if( j + 1 < data.getSize() &&

data.get(j + 1).compareTo(data.get(j)) > 0 )

// j + 1 < data.getSize()说明有右孩子

j ++; // j存储右孩子的索引(如果右比左大的话)

// data[j] 是 leftChild 和 rightChild 中的最大值

if(data.get(k).compareTo(data.get(j)) >= 0 )

break;

data.swap(k, j);

k = j;

}

}

Heapify和Replace

Heapify

从最后一个非叶子节点开始计算(如何获得节点?答:拿到最后一个节点,然后拿到他的父亲节点)

然后不断下沉

AAffA0nNPuCLAAAAAElFTkSuQmCC

public MaxHeap(E[] arr){

data = new Array<>(arr);

for(int i = parent(arr.length - 1) ; i >= 0 ; i --) // i是倒数第一个非叶子节点

siftDown(i);

}

Test

import java.util.Random;

public class Main {

private static double testHeap(Integer[] testData, boolean isHeapify){

long startTime = System.nanoTime();

MaxHeap maxHeap;

if(isHeapify)

maxHeap = new MaxHeap<>(testData);

else{

maxHeap = new MaxHeap<>();

for(int num: testData)

maxHeap.add(num);

}

int[] arr = new int[testData.length];

for(int i = 0 ; i < testData.length ; i ++)

arr[i] = maxHeap.extractMax();

for(int i = 1 ; i < testData.length ; i ++)

if(arr[i-1] < arr[i])

throw new IllegalArgumentException("Error");

System.out.println("Test MaxHeap completed.");

long endTime = System.nanoTime();

return (endTime - startTime) / 1000000000.0;

}

public static void main(String[] args) {

int n = 1000000;

Random random = new Random();

Integer[] testData = new Integer[n];

for(int i = 0 ; i < n ; i ++)

testData[i] = random.nextInt(Integer.MAX_VALUE);

double time1 = testHeap(testData, false);

System.out.println("Without heapify: " + time1 + " s");

double time2 = testHeap(testData, true);

System.out.println("With heapify: " + time2 + " s");

}

}

基于堆的优先队列

public class PriorityQueue> implements Queue {

private MaxHeap maxHeap;

public PriorityQueue(){

maxHeap = new MaxHeap<>();

}

@Override

public int getSize(){

return maxHeap.size();

}

@Override

public boolean isEmpty(){

return maxHeap.isEmpty();

}

@Override

public E getFront(){

return maxHeap.findMax();

}

@Override

public void enqueue(E e){

maxHeap.add(e);

}

@Override

public E dequeue(){

return maxHeap.extractMax();

}

}

在 100 0000个元素中选出前100名?(Leetcode347前K个高频元素)

AAffA0nNPuCLAAAAAElFTkSuQmCC

private class Freq implements Comparable{

public int e, freq;

public Freq(int e, int freq){

this.e = e;

this.freq = freq;

}

@Override

public int compareTo(Freq another){

if(this.freq < another.freq)

return 1;

else if(this.freq > another.freq)

return -1;

else

return 0;

}

}

public List topKFrequent(int[] nums, int k) {

TreeMap map = new TreeMap<>();

for(int num: nums){

if(map.containsKey(num))

map.put(num, map.get(num) + 1);

else

map.put(num, 1);

}

PriorityQueue pq = new PriorityQueue<>();

for(int key: map.keySet()){

if(pq.getSize() < k)

pq.enqueue(new Freq(key, map.get(key)));

else if(map.get(key) > pq.getFront().freq){

pq.dequeue();

pq.enqueue(new Freq(key, map.get(key)));

}

}

LinkedList res = new LinkedList<>();

while(!pq.isEmpty())

res.add(pq.dequeue().e);

return res;

}

private static void printList(List nums){

for(Integer num: nums)

System.out.print(num + " ");

System.out.println();

}

public static void main(String[] args) {

int[] nums = {1, 1, 1, 2, 2, 3};

int k = 2;

printList((new Solution()).topKFrequent(nums, k));

}

}

Java中的PriorityQueue

Java的Priority是最小堆

/// 347. Top K Frequent Elements

/// https://leetcode.com/problems/top-k-frequent-elements/description/

import java.util.*;

public class Solution2 {

private class Freq{

public int e, freq;

public Freq(int e, int freq){

this.e = e;

this.freq = freq;

}

}

private class FreqComparator implements Comparator{

@Override

public int compare(Freq a, Freq b){

return a.freq - b.freq;

}

}

public List topKFrequent(int[] nums, int k) {

TreeMap map = new TreeMap<>();

for(int num: nums){

if(map.containsKey(num))

map.put(num, map.get(num) + 1);

else

map.put(num, 1);

}

PriorityQueue pq = new PriorityQueue<>(new FreqComparator());

for(int key: map.keySet()){

if(pq.size() < k)

pq.add(new Freq(key, map.get(key)));

else if(map.get(key) > pq.peek().freq){

pq.remove();

pq.add(new Freq(key, map.get(key)));

}

}

LinkedList res = new LinkedList<>();

while(!pq.isEmpty())

res.add(pq.remove().e);

return res;

}

private static void printList(List nums){

for(Integer num: nums)

System.out.print(num + " ");

System.out.println();

}

public static void main(String[] args) {

int[] nums = {1, 1, 1, 2, 2, 3};

int k = 2;

printList((new Solution()).topKFrequent(nums, k));

}

}

优化

/// 347. Top K Frequent Elements

/// https://leetcode.com/problems/top-k-frequent-elements/description/

import java.util.*;

public class Solution2 {

private class Freq{

public int e, freq;

public Freq(int e, int freq){

this.e = e;

this.freq = freq;

}

}

public List topKFrequent(int[] nums, int k) {

TreeMap map = new TreeMap<>();

for(int num: nums){

if(map.containsKey(num))

map.put(num, map.get(num) + 1);

else

map.put(num, 1);

}

// 将只使用一次的类声明写成一个匿名类(变量捕获,拿到所有的不可改变的变量)

// 优点:可以方便的使用匿名类改变类型

// 只获取元素Integer,然后根据元素获取频率

PriorityQueue pq = new PriorityQueue<>(new Comparator(){

@Override

public int compare(Integer a,Integer b){

return map.get(a) - map.get(b);

}

});

// lamba表达式

// PriorityQueue pq = new PriorityQueue<>(

// (a,b) -> map.get(a) - map.get(b);

// );

for(int key: map.keySet()){

if(pq.size() < k)

pq.add(key);

else if(map.get(key) > map.get(pq.peek())){

pq.remove();

pq.add(key);

}

}

LinkedList res = new LinkedList<>();

while(!pq.isEmpty())

res.add(pq.remove());

return res;

}

private static void printList(List nums){

for(Integer num: nums)

System.out.print(num + " ");

System.out.println();

}

public static void main(String[] args) {

int[] nums = {1, 1, 1, 2, 2, 3};

int k = 2;

printList((new Solution()).topKFrequent(nums, k));

}

}

拓展

AAffA0nNPuCLAAAAAElFTkSuQmCC

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值