阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

使用PriorityQueue

31次阅读
没有评论

共计 2228 个字符,预计需要花费 6 分钟才能阅读完成。

我们知道,Queue是一个先进先出(FIFO)的队列。

在银行柜台办业务时,我们假设只有一个柜台在办理业务,但是办理业务的人很多,怎么办?

可以每个人先取一个号,例如:A1A2A3……然后,按照号码顺序依次办理,实际上这就是一个Queue

如果这时来了一个 VIP 客户,他的号码是V1,虽然当前排队的是A10A11A12……但是柜台下一个呼叫的客户号码却是V1

这个时候,我们发现,要实现“VIP 插队”的业务,用 Queue 就不行了,因为 Queue 会严格按 FIFO 的原则取出队首元素。我们需要的是优先队列:PriorityQueue

PriorityQueueQueue 的区别在于,它的出队顺序与元素的优先级有关,对 PriorityQueue 调用 remove()poll()方法,返回的总是优先级最高的元素。

要使用 PriorityQueue,我们就必须给每个元素定义“优先级”。我们以实际代码为例,先看看PriorityQueue 的行为:

import java.util.PriorityQueue;
import java.util.Queue;

public class Main {public static void main(String[] args) {Queue<String> q = new PriorityQueue<>();
        // 添加 3 个元素到队列:
        q.offer("apple");
        q.offer("pear");
        q.offer("banana");
        System.out.println(q.poll()); // apple
        System.out.println(q.poll()); // banana
        System.out.println(q.poll()); // pear
        System.out.println(q.poll()); // null, 因为队列为空
    }
}

我们放入的顺序是 "apple""pear""banana",但是取出的顺序却是"apple""banana""pear",这是因为从字符串的排序看,"apple" 排在最前面,"pear"排在最后面。

因此,放入 PriorityQueue 的元素,必须实现 Comparable 接口,PriorityQueue会根据元素的排序顺序决定出队的优先级。

如果我们要放入的元素并没有实现 Comparable 接口怎么办?PriorityQueue允许我们提供一个 Comparator 对象来判断两个元素的顺序。我们以银行排队业务为例,实现一个PriorityQueue

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

public class Main {public static void main(String[] args) {Queue<User> q = new PriorityQueue<>(new UserComparator());
        // 添加 3 个元素到队列:
        q.offer(new User("Bob", "A1"));
        q.offer(new User("Alice", "A2"));
        q.offer(new User("Boss", "V1"));
        System.out.println(q.poll()); // Boss/V1
        System.out.println(q.poll()); // Bob/A1
        System.out.println(q.poll()); // Alice/A2
        System.out.println(q.poll()); // null, 因为队列为空
    }
}

class UserComparator implements Comparator<User> {public int compare(User u1, User u2) {if (u1.number.charAt(0) == u2.number.charAt(0)) {// 如果两人的号都是 A 开头或者都是 V 开头, 比较号的大小:
            return u1.number.compareTo(u2.number);
        }
        if (u1.number.charAt(0) == 'V') {// u1 的号码是 V 开头, 优先级高:
            return -1;
        } else {return 1;
        }
    }
}

class User {public final String name;
    public final String number;

    public User(String name, String number) {this.name = name;
        this.number = number;
    }

    public String toString() {return name + "/" + number;
    }
}

实现 PriorityQueue 的关键在于提供的 UserComparator 对象,它负责比较两个元素的大小(较小的在前)。UserComparator总是把 V 开头的号码优先返回,只有在开头相同的时候,才比较号码大小。

上面的 UserComparator 的比较逻辑其实还是有问题的,它会把 A10 排在 A2 的前面,请尝试修复该错误。

小结

PriorityQueue实现了一个优先队列:从队首获取元素时,总是获取优先级最高的元素;

PriorityQueue默认按元素比较的顺序排序(必须实现 Comparable 接口),也可以通过 Comparator 自定义排序算法(元素就不必实现 Comparable 接口)。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2228字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中