Bootstrap

堆的基础学习

堆通常是一个可以被看做一棵完全二叉树的数组对象。
堆总是满足下列性质:

  • 堆中某个结点的值总是不大于或不小于其父结点的值;
  • 堆总是一棵完全二叉树。

建堆

  1. 从上往下
    假设给定一个数组,从第一个元素依次插入在堆中,调整至满足堆的结构(大根堆)
    流程:比较当前位置与父结点位置,如果当前位置比父节点大,则交换。
void heapInsert(vector<int>&a,int index){//从index位置开始往上比较
	while(index<a.size()&& a[index]>a[(index-1)/2]){
		swap(a[index],a[(index-1)/2]);//(index-1)/2是index的父节点 
		index=(index-1)/2;
	} 
}
void heapSort2(vector<int>&a){
	int heapSize=a.size();
//	for(int i=heapSize/2;i>=0;--i){
//		heapify(a,i,heapSize-1);
//	}
	for(int i=0;i<heapSize;++i){
		heapInsert(a,i);//从0到heapSize-1依次插入到堆中
	} 
	for(int i=heapSize-1;i>0;--i){
		swap(a[0],a[i]);
		heapify(a,0,i-1);
	}
}

上述建堆的时间复杂度O(NlongN)

  1. 从下往上
    一个数组就是一个完全二叉树,从最后一个非叶子结点开始往前调整结点的位置
    流程:从当前位置开始往下调整,如果当前位置比最大孩子结点小,就交换,然后下移。
void heapify(vector<int>&a,int low,int high){
	int i=low;
	int j=2*i+1;
	int temp=a[i];
	while(j<=high){
		while(j<high&& a[j+1]>a[j]){
			++j;
		}
		if(a[j]>temp){
			a[i]=a[j];
			i=j;
			j=2*i+1;
		}else{
			break;
		}
	}
	a[i]=temp;
}
void heapSort2(vector<int>&a){
	int heapSize=a.size();
	for(int i=heapSize/2;i>=0;--i){//heapSize/2是最后一个非叶子结点
		heapify(a,i,heapSize-1);
	}
//	for(int i=0;i<heapSize;++i){
//		heapInsert(a,i);
//	} 

上述时间复杂度O(N)
如果元素不是同时给出的,只能采用第一种建堆的方法。

题目

给定很多线段,每个线段都有两个数[start, end],表示线段开始位置和结束位置,左右都是闭区间。
规定:
1)线段的开始和结束位置一定都是整数值
2)线段重合区域的长度必须>=1
返回线段最多重合区域中,包含了几条线段
例:
有三个线段,[1,2],[2,3],[1,3],其中[1,2]和[1,3]重合或者[2,3]和[1,3]重合,所以返回2,但是[1,2]和[2,3]不重合(因为重合的长度是0)
分析:
解1 暴力方法
先找出所有线段中开始位置的最小值minStart和结束位置的最大值maxEnd,即在[minStart,maxEnd]找包含多少条重合的线段,然后考虑有多少个线段包含minStart+0.5记为r1,有多少个线段包含minStart+1.5记为r2,……,有多少个线段包含maxEnd-0,5,取这些数的最大值即为结果。因此每个重合区域必包含某个点5。

int way1(vector<Line*>lines){
	int minStart=lines[0]->start;
	int maxEnd=lines[0]->end;
	int re=0;
	//寻找线段的最小开始和最大结束
	for(int i=1;i<lines.size();++i){
		if(lines[i]->start<minStart){
			minStart=lines[i]->start;
		}
		if(lines[i]->end>maxEnd){
			maxEnd=lines[i]->end;
		}
	}
	for(double i=minStart+0.5;i<=maxEnd;++i){
		int sum=0;
		//遍历所有的线段,计算包含i的线段数
		for(int j=0;j<lines.size();++j){
			if(lines[j]->start<i && lines[j]->end>i){
				++sum;
			}
		}
		if(re<sum){
			re=sum;
		}
	}
	return re;
}

时间复杂度O((max-min)N),max是线段的最大结束,min是线段的最小开始。

解2 堆
任何重合区域的左边界必是某一个线段的左边界

  1. 先按线段的开始位置从小到大排序,准备一个小顶堆(存放线段的结束位置)
  2. 从最小的线段开始,将线段结束位置小于等于本线段开始位置的线段从堆中弹出,然后将本线段的结束位置压入堆,此时堆中的元素个数就是从本线段开始的区域中重合的线段数。
  3. 每一个线段都进行2过程,并同时更新重合线段数的最大值,最后返回最大值。
    为什么堆中的元素个数就是从本线段开始的区域中重合的线段数?
    重合的线段的结束位置一定是大于本线段的开始位置的,所以将线段结束位置小于等于本线段开始位置的线段从堆中弹出,此时堆中剩下的线段都是结束位置大于本线段开始位置,也即都是重合的线段。
bool compare(Line* a,Line* b){
	return a->start<b->start;
} 
int way2(vector<Line*>&lines){
	priority_queue<int,vector<int>,greater<int> >q;//小根堆
	int re=0;
	sort(lines.begin(),lines.end(),compare);
	
	for(int i=0;i<lines.size();++i){
		int j=lines[i]->start;
		while(!q.empty() && q.top()<=j){
			q.pop();
		}
		q.push(lines[i]->end);
		re=re<q.size()?q.size():re;
	}
	return re;
}

线段重合
分析:
注意本题重合区域没有限制,例如[1,2],[2,3]也是重合的

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
bool cmp(pair<int, int>p1, pair<int, int>p2) {
	return p1.first < p2.first;//按开始位置从小到大排序
}
int way2(vector<pair<int, int>>lines) {
	sort(lines.begin(), lines.end(), cmp);
	priority_queue<int, vector<int>, greater<int>>pq;//存放线段结束位置的小根堆
	int result = 0;
	for (pair<int, int>curLine : lines) {
		pq.push(curLine.second);
		while (!pq.empty() && pq.top() < curLine.first) {//如果堆顶元素小于等于线段的开始位置就弹出
			pq.pop();
		}

		result = result >= pq.size() ? result : pq.size();//更新结果
	}
	return result;
}
int main()
{

	vector<pair<int, int>>lines;
	int N;
    cin>>N;
    for(int i=0;i<N;i++){
        pair<int,int>p;
        cin>>p.first;
        cin>>p.second;
        lines.push_back(p);
    }
    cout<<way2(lines);
	return 0;
}

函数指针

写法1

int sum(int a,int b)
{
    return a+b;
}
int (*f)(int a,int b);
	f=sum;
	cout<<f(3,2);

写法2

typedef int (*fun)(int c,int d);
	fun f ;//定义一个函数指针 
	f=sum;
	cout<<f(1,2);

写法3

typedef int (fun)(int c,int d);
	fun* f ;//定义一个函数指针 
	f=sum;
	cout<<f(44,2);

手写堆

其中comp的一个实例如下:

bool myCompare(Line* a,Line*b){
	return a->start<b->start;
}
#pragma once
#include<iostream>
#include<vector>
#include<unordered_map>
#include<list>
using namespace std;


//T不可以是基础类型,如果是基础类型的话需要再包一层(因为map的key不可以重复) 
template<class T>
class Heap {
private:
	vector<T>a;
	unordered_map<T, int> map;
	int heapSize;
	typedef bool(*compare)(T a, T b);
	compare comp;//比较器 

public:
	Heap(compare comp) :comp(comp) {
		heapSize = 0;
	}
	void mySwap(int i, int j) {//交换i和j位置的数,同时索引也交换 
		map[a[i]] = j;
		map[a[j]] = i;
		swap(a[i], a[j]);
	}
	void heapify(int low, int high) {

		int i = low;
		int j = 2 * i + 1;
		while (j <= high) {
			while (j < high && comp(a[j + 1], a[j])) {
				++j;
			}
			if (comp(a[j], a[i])) {
				mySwap(i, j);
				i = j;
				j = 2 * i + 1;
			}
			else {
				break;
			}
		}
	}
	void heapInsert(int index) {
		
		while (comp(a[index], a[(index - 1) / 2])){
			mySwap(index, (index - 1) / 2);
			index = (index - 1) / 2;
		}
	}
	int getSize() {
		return heapSize;
	}
	bool empty() {
		return heapSize == 0;
	}
	T top() {
		return a[0];
	}
	void pop() {
		mySwap(0, --heapSize);
		map.erase(a[heapSize]);
		a.erase(a.begin() + heapSize);
		a.resize(heapSize);
		heapify(0, heapSize - 1);
	}

	void push(T t) {
		a.resize(++heapSize);
		a[heapSize - 1] = t;
		map[t] = heapSize - 1;
		heapInsert(heapSize-1);
		
	}
	void remove(T t) {
		int index = map[t];
		if (index == heapSize - 1) {
			--heapSize;
			a.resize(heapSize);
			map.erase(t);
			return;
		}
		mySwap(index, heapSize-1);
		--heapSize;
		a.resize(heapSize);
		map.erase(t);
		if (heapSize > 0) {
			
			heapInsert(index);
			heapify(0, heapSize - 1);
		}
		

	}
	void resign(T t) {//t元素发生改动,可能需要调整堆
		if (heapSize == 0) {
			return;
		}
		int index = map[t];
		heapInsert(index);
		heapify(index, heapSize - 1);
	}
	list<T>returnList() {//返回堆中所有元素
		list<T>re;
		for (int i = 0; i < heapSize; ++i) {
			
			re.push_back(a[i]);
		}
		return re;
	}
	bool contain(T t) {
		return map.count(t);
	}

};


相关题目

题目描述:
给定一个整形数组 int arr[] 和一个布尔类型的数组 bool op[],两个数组等长,假设长度为N,arr[i]表示客户编号,op[i]表示客户操作,op[i]=true表示客户i购买了一件商品,op[i]=false表示客户i退了一件商品。
现在要求给购买次数最多的前k名用户颁奖。所以每个事件发生前,都返回一个前k名用户名单。
得奖的规则:

  1. 如果某个用户购买商品次数为0,但是又发生了退货事件,则认为该事件无效,得奖名单和之前事件一致.
  2. 某用户发生购买商品事件,购买商品数+1,发生退货事件,购买商品数-1.
  3. 每次都是最多K个用户得奖,K也为传入的参数.如果根据全部规则,得奖人数确实不够K个,那就以不够的情况输出结果.
  4. 得奖系统分为得奖区和候选区,任何用户只要购买数>0,一定在这两个区域中的一个.
  5. 购买数最大的前K名用户进入得奖区,在最初时如果得奖区没有到达K个用户,那么新来的用户直接进入得奖区.
  6. 如果购买数不足以进入得奖区的用户,进入候选区.
  7. 如果候选区购买数最多的用户,已经足以进入得奖区,该用户就会替换得奖区中购买数最少的用户(大于才能替换),如果得奖区中购买数最少的用户有多个,就替换最早进入得奖区的用户.如果候选区中购买数最多的用户有多个,机会会给最早进入候选区的用户.
  8. 候选区和得奖区是两套时间,因用户只会在其中一个区域,所以只会有一个区域的时间,另一个没有从得奖区出来进入候选区的用户,得奖区时间删除,进入候选区的时间就是当前事件的时间(可以理解为arr[]和op中的i)从候选区出来进入得奖区的用户,候选区时间删除,进入得奖区的时间就是当前事件的时间(可以理解为arr和op们中的i).
  9. 如果某用户购买数==0,不管在哪个区域都离开,区域时间删除,离开是指彻底离开,哪个区域也不会找到该用户
    如果下次该用户又发生购买行为,产生>0的购买数,会再次根据之前规则回到某个区域中,进入区域的时间重记.

解法1 暴力模拟

class Customer {
public:
	int id;
	int item;
	int time;
	Customer(int id) :id(id) {
		item = 0;
		time = 0;
	}
	Customer(Customer* c) {
		id = c->id;
		item = c->item;
		time = c->item;
	}
};
bool count(list<Customer*>& v, Customer* c) {//查找list是否有c
	for (auto it = v.begin(); it != v.end(); ++it) {
		if ((*it) == c) {
			return true;
		}
	}
	return false;
}
bool winnerCom(Customer* a, Customer* b) {
	if (a->item < b->item) {
		return true;
	}
	else if (a->item == b->item && a->time < b->time) {
		return true;
	}
	else {
		return false;
	}
}
bool waitCom(Customer* a, Customer* b) {
	if (a->item > b->item) {
		return true;
	}
	else if (a->item == b->item && a->time < b->time) {
		return true;
	}
	else {
		return false;
	}
}
void clearZero(list<Customer*>& s) {
	auto it = s.begin();
	while (it != s.end()) {
		auto im = it;
		++it;
		if ((*im)->item == 0) {
			s.erase(im);
		}
	}
	
}
void move(list<Customer*>& winner, list<Customer*>& wait, int k, int i) {
	if (wait.empty()) {
		return;
	}
	if (winner.size() < k) {//得奖区不足k个 
		Customer* c = wait.front();
		wait.pop_front();
		c->time = i;
		winner.push_back(c);
	}
	else {
		if (wait.front()->item > winner.front()->item) {
			Customer* wa = wait.front();
			wait.pop_front();
			Customer* wi = winner.front();
			winner.pop_front();
			wa->time = i;
			wi->time = i;
			wait.push_back(wi);
			winner.push_back(wa);
		}
	}
}
void putRe(list<list<int>>& re, list<Customer*>& winner) {
	list<int>ans;
	for (auto it = winner.begin(); it != winner.end(); ++it) {
		
		Customer* lc = new Customer(*it);
		ans.push_back(lc->id);
	}
	re.push_back(ans);
}
list<list<int>> topK(vector<int>& arr, vector<bool>& op, int k) {
	unordered_map<int, Customer*>customers;//客户的id 
	list<Customer*> winner;//得奖区 	
	list<list<int>>re;
	list<Customer*> wait;//候选区 
	for (int i = 0; i< arr.size(); ++i) {

		int id = arr[i];
		bool buyOrRefund = op[i];
		if (!buyOrRefund && !customers.count(id)) {//用户退货,并且之前未购买过 

			putRe(re, winner);
			continue;
		}
		/*
		接下来分以下几种情况:
		1. 用户之前没有购买,此时买货
		2. 用户之前购买数>0,此时买货
		3. 用户之前购买数>0,此时退货
		*/
		if (!customers.count(id)) {
			Customer* customer = new Customer(id);
			customers.emplace(id, customer);
		}
		Customer* c = customers[id];
		if (buyOrRefund) {
			++c->item;
		}
		else {
			--c->item;
		}
		if (c->item == 0) {
			customers.erase(customers.find(id));
		}
		//用户购买数大于0,并且此时买货 
		if (!count(winner, c) && !count(wait, c)) {
			if (winner.size() < k) {
				c->time = i;
				winner.insert(winner.end(), c);
			}
			else {
				c->time = i;
				wait.insert(wait.end(), c);
			}
		}
		//删除购买数为0的用户 
		clearZero(winner);
		clearZero(wait);
		winner.sort(winnerCom);
		wait.sort(waitCom);
		move(winner, wait, k, i);
		putRe(re, winner);
	}
	return re;
}

解法2 加强堆

class ReturnWinner {
private:
	unordered_map<int, Customer*>customers;
	Heap<Customer*>* winner;
	Heap<Customer*>* wait;
	int k;
	int* a;
public:
	ReturnWinner(int k) :k(k) {
		winner = new Heap<Customer*>(winnerCom);
		wait = new Heap<Customer*>(waitCom);
		a = new int[10];
	}
	void operate(int time, int id, bool buyOrRefund) {
		if (!buyOrRefund && !customers.count(id)) {
			return;
		}
		//第一次购买
		if (!customers.count(id)) {
			Customer* c = new Customer(id);
			customers.emplace(id, c);
		}
		Customer* c = customers[id];
		if (buyOrRefund) {
			c->item++;
		}
		else {
			c->item-- ;
		}
		if (c->item == 0) {
			customers.erase(id);
		}
		//第一次购买
		if (!winner->contain(c) && !wait->contain(c)) {
			if (winner->getSize() < k) {
				c->time = time;
				winner->push(c);
			}
			else {
				c->time = time;
				wait->push(c);
			}
		}
		//之前在候选区
		else if (wait->contain(c)) {
			if (c->item == 0) {
				wait->remove(c);
			}
			else {
				wait->resign(c);//重新调整
			}
		}
		//之前在获奖区
		else {
			if (c->item == 0) {
				winner->remove(c);
			}
			else {
				winner->resign(c);
			}
		}
		move(time);
	}
	void move(int time) {
		if (wait->getSize() == 0) {
			return;
		}
		if (winner->getSize() < k) {
			Customer* c = wait->top();
			wait->pop();
			c->time = time;
			winner->push(c);
		}
		else {
			if (wait->top()->item > winner->top()->item) {
				Customer* wi = winner->top();
				winner->pop();
				Customer* wa = wait->top();
				wait->pop();
				wi->time = time;
				wa->time = time;
				winner->push(wa);
				wait->push(wi);
			}
		}
	}
	list<int> getList() {//返回获奖用户的id
		list<int>re;
		list<Customer*>origin = winner->returnList();
		for (auto it = origin.begin(); it != origin.end(); ++it) {
			re.push_back((*it)->id);
		}
		return re;
	}
	

};
list<list<int>> topK2(vector<int>& arr, vector<bool>& op, int k) {
	list<list<int>>re;
	ReturnWinner* returnWinner = new ReturnWinner(k);
	for (int i = 0; i < arr.size(); ++i) {
		returnWinner->operate(i, arr[i], op[i]);//一次交易
		re.push_back(returnWinner->getList());
	}
	return re;
}

完整可测试的代码

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<vector> 
#include<unordered_map>
#include<list>
#include<algorithm>
#include"Heap.h"
using namespace std;
class Customer {
public:
	int id;
	int item;
	int time;
	Customer(int id) :id(id) {
		item = 0;
		time = 0;
	}
	Customer(Customer* c) {
		id = c->id;
		item = c->item;
		time = c->item;
	}
};
bool count(list<Customer*>& v, Customer* c) {//查找list是否有c
	for (auto it = v.begin(); it != v.end(); ++it) {
		if ((*it) == c) {
			return true;
		}
	}
	return false;
}
bool winnerCom(Customer* a, Customer* b) {
	if (a->item < b->item) {
		return true;
	}
	else if (a->item == b->item && a->time < b->time) {
		return true;
	}
	else {
		return false;
	}
}
bool waitCom(Customer* a, Customer* b) {
	if (a->item > b->item) {
		return true;
	}
	else if (a->item == b->item && a->time < b->time) {
		return true;
	}
	else {
		return false;
	}
}
void clearZero(list<Customer*>& s) {//清楚s中item为0的元素
	auto it = s.begin();
	while (it != s.end()) {
		auto im = it;
		++it;
		if ((*im)->item == 0) {
			s.erase(im);
		}
	}
	
}
void move(list<Customer*>& winner, list<Customer*>& wait, int k, int i) {//调整获奖区和候选区
	if (wait.empty()) {
		return;
	}
	if (winner.size() < k) {//得奖区不足k个 
		Customer* c = wait.front();
		wait.pop_front();
		c->time = i;
		winner.push_back(c);
	}
	else {
		if (wait.front()->item > winner.front()->item) {
			Customer* wa = wait.front();
			wait.pop_front();
			Customer* wi = winner.front();
			winner.pop_front();
			wa->time = i;
			wi->time = i;
			wait.push_back(wi);
			winner.push_back(wa);
		}
	}
}
void putRe(list<list<int>>& re, list<Customer*>& winner) {//将winner中用户的id加入re
	list<int>ans;
	for (auto it = winner.begin(); it != winner.end(); ++it) {
		
		Customer* lc = new Customer(*it);
		ans.push_back(lc->id);
	}
	re.push_back(ans);
}
//暴力模拟
list<list<int>> topK(vector<int>& arr, vector<bool>& op, int k) {
	unordered_map<int, Customer*>customers;//客户的id 
	list<Customer*> winner;//得奖区 	
	list<list<int>>re;
	list<Customer*> wait;//候选区 
	for (int i = 0; i< arr.size(); ++i) {

		int id = arr[i];
		bool buyOrRefund = op[i];
		if (!buyOrRefund && !customers.count(id)) {//用户退货,并且之前未购买过 

			putRe(re, winner);
			continue;
		}
		/*
		接下来分以下几种情况:
		1. 用户之前没有购买,此时买货
		2. 用户之前购买数>0,此时买货
		3. 用户之前购买数>0,此时退货
		*/
		if (!customers.count(id)) {
			Customer* customer = new Customer(id);
			customers.emplace(id, customer);
		}
		Customer* c = customers[id];
		if (buyOrRefund) {
			++c->item;
		}
		else {
			--c->item;
		}
		if (c->item == 0) {
			customers.erase(customers.find(id));
		}
		//用户购买数大于0,并且此时买货 
		if (!count(winner, c) && !count(wait, c)) {
			if (winner.size() < k) {
				c->time = i;
				winner.insert(winner.end(), c);
			}
			else {
				c->time = i;
				wait.insert(wait.end(), c);
			}
		}
		//删除购买数为0的用户 
		clearZero(winner);
		clearZero(wait);
		winner.sort(winnerCom);
		wait.sort(waitCom);
		move(winner, wait, k, i);
		putRe(re, winner);
	}
	return re;
}
//自动生成数组
void geneArr(vector<int>& arr, vector<bool>& op, int num) {
	srand((unsigned int)time(0));
	arr.resize(num);
	op.resize(num);
	for (int j = 0; j < num; ++j) {
		int val = rand() % 5 + 1;

		arr[j] = val;
		if ((j & 1) == 0) {
			op[j] = true;
		}
		else {
			op[j] = false;
		}
	}
}

//方法2 加强堆
class ReturnWinner {
private:
	unordered_map<int, Customer*>customers;
	Heap<Customer*>* winner;
	Heap<Customer*>* wait;
	int k;
	int* a;
public:
	ReturnWinner(int k) :k(k) {
		winner = new Heap<Customer*>(winnerCom);
		wait = new Heap<Customer*>(waitCom);
		a = new int[10];
	}
	void operate(int time, int id, bool buyOrRefund) {
		if (!buyOrRefund && !customers.count(id)) {
			return;
		}
		//第一次购买
		if (!customers.count(id)) {
			Customer* c = new Customer(id);
			customers.emplace(id, c);
		}
		Customer* c = customers[id];
		if (buyOrRefund) {
			c->item++;
		}
		else {
			c->item-- ;
		}
		if (c->item == 0) {
			customers.erase(id);
		}
		//第一次购买
		if (!winner->contain(c) && !wait->contain(c)) {
			if (winner->getSize() < k) {
				c->time = time;
				winner->push(c);
			}
			else {
				c->time = time;
				wait->push(c);
			}
		}
		//之前在候选区
		else if (wait->contain(c)) {
			if (c->item == 0) {
				wait->remove(c);
			}
			else {
				wait->resign(c);//重新调整
			}
		}
		//之前在获奖区
		else {
			if (c->item == 0) {
				winner->remove(c);
			}
			else {
				winner->resign(c);
			}
		}
		move(time);
	}
	void move(int time) {
		if (wait->getSize() == 0) {
			return;
		}
		if (winner->getSize() < k) {
			Customer* c = wait->top();
			wait->pop();
			c->time = time;
			winner->push(c);
		}
		else {
			if (wait->top()->item > winner->top()->item) {
				Customer* wi = winner->top();
				winner->pop();
				Customer* wa = wait->top();
				wait->pop();
				wi->time = time;
				wa->time = time;
				winner->push(wa);
				wait->push(wi);
			}
		}
	}
	list<int> getList() {//返回获奖用户的id
		list<int>re;
		list<Customer*>origin = winner->returnList();
		for (auto it = origin.begin(); it != origin.end(); ++it) {
			re.push_back((*it)->id);
		}
		return re;
	}
	

};
list<list<int>> topK2(vector<int>& arr, vector<bool>& op, int k) {
	list<list<int>>re;
	ReturnWinner* returnWinner = new ReturnWinner(k);
	for (int i = 0; i < arr.size(); ++i) {
		returnWinner->operate(i, arr[i], op[i]);//一次交易
		re.push_back(returnWinner->getList());
	}
	return re;
}
bool cmp(list<int>& re1,list<int>& re2) {
	re1.sort();
	re2.sort();
	auto it1 = re1.begin();
	auto it2 = re2.begin();
	while (it1 != re1.end() && it2!=re2.end()) {
		if ((*it1) != (*it2)) {
			return false;
		}
		++it1;
		++it2;
	}
	return true;


}
int main() {
	int testTime = 100;
	//比较器
	for (int i = 0; i < testTime; ++i) {
		vector<int> arr;
		vector<bool> op;
		geneArr(arr, op, 60);
		list<list<int>>re1 = topK(arr, op, 3);
		list<list<int>>re2 = topK2(arr, op, 3);
		auto it1 = re1.begin();
		auto it2 = re2.begin();
		while (it1 != re1.end() && it2 != re2.end()) {
			if (!cmp(*it1, *it2)) {
				cout << "error" << endl;
			}
			++it1;
			++it2;
		}
	}
	
	return 0;
}
;