make-big-money

在之前我们使用了二分搜索树实现了集合和映射,

从本节起将介绍4个不同树结构的例子

  • 线段树
  • 字典树
  • 并查集

 

优先队列本质就是队列,

所以优先队列可以使用队列的接口,只是在实现接口时,与普通队列有两处区别,

一处在于优先队列出队的元素应该是优先级最高的元素,另一处在于队首元素也是优先级最高的元素。

 

 

 对于上面的2种线性结构,可以使用动态数组或链表这样的底层实现。

  • 本节优先队列底层实现采用堆。
  • 从上图可以看出,使用"堆"这种数据结构来实现优先队列是比较高效的。

8-2 堆的基础表示

二叉堆(Binary Heap)
  • 二叉堆就是一棵满足特殊性质的二叉树
  • 首先,二叉堆是一棵完全二叉树,"完全二叉树",不一定是满二叉树,不满的部分一定位于整棵树的右下侧。
  • 其次,堆中根节点的值是最大的称为最大堆;相应的,堆中根节点的值是小于等于孩子节点的值的称为最小堆。
  • 节点值的大小与其所处的层次没有必然联系,即,最大堆中,只需保证每个节点不大于其父节点即可,至于大不大于其父节点的兄弟节点,没有任何关系。
  • 可以用数组来存储二叉堆,如下图所示:

 

 

 

8-3 向堆中添加元素和Sift Up

添加的52不满足堆的性质,要进行调整。(52大于16)

出问题只可能出现在52的父亲节点和52的父亲节点的父亲节点这一路上。

所以,要做的是:从52开始,依次和它的父亲节点做比较。

调整节点位置后,如下

 

 这个过程就叫做Sift Up,节点的上浮过程。

 

 1  // 实现add方法,向堆中添加元素
 2     public void add(E e) {
 3         data.addLast(e);//向整个数组的末尾添加上元素,由于data是我们之前实现的动态数组Array,所以不需要管容积的问题
 4         SiftUp(data.getSize() - 1);//维护堆的性质,传入的参数表示:希望上浮的元素对应的索引是谁,
 5                             //这里是:新加入的元素e所在的索引,也就是整个数组中最后一个元素所在的索引.
 6                             //getSize()获取数组长度,在Array类中实现
 7     }
 8 
 9     // 实现元素的上浮
10     private void SiftUp(int k) {  //k是索引,k=0表示根节点的索引
11         while (k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0) {//get()获取index索引位置的元素,parent(k)表示父亲节点的索引
12             data.swap(k, parent(k));//如果父亲节点的元素值小于我们要加入的元素值,交互两个数,实现上浮。
13             k = parent(k);//更新要加入元素的索引值。
14         }
15     }

 

8-4 从堆中取出元素和Sift Down

从堆中取出元素只能取出堆中最大的元素,

取出最大元素62,把最底部元素放入索引为0的位置,变成:

再调整,执行sift Down(下沉),下沉元素每次都和它的孩子元素比较,和2个孩子中最大的元素交换位置(如果两个孩子比它大)。

 

 

 下沉代码

 1     // 实现findMax方法,查看堆中的最大元素
 2     public E findMax() {
 3         if (data.getSize() == 0) {
 4             throw new IllegalArgumentException("Can not findMax when heap is empty.");
 5         }
 6         return data.get(0);
 7     }
 8 
 9     // 实现extractMax方法,取出堆中的最大元素
10     public E extractMax() {
11         E ret = findMax();
12           //删除堆中最大元素
13         data.swap(0, data.getSize() - 1);//将索引为0的元素和末尾元素交换
14         data.removeLast();
15         SiftDown(0);//下沉
16           //--删除操作结束---
17         return ret;//取出堆中的最大元素,返回
18     }
19 
20     // 实现元素的下沉
21     private void SiftDown(int k) {
22         while (leftChild(k) < data.getSize()) {//k的左孩子的索引如果越界了,就跳出while。即K所在的节点都已经没有孩子了,
23                                                 //肯定要结束循环。注:右孩子对应的索引比左孩子要大。
24             int j = leftChild(k);//左孩子所在的索引。j+1:右孩子所对应的索引   //get()获取index索引位置的元素
25             if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0) {
26                 j = rightChild(k);//如果右孩子存在,并且对应的节点值大于左孩子的值,执行该步,此时j存储的是右孩子对应的索引
27                 // data[j]是leftChild和rightChild中的对大值
28             }
29             if (data.get(k).compareTo(data.get(j)) >= 0) {
30                 break;//比较索引k的元素值大于它孩子的值,结束。
31             } else {            //比较索引k的元素值小于它孩子的值,
32                 data.swap(k, j);//元素互换
33                 k = j;//更新下沉元素索引
34             }
35         }
36     }

 

  • 总的用动态数组实现二叉堆的业务逻辑如下:
  1  public class MaxHeap<E extends Comparable<E>> {
  2 
  3     private Array<E> data = new Array<>();
  4 
  5     // 构造函数
  6     public MaxHeap(int capacity) {
  7         data = new Array<>(capacity);
  8     }
  9 
 10     // 无参数构造函数
 11     public MaxHeap() {
 12         data = new Array<>();
 13     }
 14 
 15     // 接收参数为数组的构造函数
 16     public MaxHeap(E[] arr) {
 17         data = new Array<>(arr);
 18         for (int i = parent(arr.length - 1); i >= 0; i--) {
 19             SiftDown(i);
 20         }
 21     }
 22 
 23     // 实现getSize方法,返回堆中的元素个数
 24     public int getSize() {
 25         return data.getSize();
 26     }
 27 
 28     // 实现isEmpty方法,返回堆是否为空
 29     public boolean isEmpty() {
 30         return data.isEmpty();
 31     }
 32 
 33     // 返回完全二叉树的数组表示中,一个索引所表示的元素的父节点的索引
 34     private int parent(int index) {
 35         if (index == 0) {
 36             throw new IllegalArgumentException("Index-0 doesn\'t have parent.");
 37         }
 38         return (index - 1) / 2;
 39     }
 40 
 41     // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子的索引
 42     private int leftChild(int index) {
 43         return index * 2 + 1;
 44     }
 45 
 46     // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子的索引
 47     private int rightChild(int index) {
 48         return index * 2 + 2;
 49     }
 50 
 51     // 实现add方法,向堆中添加元素
 52     public void add(E e) {
 53         data.addLast(e);//向整个数组的末尾添加上元素,由于data是我们之前实现的动态数组Array,所以不需要管容积的问题
 54         SiftUp(data.getSize() - 1);//维护堆的性质,传入的参数表示:希望上浮的元素对应的索引是谁,
 55                             //这里是:新加入的元素e所在的索引,也就是整个数组中最后一个元素所在的索引.
 56                             //getSize()获取数组长度,在Array类中实现
 57     }
 58 
 59     // 实现元素的上浮
 60     private void SiftUp(int k) {  //k是索引,k=0表示根节点的索引
 61         while (k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0) {//get()获取index索引位置的元素,parent(k)表示父亲节点的索引
 62             data.swap(k, parent(k));//如果父亲节点的元素值小于我们要加入的元素值,交互两个数,实现上浮。
 63             k = parent(k);//更新要加入元素的索引k的值。
 64         }
 65     }
 66 
 67     // 实现findMax方法,查看堆中的最大元素
 68     public E findMax() {
 69         if (data.getSize() == 0) {
 70             throw new IllegalArgumentException("Can not findMax when heap is empty.");
 71         }
 72         return data.get(0);
 73     }
 74 
 75     // 实现extractMax方法,取出堆中的最大元素
 76     public E extractMax() {
 77         E ret = findMax();
 78           //删除堆中最大元素
 79         data.swap(0, data.getSize() - 1);//将索引为0的元素和末尾元素交换
 80         data.removeLast();
 81         SiftDown(0);//下沉
 82           //--删除操作结束---
 83         return ret;//取出堆中的最大元素,返回
 84     }
 85 
 86     // 实现元素的下沉
 87     private void SiftDown(int k) {
 88         while (leftChild(k) < data.getSize()) {//k的左孩子的索引如果越界了,就跳出while。即K所在的节点都已经没有孩子了,
 89                                                 //肯定要结束循环。注:右孩子对应的索引比左孩子要大。
 90             int j = leftChild(k);//左孩子所在的索引。j+1:右孩子所对应的索引   //get()获取index索引位置的元素
 91             if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0) {
 92                 j = rightChild(k);//如果右孩子存在,并且对应的节点值大于左孩子的值,执行该步,此时j存储的是右孩子对应的索引
 93                 // data[j]是leftChild和rightChild中的对大值
 94             }
 95             if (data.get(k).compareTo(data.get(j)) >= 0) {
 96                 break;//比较索引k的元素值大于它孩子的值,结束。
 97             } else {            //比较索引k的元素值小于它孩子的值,
 98                 data.swap(k, j);//元素互换
 99                 k = j;//更新下沉元素索引k的值
100             }
101         }
102     }
103 
104     
105    }
  • 测试用动态数组实现的二叉堆
 1 import java.util.Random;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6 
 7         int n = 1000000;
 8         MaxHeap<Integer> maxHeap = new MaxHeap<>();
 9         Random random = new Random();
10         for (int i = 0; i < n; i++) {
11             maxHeap.add(random.nextInt(Integer.MAX_VALUE));//添加在(0,Integer的最大值)范围内的n个随机数到maxHeap中
12         }
13 
14         int[] arr = new int[n];
15         for (int i = 0; i < n; i++) {
16             arr[i] = maxHeap.extractMax();//将n个元素按最大堆的extractMax()方法取出,相当于对n个数进行从大到小排序,
17         }
18 
19         for (int i = 1; i < n; i++) {//验证extractMax()方法
20             if (arr[i - 1] < arr[i]) {
21                 throw new IllegalArgumentException("Error");
22             }
23         }
24 
25         System.out.println("Test MaxHeap completed.");
26     }
27 }

 

 

 

 8-5 Heapify 和 Replace

一、replace
定义:取出最大元素后,放入一个新元素【堆中总数没有变化】

实现方法:1.可以先 extractMax,再 add,两次O(log n)的操作;

                  2.可以直接将堆顶元素替换以后 Sift Down,一次 O(log n)的操作;

1    // 实现replace方法,取出堆中的最大元素,并替换为元素e
2     public E replace(E e) {
3         E ret = findMax();//取出堆中的最大元素ret
4         data.set(0, e);//将堆顶元素换成要替换的元素
5         SiftDown(0);//新的堆顶元素可能违背堆的性质,进行SiftDown
6         return ret;//查看堆中的最大元素ret
7     }

 

定义:将任意数组整理成堆的形状;

方法:将当前数组看做完全二叉树,从当前最后一个非叶子节点开始;即图中的 22 ;【最后一个非叶子节点的索引:拿到最后一个叶子节点,根据这个叶子节点来计算其父亲节点的索引即可】

从 22 开始,不断进行下沉操作

索引为3 的是13,对其进行下沉操作,交换 41 和 13;

索引为 2 的是19,对其进行下沉操作

对索引为 1 、0 的继续进行下沉,得到最终的二叉树

 

 

实现

public class Array<E> {}中添加
1     public Array(E[] arr){    //本节新添加,Array支持用户传来一个数组arr,根据arr,生成一个动态数组
2         data = (E[])new Object[arr.length];
3         for(int i = 0 ; i < arr.length ; i ++)
4             data[i] = arr[i];
5         size = arr.length;
6     }

 

public class MaxHeap<E extends Comparable<E>> {}中添加
1  public MaxHeap(E[] arr){//传入数组arr,将arr数组转化成堆的形状,并且放入data对应的动态数组中
2         data = new Array<>(arr);//Array支持用户传来一个数组arr,根据arr,生成一个动态数组,data中存放arr所有元素
3         for(int i = parent(arr.length - 1) ; i >= 0 ; i --)//parent(arr.length - 1):最后一个节点的父节点。即从最后一个非叶子节点开始
4             siftDown(i);//每次对i个节点进行下沉操作。
5     }

 

8-6 基于堆的优先队列

首先我们的队列仍然需要继承我们之前讲队列时候声明的那个接口Queue,然后实现这个接口中的方法就可以了,之类简单写一下:

Queue.java

1 public interface Queue<E> {
2  
3     int getSize();
4     boolean isEmpty();
5     void enqueue(E e);
6     E dequeue();
7     E getFront();
8 }

 

实现优先队列的业务逻辑如下

 1 public class PriorityQueue<E extends Comparable<E>> implements Queue<E> {  //E:泛型,优先队列必须可比较,要实现Comparable接口。
 2                                                                         //PriorityQueue实现了Queue接口
 3 
 4     private MaxHeap<E> maxHeap;
 5 
 6     public PriorityQueue(){
 7         maxHeap = new MaxHeap<>();
 8     }
 9 
10     @Override
11     public int getSize(){
12         return maxHeap.size();
13     }
14 
15     @Override
16     public boolean isEmpty(){
17         return maxHeap.isEmpty();
18     }
19 
20     @Override
21     public E getFront(){//获取队首元素
22         return maxHeap.findMax();//实际上,就是获取最大堆堆顶的元素
23     }
24 
25     @Override
26     public void enqueue(E e){//入队操作,添加元素e
27         maxHeap.add(e);
28     }
29 
30     @Override
31     public E dequeue(){//出队操作
32         return maxHeap.extractMax();//提出最大值
33     }
34 }

 

8-8 Java中的PriorityQueue

 

 

二、优先队列的经典问题
在100 0000 个元素中选出前 100 个元素【在N个元素中选出前M个元素,M<<N】

解决方法:

1.使用高级排序(归并等)时间复杂度为 NlogN;

2.使用优先队列时间复杂度为 NlogM;(M<<N)

使用优先队列方法思路:【使用最小堆】

使用优先队列维护当前看到的前M个元素,将N个元素中的前M个元素放入优先队列中,之后每看到一个新的元素,如果这个新的元素比优先队列中最小的元素还要大的话,就用这个新的元素取代优先队列中的最小元素;直到遍历完所有N个元素,这时留在其中的M个元素就是我们所要找的M个元素。

题目链接

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

求频次,之前将映射,可以使用底层基于二分搜索树的Map类来完成,这里我们采用

TreeMap类
  1 /// 347. Top K Frequent Elements
  2 /// https://leetcode.com/problems/top-k-frequent-elements/description/
  3 
  4 import java.util.LinkedList;
  5 import java.util.List;
  6 import java.util.TreeMap;
  7 
  8 class Solution {
  9 
 10     private class Array<E> {
 11 
 12         private E[] data;
 13         private int size;
 14 
 15         // 构造函数,传入数组的容量capacity构造Array
 16         public Array(int capacity){
 17             data = (E[])new Object[capacity];
 18             size = 0;
 19         }
 20 
 21         // 无参数的构造函数,默认数组的容量capacity=10
 22         public Array(){
 23             this(10);
 24         }
 25 
 26         public Array(E[] arr){
 27             data = (E[])new Object[arr.length];
 28             for(int i = 0 ; i < arr.length ; i ++)
 29                 data[i] = arr[i];
 30             size = arr.length;
 31         }
 32 
 33         // 获取数组的容量
 34         public int getCapacity(){
 35             return data.length;
 36         }
 37 
 38         // 获取数组中的元素个数
 39         public int getSize(){
 40             return size;
 41         }
 42 
 43         // 返回数组是否为空
 44         public boolean isEmpty(){
 45             return size == 0;
 46         }
 47 
 48         // 在index索引的位置插入一个新元素e
 49         public void add(int index, E e){
 50 
 51             if(index < 0 || index > size)
 52                 throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");
 53 
 54             if(size == data.length)
 55                 resize(2 * data.length);
 56 
 57             for(int i = size - 1; i >= index ; i --)
 58                 data[i + 1] = data[i];
 59 
 60             data[index] = e;
 61 
 62             size ++;
 63         }
 64 
 65         // 向所有元素后添加一个新元素
 66         public void addLast(E e){
 67             add(size, e);
 68         }
 69 
 70         // 在所有元素前添加一个新元素
 71         public void addFirst(E e){
 72             add(0, e);
 73         }
 74 
 75         // 获取index索引位置的元素
 76         public E get(int index){
 77             if(index < 0 || index >= size)
 78                 throw new IllegalArgumentException("Get failed. Index is illegal.");
 79             return data[index];
 80         }
 81 
 82         // 修改index索引位置的元素为e
 83         public void set(int index, E e){
 84             if(index < 0 || index >= size)
 85                 throw new IllegalArgumentException("Set failed. Index is illegal.");
 86             data[index] = e;
 87         }
 88 
 89         // 查找数组中是否有元素e
 90         public boolean contains(E e){
 91             for(int i = 0 ; i < size ; i ++){
 92                 if(data[i].equals(e))
 93                     return true;
 94             }
 95             return false;
 96         }
 97 
 98         // 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
 99         public int find(E e){
100             for(int i = 0 ; i < size ; i ++){
101                 if(data[i].equals(e))
102                     return i;
103             }
104             return -1;
105         }
106 
107         // 从数组中删除index位置的元素, 返回删除的元素
108         public E remove(int index){
109             if(index < 0 || index >= size)
110                 throw new IllegalArgumentException("Remove failed. Index is illegal.");
111 
112             E ret = data[index];
113             for(int i = index + 1 ; i < size ; i ++)
114                 data[i - 1] = data[i];
115             size --;
116             data[size] = null; // loitering objects != memory leak
117 
118             if(size == data.length / 4 && data.length / 2 != 0)
119                 resize(data.length / 2);
120             return ret;
121         }
122 
123         // 从数组中删除第一个元素, 返回删除的元素
124         public E removeFirst(){
125             return remove(0);
126         }
127 
128         // 从数组中删除最后一个元素, 返回删除的元素
129         public E removeLast(){
130             return remove(size - 1);
131         }
132 
133         // 从数组中删除元素e
134         public void removeElement(E e){
135             int index = find(e);
136             if(index != -1)
137                 remove(index);
138         }
139 
140         public void swap(int i, int j){
141 
142             if(i < 0 || i >= size || j < 0 || j >= size)
143                 throw new IllegalArgumentException("Index is illegal.");
144 
145             E t = data[i];
146             data[i] = data[j];
147             data[j] = t;
148         }
149 
150         @Override
151         public String toString(){
152 
153             StringBuilder res = new StringBuilder();
154             res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
155             res.append(\'[\');
156             for(int i = 0 ; i < size ; i ++){
157                 res.append(data[i]);
158                 if(i != size - 1)
159                     res.append(", ");
160             }
161             res.append(\']\');
162             return res.toString();
163         }
164 
165         // 将数组空间的容量变成newCapacity大小
166         private void resize(int newCapacity){
167 
168             E[] newData = (E[])new Object[newCapacity];
169             for(int i = 0 ; i < size ; i ++)
170                 newData[i] = data[i];
171             data = newData;
172         }
173     }
174 
175     private class MaxHeap<E extends Comparable<E>> {
176 
177         private Array<E> data;
178 
179         public MaxHeap(int capacity){
180             data = new Array<>(capacity);
181         }
182 
183         public MaxHeap(){
184             data = new Array<>();
185         }
186 
187         public MaxHeap(E[] arr){
188             data = new Array<>(arr);
189             for(int i = parent(arr.length - 1) ; i >= 0 ; i --)
190                 siftDown(i);
191         }
192 
193         // 返回堆中的元素个数
194         public int size(){
195             return data.getSize();
196         }
197 
198         // 返回一个布尔值, 表示堆中是否为空
199         public boolean isEmpty(){
200             return data.isEmpty();
201         }
202 
203         // 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
204         private int parent(int index){
205             if(index == 0)
206                 throw new IllegalArgumentException("index-0 doesn\'t have parent.");
207             return (index - 1) / 2;
208         }
209 
210         // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
211         private int leftChild(int index){
212             return index * 2 + 1;
213         }
214 
215         // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
216         private int rightChild(int index){
217             return index * 2 + 2;
218         }
219 
220         // 向堆中添加元素
221         public void add(E e){
222             data.addLast(e);
223             siftUp(data.getSize() - 1);
224         }
225 
226         private void siftUp(int k){
227 
228             while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
229                 data.swap(k, parent(k));
230                 k = parent(k);
231             }
232         }
233 
234         // 看堆中的最大元素
235         public E findMax(){
236             if(data.getSize() == 0)
237                 throw new IllegalArgumentException("Can not findMax when heap is empty.");
238             return data.get(0);
239         }
240 
241         // 取出堆中最大元素
242         public E extractMax(){
243 
244             E ret = findMax();
245 
246             data.swap(0, data.getSize() - 1);
247             data.removeLast();
248             siftDown(0);
249 
250             return ret;
251         }
252 
253         private void siftDown(int k){
254 
255             while(leftChild(k) < data.getSize()){
256                 int j = leftChild(k); // 在此轮循环中,data[k]和data[j]交换位置
257                 if( j + 1 < data.getSize() &&
258                         data.get(j + 1).compareTo(data.get(j)) > 0 )
259                     j ++;
260                 // data[j] 是 leftChild 和 rightChild 中的最大值
261 
262                 if(data.get(k).compareTo(data.get(j)) >= 0 )
263                     break;
264 
265                 data.swap(k, j);
266                 k = j;
267             }
268         }
269 
270         // 取出堆中的最大元素,并且替换成元素e
271         public E replace(E e){
272 
273             E ret = findMax();
274             data.set(0, e);
275             siftDown(0);
276             return ret;
277         }
278     }
279 
280     private interface Queue<E> {
281 
282         int getSize();
283         boolean isEmpty();
284         void enqueue(E e);
285         E dequeue();
286         E getFront();
287     }
288 
289     private class PriorityQueue<E extends Comparable<E>> implements Queue<E> {
290 
291         private MaxHeap<E> maxHeap;
292 
293         public PriorityQueue(){
294             maxHeap = new MaxHeap<>();
295         }
296 
297         @Override
298         public int getSize(){
299             return maxHeap.size();
300         }
301 
302         @Override
303         public boolean isEmpty(){
304             return maxHeap.isEmpty();
305         }
306 
307         @Override
308         public E getFront(){
309             return maxHeap.findMax();
310         }
311 
312         @Override
313         public void enqueue(E e){
314             maxHeap.add(e);
315         }
316 
317         @Override
318         public E dequeue(){
319             return maxHeap.extractMax();
320         }
321     }
322 
323     private class Freq implements Comparable<Freq>{//创建类Freq,Freq必须是可以比较的,所以要加上Comparable<Freq>
324 
325         public int e, freq;//元素e,元素e对应的频次freq
326 
327         public Freq(int e, int freq){
328             this.e = e;
329             this.freq = freq;
330         }
331 
332         @Override   //上面采用了implements Comparable<Freq>,就必须定义compareTo()方法
333         public int compareTo(Freq another){//Freq another指另一个元素对应的类对象
334             if(this.freq < another.freq)//如果this.freq的频次低
335                 return 1;//compareTo()的返回值,表示this.freq的优先级高
336             else if(this.freq > another.freq)
337                 return -1;
338             else
339                 return 0;
340         }
341     }
342 
343     public List<Integer> topKFrequent(int[] nums, int k) {//传入int型数组nums和k,将前k个频次最高的元素放进一个List里,然后返回这些元素
344         //-------------统计频次---------------//
345         TreeMap<Integer, Integer> map = new TreeMap<>();//TreeMap这个类,统计数组中各个元素出现的频次。<Integer是元素, Integer是频次>
346         for(int num: nums){
347             if(map.containsKey(num))//如果containsKey已经包含了num,
348                 map.put(num, map.get(num) + 1);//get(num)获取num频次,再加1.
349             else
350                 map.put(num, 1);//否则,我们是第一次见到num,给定频次1.
351         }
352         //--------统计频次结束-----------//
353         //------------利用优先队列求出前k个元素----------------------//
354         PriorityQueue<Freq> pq = new PriorityQueue<>();//pq是Freq类型的优先级队列,Freq类型有构造元素e,元素e对应的频次freq
355         for(int key: map.keySet()){//对所有的键进行遍历,
356             if(pq.getSize() < k)//如果当前的优先队列元素数是小于k的,也就是还没有存够k个元素
357                 pq.enqueue(new Freq(key, map.get(key)));//入队一个Freq对象,map.get(key)获取元素Key的频率。
358             else if(map.get(key) > pq.getFront().freq){//当前新遍历到的元素频次大于队首元素的频次
359                 pq.dequeue();//优先队列队首元素出队。
360                 pq.enqueue(new Freq(key, map.get(key)));//再进队一个元素key, map.get(key)
361             }
362         }
363         //-----------利用优先队列求出前k个元素----结束-------------//
364 
365         //-----------然后将优先队列中的元素放入队列中---------------//
366         LinkedList<Integer> res = new LinkedList<>();//初始化一个LinkedList对象,里面存放的是Integer
367         while(!pq.isEmpty())
368             res.add(pq.dequeue().e);//添加一个新的元素,这个元素就是优先队列出队的队首元素的e。
369         return res;
370     }
371 
372     private static void printList(List<Integer> nums){
373         for(Integer num: nums)
374             System.out.print(num + " ");
375         System.out.println();
376     }
377 
378     public static void main(String[] args) {
379 
380         int[] nums = {1, 1, 1, 2, 2, 3};
381         int k = 2;
382         printList((new Solution()).topKFrequent(nums, k));
383     }
384 }

 

参考:https://www.cnblogs.com/wmyskxz/p/9301021.html

https://blog.csdn.net/jianghao233/article/details/82752826

分类:

技术点:

相关文章: