Java中的优先队列

探讨了如何从海量URL中统计并找出被搜索次数最高的URL,提出了使用优先队列进行排序的方法,并通过Java代码示例展示了如何实现。

Form一个问题

假设百度搜索引擎一天会搜索M亿条URL,如何根据URL被搜索的次数来找出次数最高的N个URL呢?
个人有一个抽象的思路:
- 先对所有的URL日志文档进行整合,同一类型的当作一个结点,利用B或者B+树搜索的优秀性能来处理
- 再使用优先队列或者是最大值堆来进行一个排序

正确与否先撇开不谈,整合同类URL的过程中会给后续排序减少大量的工作量(但究竟对于这种亿级的数据量还是只有一个朦胧的概念)。不管怎么说,先来研究一下Java中的优先队列好了

优先队列和遍历层次树

优先队列(PriorityQueue)是不同于普通队列的先进先出的队列,每次从队列中取出的是具有最高优先权的元素。这是从Java1.5开始引入的数据结构的接口。

// TestPriorityQueue.java
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;

class Student{
    int id;
    String name;

    public Student(){
        this.id = 0;
        this.name = "";
    }

    public Student(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
}

public class TestPriorityQueue {

    private static Comparator<Student> stCompare = new Comparator<Student>(){
        // 重写了比较器中的compare方法,否则直接把Student类型的元素加入优先队列会报错
        @Override
        public int compare(Student st1,Student st2){
            // 针对Student的id属性进行比较
            return (int)(st1.getId()-st2.getId());
        }
    };

    public static void main(String[] args){
        Queue<Integer> number = new PriorityQueue<Integer>();// 存放int类型的数据
        Random rand = new Random();
        for(int i=0;i<5;i++){
            //因为实例化时使用了默认的比较器,所以队列新增的元素时都会自动排序
            number.add(rand.nextInt(100));
        }
        for(Integer i : number){
            System.out.println(i);
        }
        System.out.println();

        // ----- 下面开始排序自定义类
        // 把重写后的比较器作为参数传入优先队列
        Queue<Student> students = new PriorityQueue<Student>(5,stCompare);
        for(int i=0;i<5;i++){
            students.add(new Student(rand.nextInt(10),String.valueOf(i)));
        }

        // 预计的输出结果会是:不管st.name是怎样的顺序,但是st.id一定是由小到大
        for(Student st : students){
            System.out.println(st.id + " " + st.name);
        }
    }
}

遍历层次树

怎么百度的都是概念层次树(黑人问号….),相关的知识有如何层次遍历二叉树,思路是
- 使其根节点入队列,然后出队进行访问
- 若左子节点不为空,使左子节点入队
- 若该节点的右子节点,再使右子节点入队
- 重复上面三个步骤,直到访问了所有节点

大概的思路是这样,开的坑已经够多了,这个就先放后面好了 /:doge

又回到了HashMap高性能读写方法?

其实是自己没有绕出这个圈,那天和dalao讨论的时候,ta认为没有什么优化的方法,毕竟HashMap已经被写好放在jar中了,若是使用,怎么会优化呢?

of cause,自己撸一个HashMap实现,这就引出了一个重点,在我们讨论这个问题的时候,前提是什么?,有说可以自己撸吗?不知道,有说必须要用jdk中的HashMap吗?不知道。

So,…….

日常总结

今天被教育“凡是遇到问题的时候,第一个想到的就应该是前提条件”,没有前提条件,问题是不受约束的。看似是一个谁都懂的道理,但真的很多时候,会被自己潜意识认为的条件局限了自己的思维。就这样。

Java中的优先队列通常使用`PriorityQueue`类来实现,它是基于堆结构(默认是最小堆)的队列,以下是它的使用方法和特性: ### 使用方法 可以通过以下步骤使用`PriorityQueue`: 1. **导入包**:使用`PriorityQueue`需要导入`java.util.PriorityQueue`包。 2. **初始化优先队列**:创建`PriorityQueue`对象,可以指定初始容量。 3. **添加元素**:使用`offer()`方法将元素添加到队列中。 4. **获取元素**:使用`peek()`方法获取队列中优先级最高元素(最小堆中为最小值)。 5. **删除元素**:使用`poll()`方法删除并返回队列中优先级最高元素。 6. **清空队列**:使用`clear()`方法清空队列中的所有元素。 7. **检查队列是否为空**:使用`isEmpty()`方法检查队列是否为空。 以下是一个示例代码: ```java import java.util.PriorityQueue; public class Test { public static void main(String[] args) { // 初始化一个整数数组 int[] arr = {4, 1, 9, 2, 8, 0, 7, 3, 6, 5}; PriorityQueue<Integer> q = new PriorityQueue<>(arr.length); // 将数组中的元素添加到优先级队列中 for (int e : arr) { q.offer(e); } // 打印优先级队列中有效元素的个数 System.out.println(q.size()); // 获取并打印优先级队列中优先级最高元素(即最小值,因为是最小堆) System.out.println(q.peek()); // 从优先级队列中删除两个元素 q.poll(); q.poll(); // 打印删除两个元素后,优先级队列中有效元素的个数 System.out.println(q.size()); // 获取并打印当前优先级最高元素 System.out.println(q.peek()); // 向优先级队列中插入一个新的元素 q.offer(0); // 获取并打印插入新元素后的优先级最高元素 System.out.println(q.peek()); // 清空优先级队列中的所有有效元素 q.clear(); // 检测优先级队列是否为空,并打印结果 if (q.isEmpty()) { System.out.println("优先级队列已经为空!!!"); } else { System.out.println("优先级队列不为空"); } } } ``` ### 特性 - **优先排序**:`PriorityQueue`会根据元素的自然顺序(或指定的比较器)对元素进行排序,每次取出的元素都是优先级最高元素(默认是最小值)。 - **堆结构**:基于堆结构实现,插入和删除操作的时间复杂度为$O(log n)$,其中$n$是队列元素的数量。 - **动态调整**:插入和删除操作可能会破坏堆的结构,因此每次操作后会自动调整堆结构,以保证队列的有序性。 - **允许重复元素**:`PriorityQueue`允许存储重复的元素。 - **不允许`null`元素**:`PriorityQueue`不允许插入`null`元素,否则会抛出`NullPointerException`异常。 - **非线程安全**:`PriorityQueue`是非线程安全的,如果需要在多线程环境中使用,可以考虑使用`PriorityBlockingQueue`。 ### 自定义比较器 如果需要使用自定义的排序规则,可以在创建`PriorityQueue`对象时传入一个比较器(`Comparator`)。例如,创建一个最大堆: ```java import java.util.Comparator; import java.util.PriorityQueue; public class MaxHeapExample { public static void main(String[] args) { PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); maxHeap.offer(4); maxHeap.offer(1); maxHeap.offer(9); System.out.println(maxHeap.peek()); // 输出 9 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值