优先级队列的实现

目录

目录

1.优先级队列的介绍

2.优先级队列最大堆的简单实现

3.自定义类型元素间的大小比较 (覆写了equals方法,equals默认是比较地址)

4.比较两个自定义对象谁大谁小(用Comparable接口)

4.有时候要升序、有时候需要降序用java util.Comparator-比较器

5.用Comparator将JDK的最小堆改造为最大堆使用

6.笔试题:最小k个数(非常爱考的问题)

    6.1最小k个数

    6.2前k个高频元素(这个系列最难的一道题)

1.优先级队列的介绍

优先级队列虽然名字叫队列,但是底层是基于堆的实现,是按照元素间的优先级大小顺序动态(处理的元素个数是动态变化的)出队。

任务管理器就是一个优先级队列。

优先级队列与不同队列的区别

JDK内置的优先级队列默认是最小堆的实现,队首元素就是当前队列的最小值。(所以后面通过比较器把内置最小堆改为了最大堆)

2.优先级队列最大堆的简单实现

覆写了我之前自己写的队列的四个方法,通过自己的实现的二叉堆MaxHeap进行了优先级队列的简单实现。

这个代码执行出来是倒序的一组数字

 下面是测试的代码 

3.自定义类型元素间的大小比较 (覆写了equals方法,equals默认是比较地址)

传入的o是否是Student类new出来的
        if (!(o instanceof Student)) {
            return false;
        }

比较两个自定义的类型是否相等

public class PriorityQueueTest {
    public static void main(String[] args) {
        Student stu1 = new Student("张三", 10);
        Student stu2 = new Student("李四", 20);
        Student stu3 = new Student("王淇", 30);
        System.out.println(stu1.equals(stu3));
    }
}
        class Student {
            String name;
            int age;
            public Student(String name, int age) {
                this.name = name;
                this.age = age;
            }

           // 将当前对象和传入的对象比较
            @Override
            public boolean equals(Object o) {
                if (o == null) {
                    return false;
                }
                if (this == o) {
                    return true;
                }
                //传入的o是否是Student类new出来的,如果不是,返回false
                if (!(o instanceof Student)) {
                    return false;
                }
                //向下转型还原为Student类
                Student stu = (Student) o;
                return this.age == stu.age && this.name.equals(stu.name);
            }
            @Override
            public String toString() {
                return "student{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }

4.比较两个自定义对象谁大谁小(用Comparable接口)

public class PriorityQueueTest {
    public static void main(String[] args) {
        Student stu1 = new Student("张三", 10);
        Student stu2 = new Student("李四", 20);
        Student stu3 = new Student("王淇", 5);
        System.out.println(stu1.compareTo(stu2));
        System.out.println(stu2.compareTo(stu3));
    }
}
        class Student implements Comparable<Student>{
            String name;
            int age;
            public Student(String name, int age) {
                this.name = name;
                this.age = age;
            }

           // 将当前对象和传入的对象比较
            @Override
            public boolean equals(Object o) {
                if (o == null) {
                    return false;
                }
                if (this == o) {
                    return true;
                }
                //传入的o是否是Student类new出来的,如果不是,返回false
                if (!(o instanceof Student)) {
                    return false;
                }
                //向下转型还原为Student类
                Student stu = (Student) o;
                return this.age == stu.age && this.name.equals(stu.name);
            }
            @Override
            public String toString() {
                return "student{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
            @Override
            public int compareTo(Student o) {
                return this.age-o.age;//被减数和减数反一下就变成了降序排序
            }
        }

 然后我把自定义类型的数据放在数组里进行了排序

排序方法默认是升序的,如果要降序,就更改一下CompareTo方法 ,如下,就可降序排序

 

4.有时候要升序、有时候需要降序用java util.Comparator-比较器

就是创建了基于此接口的俩个类一个升序一个降序

public class PriorityQueueTest {
    public static void main(String[] args) {
        Student stu1 = new Student("张三", 40);
        Student stu2 = new Student("李四", 20);
        Student stu3 = new Student("王淇", 5);
      //构造一个对象数组
        Student[] students ={stu1,stu2,stu3};
       //对数组排序,排序默认是升序
       Arrays.sort(students,new StudentComDesc());
        System.out.println(Arrays.toString(students));
    }
}
//升序排序
class StudentCom implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge() - o2.getAge();
    }
}
//降序排序
class StudentComDesc implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge()-o2.getAge();
    }
}
class Student  {
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    // 将当前对象和传入的对象比较
    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (this == o) {
                    return true;
        }
        //传入的o是否是Student类new出来的,如果不是,返回false
        if (!(o instanceof Student)) {
            return false;
        }
        //向下转型还原为Student类
        Student stu = (Student) o;
        return this.age == stu.age && this.name.equals(stu.name);
    }
    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

执行代码的截图

 使用Comparator相比Comparable来说更加灵活,无侵入编程(策略模式)

5.用Comparator将JDK的最小堆改造为最大堆使用

第一种写法:

public class PriorityQueueTest {
    public static void main(String[] args) {
        //通过构造方法传入比较器
        //这是对优先级队列的声明
        //默认是最小堆,“值”(比较器Compare的返回值越小,优先级越高)
       // Queue<Student> queue =new PriorityQueue<>(new StudentCom());
        //传入降序比较器时,“值”(比较器Compare的返回值越大,返回复数,优先级越高)
       // Queue<Student> queue =new PriorityQueue<>(new StudentComDesc());
        //第二种写法

        /*Queue<Student> queue =new PriorityQueue<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return  o1.getAge() - o2.getAge();
            }
        });*/
        //函数式编程
        Queue<Student> queue =new PriorityQueue<>((o1,o2) -> o2.getAge()- o1.getAge());
        Student stu1 = new Student("张三", 40);
        Student stu2 = new Student("李四", 20);
        Student stu3 = new Student("王淇", 18);
        //入队
        queue.offer(stu1);
        queue.offer(stu2);
        queue.offer(stu3);
        System.out.println(queue);
        while(!queue.isEmpty()){
            System.out.println(queue.poll());
        }
    }
}
//升序排序
class StudentCom implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge() - o2.getAge();
    }
}
//降序排序
class StudentComDesc implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o2.getAge()-o1.getAge();
    }
}
class Student  {
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    // 将当前对象和传入的对象比较
    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (this == o) {
                    return true;
        }
        //传入的o是否是Student类new出来的,如果不是,返回false
        if (!(o instanceof Student)) {
            return false;
        }
        //向下转型还原为Student类
        Student stu = (Student) o;
        return this.age == stu.age && this.name.equals(stu.name);
    }
    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

第二种写法:(匿名内部类) 

第三种写法:(函数式编程)

了解即可

6.笔试题:最小k个数(非常爱考的问题)

6.1最小k个数

 看到找最小或者在最大,都是优先级队列

找最大k的思路: 以找最大的三个数为例:构造只有三个元素的最小堆,最小堆中就存放最大的三个元素

然后把小的换出堆,把大的换进堆中,保留堆中的三个元素

public class Num17_14_SmallestK {
    public int[] smallest(int[] arr, int k) {
        if (arr.length == 0 || k == 0) {
            return new int[0];
        }
        //构造一个最大堆,JDK默认是最小堆,用比较器改造为最大堆
        //要把最小堆改为最大堆,就是要告诉编译器值越大,让编译器来看反而小
        Queue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        for (int i:arr) {
            if(queue.size()<k){
                queue.offer(i);
            }else{
                //比较当前元素与栈顶元素的大小
                //大于堆顶元素,则大于堆中的所有值
                int peek = queue.peek();
                if(i>peek){
                    continue;
                }else{
                    //小于堆顶元素,出堆顶,入、i
                    queue.poll();
                    queue.offer(i);
                }
            }
        }
        int[] ret =new int[k];
        for (int i = 0; i < k; i++) {
            ret[i] =queue.poll();
        }
        return ret;
    }
}

6.2前k个高频元素(这个系列最难的一道题)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
A*算法是一种启发式搜索算法,它使用优先级队列实现。在A*算法的运算过程中,每次从优先队列中选取f(n)值最小(优先级最高)的节点作为下一个待遍历的节点。同时,A*算法使用两个集合来表示待遍历的节点和已经遍历过的节点,通常称之为open_set和close_set。其中,open_set表示待遍历的节点集合,close_set表示已经遍历过的节点集合。 在实现A*算法时,我们需要使用优先级队列来存储待遍历的节点。C++提供了一个priority_queue类,它使用了二叉堆来实现,因此不能为元素重新设置优先级。为了解决这个问题,我们可以使用pair(priority, item)作为队列元素,并进行排序。在C++中,优先队列默认返回优先级最大的元素,使用的是std::less比较符。但是,在A*算法中,我们需要的是最小的元素,因此需要使用std::greater比较符。 下面是一个使用优先级队列实现A*算法的伪代码: 1. 将起点加入open_set中 2. while open_set不为空 3. 从open_set中取出f(n)值最小的节点n 4. 如果n是终点,则返回路径 5. 将n加入close_set中 6. 对n的所有邻居节点进行如下操作 7. 如果邻居节点已经在close_set中,则跳过 8. 如果邻居节点不在open_set中,则加入open_set中,并计算邻居节点的f(n)值 9. 如果邻居节点已经在open_set中,并且新的f(n)值比原来的小,则更新邻居节点的f(n)值 10. 返回无解

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值