栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

二叉堆(TopK问题,优先级队列)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二叉堆(TopK问题,优先级队列)

TopK问题常见题型为求最大(最小)的K个值。

我们一般拿堆来解决。

堆:二叉堆首先是一颗完全二叉树

二叉堆结点间的关系满足:

大根堆: 根节点是整棵树的最大值,对于它的任意子树,堆中根节点的值>=子树中的结点值。

小根堆: 根节点是整棵树的最小值,对于它的任意子树,堆中根节点的值<=子树中的结点值。

TopK题型解决:取大用小,取小用大。

(取前100个比较小的树用大根堆,

取前100个比较大的树用小根堆)

实现一个大根堆:

package ds.bin_tree.bin_tree_heap;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;


public class MaxHeap {
    List arr;
    public MaxHeap()
    {
        this(10);
    }
    //初始化堆大小
    public MaxHeap(int size)
    {
        arr=new ArrayList<>(size);
    }
    public void siftUp(int k)
    {
        //上浮条件:结点值大于父节点值||走到根结点
        while (k>0&&arr.get(k)>arr.get(parent(k)))
        {
            swap(k,parent(k));
            k=parent(k);
        }
    }

    
    public MaxHeap(int[] arr2)
    {
        arr=new ArrayList<>(arr2.length);
        MaxHeap maxHeap=new MaxHeap();
        for (int i:arr2)
        {
            arr.add(i);
        }
        //从最后一个非叶子结点开始,依次进行元素下沉
        for (int i=parent(arr.size()-1);i>=0;i--)
        {
            siftDown(i);
        }
    }

    
    public void siftDown(int k)
    {
        //终止条件:走到叶子结点了,k的左子树已经大于数组长度了
        while (leftTree(k)arr.get(i))
            {
                i=i+1;
            }
            if (arr.get(k)>arr.get(i))
            {
                break;
            }
            else
            {
                swap(k,i);
                k=i;
            }
        }
    }
    
    public int extractMax()
    {
        if (isEmpty())
        {
            throw new NoSuchElementException("heap is empty");
        }
      int max=arr.get(0);
        arr.set(0,arr.get(arr.size()-1));
        arr.remove(arr.size()-1);
        siftDown(0);
        return max;
    }

    
    public  int peekMax()
    {
        if (isEmpty())
        {
            throw new NoSuchElementException("heap is empty");
        }
        return arr.get(0);
    }
    private void swap(int i, int j) {
        int temp=arr.get(i);
        //arr.set(元素下标,元素值)
        arr.set(i,arr.get(j));
        arr.set(j,temp);
    }

    public void add(int val)
    {
        arr.add(val);
        siftUp(arr.size()-1);
    }

    

    private int parent(int k)
   {
       return (k-1)/2;
   }

    private boolean isEmpty()
    {
        return arr.size()==0;
    }

    
    private int leftTree(int k)
    {
        return (2*k)+1;
    }

    
    public int rightTree(int k)
    {
        return (2*k)+2;
    }

    @Override
    public String toString() {
        return arr.toString();
    }
}

优先级队列:看起来是队列,底层是基于堆的实现,按照元素的优先级大小动态出队。

(JDK内置优先级是最小堆)

package ds.bin_tree.bin_tree_heap;

import java.util.*;
import java.util.PriorityQueue;




public class PriorityQueueTest {
    public static void main(String[] args) {
        //通过构造方法传入比较器
        //默认是最小堆,“值”(比较器comparator返回的值)越小,优先级越高
        //传入降序比较器。
//        Queue queue=new PriorityQueue<>(new StudentComDesc());
        //匿名内部类,创建一个Comparator接口的子类,这个子类只使用一次
        Queue queue=new PriorityQueue<>(new Comparator()
        {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge()- o2.getAge();
            }
        });
        //Lambda表达式,函数式编程
//      Queue queue=new PriorityQueue<>((o1, o2) -> o1.getAge()-o2.getAge());

        Student  stu = new Student("张三", 19);
        Student stu2 = new Student("李四", 27);
        Student stu3 = new Student("王五", 25);
        queue.offer(stu);
        queue.offer(stu2);
        queue.offer(stu3);
        while (!queue.isEmpty())
        {
            System.out.println(queue.poll());
        }
//        Student[] students={stu,stu2,stu3};
//        Arrays.sort(students);
//        System.out.println(Arrays.toString(students));
//        System.out.println(stu.compareTo(stu2));
//        System.out.println(stu.compareTo(stu3));
//        Student[] students={stu,stu2,stu3};
//        Arrays.sort(students,new StudentCom());
//        System.out.println(Arrays.toString(students));
    }
}
//从小到大顺序
class StudentCom implements Comparator
{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge()-o2.getAge();
    }
}
//从大到小顺序
class StudentComDesc implements Comparator
{

    @Override
    public int compare(Student o1, Student o2) {
        return o2.getAge()-o1.getAge();
    }
}
class Student
{
    private String name;
    private int age;
    public Student(String name,int age)
    {
        this.age=age;
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

Comparable和Compator区别:

比较器Compartor:新建一个类来对内容进行比较。

一个类实现了Comparabe接口,说明该类具备了可比较大小的能力。类本身具备可比较能力。

如:

class Student implements Comparable
{
    private String name;
    private int age;
    public Student(String name,int age)
    {
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.getAge()-o.getAge();
    }
}
TopK问题:

package ds.bin_tree.bin_tree_heap.leetcode;

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


public class Num17_14 {
    public int[] smallestK(int[] arr, int k) {
       if (arr.length==0||k==0)
       {
           return new int[0];
       }
       //构造一个最大堆,JDK默认最小堆,使用比较器改为最大堆。
        Queue queue=new PriorityQueue<>(new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
       for (int i:arr)
       {
           if (queue.size()peek)
               {
                   continue;
               }
               //当前元素<堆顶元素,先出队,再把当前元素入队
               else
               {
                   queue.poll();
                   queue.offer(i);
               }
           }

       }
       int[] ret=new int[k];
       for (int i=0;i 

package ds.bin_tree.bin_tree_heap.leetcode;

import java.util.*;


public class Num347 {
    private class Freq implements Comparable
    {
        private int key;
        private int times;
        public Freq(int key, int times) {
            this.key = key;
            this.times = times;
        }
        @Override
        public int compareTo(Freq o) {
            return this.times-o.times;
        }
    }
    public int[] topKFrequent(int[] nums, int k) {
        int[] ret=new int[k];
        Map map=new HashMap<>();
        for (int i:nums)
        {
            //遍历数组,如果i存在,取得存在的次数再+1,不存在,给一个默认值0 ,次数为0再+1;
            map.put(i, map.getOrDefault(i,0)+1);
        }
        //扫描map集合,将前k个最高频率放入优先级中
        Queue queue=new PriorityQueue<>();
        for (Map.Entryentry: map.entrySet())
        {
            if (queue.size()entry.getValue())
                {
                    continue;
                }
                else
                {
                    queue.poll();
                    queue.offer(new Freq(entry.getKey(),entry.getValue()));
                }
            }
        }
        for (int i=0;i 

 

package ds.bin_tree.bin_tree_heap.leetcode;

import java.util.*;


public class Num373 {
    private class Pair
    {
        //第一个数组中的数
         int u;
        //第二个数组中的数
         int v;
        public Pair(int u, int v) {
            this.u = u;
            this.v = v;
        }
    }
    //前k个最小元素构建大根堆
    public List> kSmallestPairs(int[] nums1, int[] nums2, int k) {
       PriorityQueue queue=new PriorityQueue<>(new Comparator() {
            @Override
            public int compare(Pair o1, Pair o2) {
                return (o2.u+ o2.v)-(o1.u+o1.v);
            }
        });
        for (int i=0;i(pair.u+ pair.v))
                    {
                        continue;
                    }
                    else {
                       queue.poll();
                       queue.offer(new Pair(nums1[i],nums2[j] ));
                    }
                }
            }
        }
        List> ret=new ArrayList<>();
        //当k>数组长度的时候(例如有两个数对,k=3;)不可能出队三次,终止条件要加上!queue.isEmpty
        for (int i = 0; i < k&&(!queue.isEmpty()); i++) {
            List temp=new ArrayList<>();
            Pair pair=queue.poll();
            temp.add(pair.u);
            temp.add(pair.v);
            ret.add(temp);
        }
        Collections.reverse(ret);

     return ret;
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768611.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号