堆
堆的典型应用, 优先队列
典型应用: 操作系统程序调用
医院排队, 有的病人病情比较严重, 先去看病
游戏里面英雄攻击范围的敌人, 动态优先选择
不使用0号索引,存储堆
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;
template<typename Item>
class MaxHeap{
private:
Item *data;
int count;
public:
// 构造函数, 构造一个空堆, 可容纳capacity个元素
MaxHeap(int capacity){
data = new Item[capacity+1];
count = 0;
}
~MaxHeap(){
delete[] data;
}
// 返回堆中的元素个数
int size(){
return count;
}
// 返回一个布尔值, 表示堆中是否为空
bool isEmpty(){
return count == 0;
}
};
// 测试 MaxHeap
int main() {
MaxHeap<int> maxheap = MaxHeap<int>(100);//容量
cout<<maxheap.size()<<endl; // 元素个数
return 0;
}
堆中插入元素 shift up
void shiftUp(int k){
while( k > 1 && data[k/2] < data[k] ){
// data[k/2]父节点
swap( data[k/2], data[k] );
k /= 2;
}
}
// 像最大堆中插入一个新的元素 item
void insert(Item item){
assert( count + 1 <= capacity );
data[count+1] = item;
count ++;
shiftUp(count);
}
完整代码
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;
template<typename Item>
class MaxHeap{
private:
Item *data;
int count;
int capacity;
void shiftUp(int k){
while( k > 1 && data[k/2] < data[k] ){
// data[k/2]父节点
swap( data[k/2], data[k] );
k /= 2;
}
}
public:
// 构造函数, 构造一个空堆, 可容纳capacity个元素
MaxHeap(int capacity){
data = new Item[capacity+1];
count = 0;
this->capacity = capacity;
}
~MaxHeap(){
delete[] data;
}
// 返回堆中的元素个数
int size(){
return count;
}
// 返回一个布尔值, 表示堆中是否为空
bool isEmpty(){
return count == 0;
}
// 像最大堆中插入一个新的元素 item
void insert(Item item){
assert( count + 1 <= capacity );
data[count+1] = item;
count ++;
shiftUp(count);
}
public:
// 以树状打印整个堆结构
void testPrint(){
// 我们的testPrint只能打印100个元素以内的堆的树状信息
if( size() >= 100 ){
cout<<"This print function can only work for less than 100 int";
return;
}
// 我们的testPrint只能处理整数信息
if( typeid(Item) != typeid(int) ){
cout <<"This print function can only work for int item";
return;
}
cout<<"The max heap size is: "<<size()<<endl;
cout<<"Data in the max heap: ";
for( int i = 1 ; i <= size() ; i ++ ){
// 我们的testPrint要求堆中的所有整数在[0, 100)的范围内
assert( data[i] >= 0 && data[i] < 100 );
cout<<data[i]<<" ";
}
cout<<endl;
cout<<endl;
int n = size();
int max_level = 0;
int number_per_level = 1;
while( n > 0 ) {
max_level += 1;
n -= number_per_level;
number_per_level *= 2;
}
int max_level_number = int(pow(2, max_level-1));
int cur_tree_max_level_number = max_level_number;
int index = 1;
for( int level = 0 ; level < max_level ; level ++ ){
string line1 = string(max_level_number*3-1, ' ');
int cur_level_number = min(count-int(pow(2,level))+1,int(pow(2,level)));
bool isLeft = true;
for( int index_cur_level = 0 ; index_cur_level < cur_level_number ; index ++ , index_cur_level ++ ){
putNumberInLine( data[index] , line1 , index_cur_level , cur_tree_max_level_number*3-1 , isLeft );
isLeft = !isLeft;
}
cout<<line1<<endl;
if( level == max_level - 1 )
break;
string line2 = string(max_level_number*3-1, ' ');
for( int index_cur_level = 0 ; index_cur_level < cur_level_number ; index_cur_level ++ )
putBranchInLine( line2 , index_cur_level , cur_tree_max_level_number*3-1 );
cout<<line2<<endl;
cur_tree_max_level_number /= 2;
}
}
private:
void putNumberInLine( int num, string &line, int index_cur_level, int cur_tree_width, bool isLeft){
int sub_tree_width = (cur_tree_width - 1) / 2;
int offset = index_cur_level * (cur_tree_width+1) + sub_tree_width;
assert(offset + 1 < line.size());
if( num >= 10 ) {
line[offset + 0] = '0' + num / 10;
line[offset + 1] = '0' + num % 10;
}
else{
if( isLeft)
line[offset + 0] = '0' + num;
else
line[offset + 1] = '0' + num;
}
}
void putBranchInLine( string &line, int index_cur_level, int cur_tree_width){
int sub_tree_width = (cur_tree_width - 1) / 2;
int sub_sub_tree_width = (sub_tree_width - 1) / 2;
int offset_left = index_cur_level * (cur_tree_width+1) + sub_sub_tree_width;
assert( offset_left + 1 < line.size() );
int offset_right = index_cur_level * (cur_tree_width+1) + sub_tree_width + 1 + sub_sub_tree_width;
assert( offset_right < line.size() );
line[offset_left + 1] = '/';
line[offset_right + 0] = '\\';
}
};
// 测试 MaxHeap
int main() {
MaxHeap<int> maxheap = MaxHeap<int>(100);
srand(time(NULL));
for( int i = 0 ; i < 10; i ++ )
maxheap.insert( rand()%100 );
maxheap.testPrint();
return 0;
}
取出元素 shift down
取出优先级最高的元素 62
将
#include <iostream>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <ctime>
#include <string>
using namespace std;
// 泛型 模板
template<typename Item>
class MaxHeap{
private:
Item *data;
int count; // 存储的的元素值
int capacity;
void shiftUp(int k){
while (k>1 && data[k/2] < data[k]){
swap(data[k/2], data[k]);
k /= 2;
}
}
void shiftDown(int k){
while (2*k <= count){
int j = 2*k; // 左孩子
if (j+1 <= count && data[j+1] > data[j]) // 变成有孩子
j++;
if (data[k] >= data[j]) break;//找到了自己的位置
swap(data[k], data[j]);
k = j;//掉下来之后就是孩子
}
}
public:
MaxHeap(int capacity){
// 在堆空间创造数组 new int[10];
data = new Item[capacity+1];
count = 0;
this->capacity = capacity;
}
~MaxHeap(){
delete[] data;
}
int size(){
return count;
}
bool isEmpty(){
return count==0;
}
void insert(Item item){
assert(count + 1 <= capacity);
data[count + 1] = item;
count++;
shiftUp(count);
}
void show(){
for (int i = 1; i < 12; i++) {
cout<< data[i] <<" ";
}
}
Item getMax(){
assert(count > 0);
return data[1];
}
Item extractMax(){
assert(count > 0);
Item ret = data[1];
swap(data[1], data[count]);
count--;
shiftDown(1);
return ret;
}
private:
void putNumberInLine( int num, string &line, int index_cur_level, int cur_tree_width, bool isLeft){
int sub_tree_width = (cur_tree_width - 1) / 2;
int offset = index_cur_level * (cur_tree_width+1) + sub_tree_width;
assert(offset + 1 < line.size());
if( num >= 10 ) {
line[offset + 0] = '0' + num / 10;
line[offset + 1] = '0' + num % 10;
}
else{
if( isLeft)
line[offset + 0] = '0' + num;
else
line[offset + 1] = '0' + num;
}
}
void putBranchInLine( string &line, int index_cur_level, int cur_tree_width){
int sub_tree_width = (cur_tree_width - 1) / 2;
int sub_sub_tree_width = (sub_tree_width - 1) / 2;
int offset_left = index_cur_level * (cur_tree_width+1) + sub_sub_tree_width;
assert( offset_left + 1 < line.size() );
int offset_right = index_cur_level * (cur_tree_width+1) + sub_tree_width + 1 + sub_sub_tree_width;
assert( offset_right < line.size() );
line[offset_left + 1] = '/';
line[offset_right + 0] = '\\';
}
public:
void testPrint(){
// 我们的testPrint只能打印100个元素以内的堆的树状信息
if( size() >= 100 ){
cout<<"This print function can only work for less than 100 int";
return;
}
// 我们的testPrint只能处理整数信息
if( typeid(Item) != typeid(int) ){
cout <<"This print function can only work for int item";
return;
}
cout<<"The max heap size is: "<<size()<<endl;
cout<<"Data in the max heap: ";
for( int i = 1 ; i <= size() ; i ++ ){
// 我们的testPrint要求堆中的所有整数在[0, 100)的范围内
assert( data[i] >= 0 && data[i] < 100 );
cout<<data[i]<<" ";
}
cout<<endl;
cout<<endl;
int n = size();
int max_level = 0;
int number_per_level = 1;
while( n > 0 ) {
max_level += 1;
n -= number_per_level;
number_per_level *= 2;
}
int max_level_number = int(pow(2, max_level-1));
int cur_tree_max_level_number = max_level_number;
int index = 1;
for( int level = 0 ; level < max_level ; level ++ ){
string line1 = string(max_level_number*3-1, ' ');
int cur_level_number = min(count-int(pow(2,level))+1,int(pow(2,level)));
bool isLeft = true;
for( int index_cur_level = 0 ; index_cur_level < cur_level_number ; index ++ , index_cur_level ++ ){
putNumberInLine( data[index] , line1 , index_cur_level , cur_tree_max_level_number*3-1 , isLeft );
isLeft = !isLeft;
}
cout<<line1<<endl;
if( level == max_level - 1 )
break;
string line2 = string(max_level_number*3-1, ' ');
for( int index_cur_level = 0 ; index_cur_level < cur_level_number ; index_cur_level ++ )
putBranchInLine( line2 , index_cur_level , cur_tree_max_level_number*3-1 );
cout<<line2<<endl;
cur_tree_max_level_number /= 2;
}
}};
int main (){
// vector<int>
MaxHeap<int> maxHeap = MaxHeap<int>(100);
srand(time(NULL));
maxHeap.insert(62);
maxHeap.insert(41);
maxHeap.insert(30);
maxHeap.insert(28);
maxHeap.insert(16);
maxHeap.insert(22);
maxHeap.insert(13);
maxHeap.insert(17);
maxHeap.insert(19);
maxHeap.insert(15);
maxHeap.insert(52);
// for (int i = 0; i < 50; i++) {
// maxHeap.insert(rand()%100);
// }
maxHeap.testPrint();
cout<< "-----" <<endl;
// cout<< maxHeap.getMax() <<endl;
maxHeap.extractMax();
maxHeap.testPrint();
return 0;
};
实现自己的优先队列
#include <iostream>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <ctime>
#include <string>
using namespace std;
// 泛型 模板
template<typename Item>
class PriorityQueue{
private:
Item *data;
int count; // 存储的的元素值
int capacity;
void shiftUp(int k){
while (k>1 && data[k/2] < data[k]){
swap(data[k/2], data[k]);
k /= 2;
}
}
void shiftDown(int k){
while (2*k <= count){
int j = 2*k; // 左孩子
if (j+1 <= count && data[j+1] > data[j]) // 变成有孩子
j++;
if (data[k] >= data[j]) break;//找到了自己的位置
swap(data[k], data[j]);
k = j;//掉下来之后就是孩子
}
}
public:
PriorityQueue(int capacity){
// 在堆空间创造数组 new int[10];
data = new Item[capacity+1];
count = 0;
this->capacity = capacity;
}
~PriorityQueue(){
delete[] data;
}
int size(){
return count;
}
bool isEmpty(){
return count==0;
}
void insert(Item item){
assert(count + 1 <= capacity);
data[count + 1] = item;
count++;
shiftUp(count);
}
void show(){
for (int i = 1; i < 12; i++) {
cout<< data[i] <<" ";
}
}
Item getMax(){
assert(count > 0);
return data[1];
}
Item extractMax(){
assert(count > 0);
Item ret = data[1];
swap(data[1], data[count]);
count--;
shiftDown(1);
return ret;
}
private:
void putNumberInLine( int num, string &line, int index_cur_level, int cur_tree_width, bool isLeft){
int sub_tree_width = (cur_tree_width - 1) / 2;
int offset = index_cur_level * (cur_tree_width+1) + sub_tree_width;
assert(offset + 1 < line.size());
if( num >= 10 ) {
line[offset + 0] = '0' + num / 10;
line[offset + 1] = '0' + num % 10;
}
else{
if( isLeft)
line[offset + 0] = '0' + num;
else
line[offset + 1] = '0' + num;
}
}
void putBranchInLine( string &line, int index_cur_level, int cur_tree_width){
int sub_tree_width = (cur_tree_width - 1) / 2;
int sub_sub_tree_width = (sub_tree_width - 1) / 2;
int offset_left = index_cur_level * (cur_tree_width+1) + sub_sub_tree_width;
assert( offset_left + 1 < line.size() );
int offset_right = index_cur_level * (cur_tree_width+1) + sub_tree_width + 1 + sub_sub_tree_width;
assert( offset_right < line.size() );
line[offset_left + 1] = '/';
line[offset_right + 0] = '\\';
}
public:
void testPrint(){
// 我们的testPrint只能打印100个元素以内的堆的树状信息
if( size() >= 100 ){
cout<<"This print function can only work for less than 100 int";
return;
}
// 我们的testPrint只能处理整数信息
if( typeid(Item) != typeid(int) ){
cout <<"This print function can only work for int item";
return;
}
cout<<"The max heap size is: "<<size()<<endl;
cout<<"Data in the max heap: ";
for( int i = 1 ; i <= size() ; i ++ ){
// 我们的testPrint要求堆中的所有整数在[0, 100)的范围内
assert( data[i] >= 0 && data[i] < 100 );
cout<<data[i]<<" ";
}
cout<<endl;
cout<<endl;
int n = size();
int max_level = 0;
int number_per_level = 1;
while( n > 0 ) {
max_level += 1;
n -= number_per_level;
number_per_level *= 2;
}
int max_level_number = int(pow(2, max_level-1));
int cur_tree_max_level_number = max_level_number;
int index = 1;
for( int level = 0 ; level < max_level ; level ++ ){
string line1 = string(max_level_number*3-1, ' ');
int cur_level_number = min(count-int(pow(2,level))+1,int(pow(2,level)));
bool isLeft = true;
for( int index_cur_level = 0 ; index_cur_level < cur_level_number ; index ++ , index_cur_level ++ ){
putNumberInLine( data[index] , line1 , index_cur_level , cur_tree_max_level_number*3-1 , isLeft );
isLeft = !isLeft;
}
cout<<line1<<endl;
if( level == max_level - 1 )
break;
string line2 = string(max_level_number*3-1, ' ');
for( int index_cur_level = 0 ; index_cur_level < cur_level_number ; index_cur_level ++ )
putBranchInLine( line2 , index_cur_level , cur_tree_max_level_number*3-1 );
cout<<line2<<endl;
cur_tree_max_level_number /= 2;
}
}};
int main (){
// vector<int>
PriorityQueue<int> pq = PriorityQueue<int>(20);
for (int i = 0; i < 10; i++) {
int num = rand()%100;
pq.insert(num);
cout<< "insert "<< num << " in priority_queue" <<endl;
}
pq.testPrint();
while (!pq.isEmpty()){
cout<< pq.getMax() <<"\t";
pq.extractMax();
}
cout<< "-----" <<endl;
return 0;
};
优先队列的使用
#include <iostream>
#include <queue>
#include <ctime>
#include <functional>
using namespace std;
bool myCmp(int a , int b){
if(a%10 != b%10)
return a%10 > b%10;
return a > b;
}
int main() {
srand(time(NULL));
// 默认的priority queue, 底层是最大堆
priority_queue<int> pq;
for(int i = 0 ; i < 10 ; i ++){
int num = rand() % 100;
pq.push(num);
cout << "insert " << num << " in priority queue." << endl;
}
while(!pq.empty()){
cout << pq.top() << " ";
pq.pop();
}
cout << endl << endl;
// 使用greater的priority queue, 底层是最小堆
priority_queue<int, vector<int>, greater<int>> pq2;
for(int i = 0; i < 10; i ++){
int num = rand() % 100;
pq2.push(num);
cout << "insert " << num << " in priority queue." << endl;
}
while(!pq2.empty()){
cout << pq2.top() << " ";
pq2.pop();
}
cout << endl << endl;
// 使用自定义Comparator的priority queue
priority_queue<int, vector<int>, function<bool(int,int)>> pq3(myCmp);
for(int i = 0; i < 10; i ++){
int num = rand() % 100;
pq3.push(num);
cout << "insert " << num << " in priority queue." << endl;
}
while(!pq3.empty()){
cout << pq3.top() << " ";
pq3.pop();
}
return 0;
}
索引堆
堆顶元素是索引10指向的62, 比如将系统进程好为7的优先级往前提一提, 就是交换索引就行, 比较的时候比较值,交换的时候交换索引
#include <iostream>
#include <cassert>
#include "SortTestHelper.h"
using namespace std;
// 最大索引堆
template<typename Item>
class IndexMaxHeap{
private:
Item *data; // 最大索引堆中的数据
int *indexes; // 最大索引堆中的索引
int count;
int capacity;
// 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
void shiftUp( int k ){
while( k > 1 && data[indexes[k/2]] < data[indexes[k]] ){
swap( indexes[k/2] , indexes[k] );
k /= 2;
}
}
// 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
void shiftDown( int k ){
while( 2*k <= count ){
int j = 2*k;
if( j + 1 <= count && data[indexes[j+1]] > data[indexes[j]] )
j += 1;
if( data[indexes[k]] >= data[indexes[j]] )
break;
swap( indexes[k] , indexes[j] );
k = j;
}
}
public:
// 构造函数, 构造一个空的索引堆, 可容纳capacity个元素
IndexMaxHeap(int capacity){
data = new Item[capacity+1];
indexes = new int[capacity+1];
count = 0;
this->capacity = capacity;
}
~IndexMaxHeap(){
delete[] data;
delete[] indexes;
}
// 返回索引堆中的元素个数
int size(){
return count;
}
// 返回一个布尔值, 表示索引堆中是否为空
bool isEmpty(){
return count == 0;
}
// 向最大索引堆中插入一个新的元素, 新元素的索引为i, 元素为item
// 传入的i对用户而言,是从0索引的
void insert(int i, Item item){
assert( count + 1 <= capacity );
assert( i + 1 >= 1 && i + 1 <= capacity );
i += 1;
data[i] = item;
indexes[count+1] = i;
count++;
shiftUp(count);
}
// 从最大索引堆中取出堆顶元素, 即索引堆中所存储的最大数据
Item extractMax(){
assert( count > 0 );
Item ret = data[indexes[1]];
swap( indexes[1] , indexes[count] );
count--;
shiftDown(1);
return ret;
}
// 从最大索引堆中取出堆顶元素的索引
int extractMaxIndex(){
assert( count > 0 );
int ret = indexes[1] - 1;
swap( indexes[1] , indexes[count] );
count--;
shiftDown(1);
return ret;
}
// 获取最大索引堆中的堆顶元素
Item getMax(){
assert( count > 0 );
return data[indexes[1]];
}
// 获取最大索引堆中的堆顶元素的索引
int getMaxIndex(){
assert( count > 0 );
return indexes[1]-1;
}
// 获取最大索引堆中索引为i的元素
Item getItem( int i ){
assert( i + 1 >= 1 && i + 1 <= capacity );
return data[i+1];
}
// 将最大索引堆中索引为i的元素修改为newItem
void change( int i , Item newItem ){
i += 1;
data[i] = newItem;
// 找到indexes[j] = i, j表示data[i]在堆中的位置
// 之后shiftUp(j), 再shiftDown(j)
for( int j = 1 ; j <= count ; j ++ )
if( indexes[j] == i ){
shiftUp(j);
shiftDown(j);
return;
}
}
// 测试索引堆中的索引数组index
// 注意:这个测试在向堆中插入元素以后, 不进行extract操作有效
bool testIndexes(){
int *copyIndexes = new int[count+1];
for( int i = 0 ; i <= count ; i ++ )
copyIndexes[i] = indexes[i];
copyIndexes[0] = 0;
std::sort(copyIndexes, copyIndexes + count + 1);
// 在对索引堆中的索引进行排序后, 应该正好是1...count这count个索引
bool res = true;
for( int i = 1 ; i <= count ; i ++ )
if( copyIndexes[i-1] + 1 != copyIndexes[i] ){
res = false;
break;
}
delete[] copyIndexes;
if( !res ){
cout<<"Error!"<<endl;
return false;
}
return true;
}
};
// 使用最大索引堆进行堆排序, 来验证我们的最大索引堆的正确性
// 最大索引堆的主要作用不是用于排序, 我们在这里使用排序只是为了验证我们的最大索引堆实现的正确性
// 在后续的图论中, 无论是最小生成树算法, 还是最短路径算法, 我们都需要使用索引堆进行优化:)
template<typename T>
void heapSortUsingIndexMaxHeap(T arr[], int n){
IndexMaxHeap<T> indexMaxHeap = IndexMaxHeap<T>(n);
for( int i = 0 ; i < n ; i ++ )
indexMaxHeap.insert( i , arr[i] );
assert( indexMaxHeap.testIndexes() );
for( int i = n-1 ; i >= 0 ; i -- )
arr[i] = indexMaxHeap.extractMax();
}
int main() {
int n = 1000000;
int* arr = SortTestHelper::generateRandomArray(n, 0, n);
SortTestHelper::testSort("Heap Sort Using Index-Max-Heap", heapSortUsingIndexMaxHeap, arr, n);
delete[] arr;
return 0;
}
SortTestHelper.h
#ifndef INC_08_INDEX_HEAP_SORTTESTHELPER_H
#define INC_08_INDEX_HEAP_SORTTESTHELPER_H
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cassert>
#include <string>
using namespace std;
namespace SortTestHelper {
// 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
int *generateRandomArray(int n, int range_l, int range_r) {
int *arr = new int[n];
srand(time(NULL));
for (int i = 0; i < n; i++)
arr[i] = rand() % (range_r - range_l + 1) + range_l;
return arr;
}
// 生成一个近乎有序的数组
// 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据
// swapTimes定义了数组的无序程度
int *generateNearlyOrderedArray(int n, int swapTimes){
int *arr = new int[n];
for(int i = 0 ; i < n ; i ++ )
arr[i] = i;
srand(time(NULL));
for( int i = 0 ; i < swapTimes ; i ++ ){
int posx = rand()%n;
int posy = rand()%n;
swap( arr[posx] , arr[posy] );
}
return arr;
}
// 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组
int *copyIntArray(int a[], int n){
int *arr = new int[n];
//* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:)
copy(a, a+n, arr);
return arr;
}
// 打印arr数组的所有内容
template<typename T>
void printArray(T arr[], int n) {
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return;
}
// 判断arr数组是否有序
template<typename T>
bool isSorted(T arr[], int n) {
for (int i = 0; i < n - 1; i++)
if (arr[i] > arr[i + 1])
return false;
return true;
}
// 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间
// 将算法的运行时间打印在控制台上
template<typename T>
void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {
clock_t startTime = clock();
sort(arr, n);
clock_t endTime = clock();
cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
assert(isSorted(arr, n));
return;
}
// 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间
// 将算法的运行时间以double类型返回, 单位为秒(s)
template<typename T>
double testSort(void (*sort)(T[], int), T arr[], int n) {
clock_t startTime = clock();
sort(arr, n);
clock_t endTime = clock();
assert(isSorted(arr, n));
return double(endTime - startTime) / CLOCKS_PER_SEC;
}
};
#endif //INC_08_INDEX_HEAP_SORTTESTHELPER_H
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <cassert>
using namespace std;
// 347. Top K Frequent Elements
// https://leetcode-cn.com/problems/top-k-frequent-elements/submissions/
// 时间复杂度: O(nlogk)
// 空间复杂度: O(n + k)
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
assert(k > 0);
// 统计每个元素出现的频率
unordered_map<int,int> freq;
for(int i = 0 ; i < nums.size() ; i ++ )
freq[nums[i]] ++;
assert(k <= freq.size());
// 扫描freq,维护当前出现频率最高的k个元素
// 在优先队列中,按照频率排序,所以数据对是 (频率,元素) 的形式
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
for(unordered_map<int,int>::iterator iter = freq.begin();
iter != freq.end(); iter ++ ){
if(pq.size() == k){
if(iter->second > pq.top().first){
pq.pop();
pq.push( make_pair(iter->second, iter->first));
}
}
else
pq.push(make_pair(iter->second , iter->first));
}
vector<int> res;
while(!pq.empty()){
res.push_back(pq.top().second);
pq.pop();
}
return res;
}
};
int main() {
int nums[] = {1, 1, 1, 2, 2, 3};
vector<int> vec(nums, nums + sizeof(nums)/sizeof(int));
int k = 2;
vector<int> res = Solution().topKFrequent(vec, 2);
for( int i = 0 ; i < res.size() ; i ++ )
cout<<res[i]<<" ";
cout<<endl;
return 0;
}