堆的基础学习

glibc 堆学习(一)-基础概念 在程序运行过程中,堆可以提供动态分配的内存,允许程序申请大小未知的内存。堆其实就是程序虚拟地址空间的一块连续的线性区域,它由低地址向高地址方向增长。我们一般称管理堆的那部分程序为堆管理器。 阅读详情

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

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

建堆

  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;
}
GD32 TIMER0 PWM输出死活没波形?别忘了这个关键配置(附完整代码) 本文详细解析了GD32 TIMER0 PWM输出无波形的常见问题,特别强调了高级定时器特有的主输出使能配置。通过完整的代码示例和调试技巧,帮助开发者快速解决PWM输出问题,适用于无刷电机控制等嵌入式应用场景。 阅读详情

相关推荐

Infinite-Canvas:一站式AI绘画工作流平台部署与实战指南

在 AI 绘画和内容创作领域,你是否经常遇到这样的困扰:灵感来了,却要在多个工具间来回切换——找素材、写提示词、调整参数、批量生成,整个过程繁琐且低效。创作一个系列作品时,管理不同版本的图片和提示词更是让人头疼。如果你渴望一个能整合所有流程,实现从素材管理、提示词工程到批量出图一站式完成的工作台,那么今天介绍的 Infinite-Canvas 正是为你量身打造的解决方案。 Infinite-Canvas 是一个开源的本地网页应用,它将 AI 绘画的完整工作流集成在一个界面中。无论你是想快速生成单张图片,还是

weixin_28707535的博客 338

【堆 - 专题】“加强堆” 解决 TopK 问题!

作为电商平台负责人,给购买次数最多的前 K 名用户颁奖!如何快速实现呢?

weixin_46879314的博客 1222

关于堆的学习

1.堆的概念 大顶堆:每个节点的值都大于或等于其左右孩子节点的值,下图是完全二叉树是大顶堆 小顶堆:每个节点的值都小于或等于其左右孩子节点的值 如果我们用指针来表示大顶堆,那么每个结点需要三个指针来找到它的上下结点(父结点和两个子结点各需要一个),但如果使用完全二叉树,表达就会边的特别方便,如下图所示。完全二叉树使用数组而不需要指针就可以表示大顶堆。(注意为了方便,是从下标1开始存放元素的)...

chenkaibsw的专栏 346

国密系列算法简介

众所周知,为了保障商用密码的安全性,国家商用密码管理办公室制定了一系列密码标准,包括SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖冲之密码算法(ZUC)那等等。其中SM1、SM4、SM7、祖冲之密码(ZUC)是对称算法;SM2、SM9是非对称算法;SM3是哈希算法。目前,这些算法已广泛应用于各个领域中,期待有一天会有采用国密算法的区块链应用出现。其中SM1、SM7算法不公开,调用该...

HardessGod的博客 5775

保姆级教程:用海思PQTool搞定ISP图像调试,从参数读取到固件烧录全流程

本文提供海思PQTool的ISP图像调试全流程指南,从参数读取、实时调试到固件烧录,涵盖环境配置、核心功能解析、参数固化及生产部署。通过实战案例和避坑指南,帮助开发者高效提升图像质量,适用于海思开发板的ISP调试与优化。

weixin_30872337的博客 280

堆-初步学习堆的简单使用

堆的使用 今天学习了一个算法,堆 用法之一: 堆一般用数组的形式保存数字,通过维护一个完全二叉树的结构来保存前几大的数字; 先确定一个需要维护的数字的多少,然后建立一个数组,数组的第一树根是arr【1】; 然后每个arr[i]树根的左儿子是arr[2i]右儿子 是arr[2i+1];十分具有规律,所以一般就用数组就可以解决,用链表有些麻烦,但是比较公整; 1.先存进前m,个数进入数组, 2.然后循环由m/2开始循环到1,查看每个结点的儿子和根是否符合关系,然后调整, 3,通过不断更新和调整遍历完所有输入的数

tmh 236

堆的学习

今天把堆重新看了一篇,堆分为最小堆,最大堆。。 N个元素称为堆,当且仅当它的关键字序列k1,k2,….kn,满足: Ki<=k2i ki<=k2i+1(最小堆) 或者满足ki>=k2i ki>=k2i+1(最大堆) 由定义就可看出堆的一个重要性质。。 堆的操作: up down insert delete delete_max makeheap ...

weixin_30485291的博客 156

【AI智能体】最强AI编程利器 Claude Code 从部署到项目实战详解

最强AI编程利器 Claude Code 从部署到项目实战详解

congge 4511

Qwen大模型参数解析

Qwen系列模型的参数主要分为(决定模型结构)和(控制生成行为)两类。由于该系列已迭代多个版本,参数设计也在不断演进,我会结合最新版本为你进行分层梳理。

yeyiboy的博客 165

堆的理论知识学习

最近花了两天时间上网查阅资料学习了堆的内存管理模式,找到了几篇还不错的文章,在此分享一下: Linux堆内存管理深入分析上 Linux堆内存管理深入分析下 PWN之堆内存管理 申请内存块 看雪的求助 较详细的内存分配过程 Glibc 内存管理 Ptmalloc2 源代码分析 华庭(庄明强) (经典,较长但较详细,可自己上网找) 这几篇文章讲的已经比较详细,基础的东西我就不再赘述,只是总结一下我自己...

【xiaoxiaorenwu's blog】 377

【乐企文件生成工程】关于乐企文件生成工程的详细介绍

发票文件生成方式有两种思路:1、根据已有的OFD模板,动态替换ofd模板内容;之后将ofd转pdf(局限:单行问题不大)详情可以在此处了解2、根据html模板动态占位:该工程就是这种方式 ,目前效果良好,可看下图。拿去即用的源码!无任何保留,当然也并不是所有票种都支持(时间有限、精力有限、已经连着转了,要冒烟了…)

九七的博客 2031

堆学习基础

1、什么是堆? 是虚拟地址空间的一块连续的线性区域 提供动态分配的内存,允许程序申请大小未知的内存 在用户与操作系统之间,作为动态内存管理的中间人 响应用户的申请内存请求,向操作系统申请内存,然后将其返回给用户程序 管理用户所释放的内存,适时归还给操作系统 2、各种堆管理器 dlmalloc- General purpose allocator - ptmalloc2 - glibc(Linux系统使用的libc) 本文重点学习 jemalloc - FreeBSD and Firefox tcma

山楂的博客 1536

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

数据结构0基础学习堆

堆是一种重要的数据结构,是一种完全二叉树,(二叉树的内容后面会出),堆分为大小堆,大堆,左右结点都小于根节点,(又称子节点和父节点),小堆则反过来,可以用静态数组/顺序表实现。

2403_87165176的博客 1845

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

堆的基础题目学习(EPI)

堆的应用范围也比较广泛,经常游走在各种面试题目之前,不论算法设计的题目还是海量数据处理的题目,经常能看到这种数据结构的身影。堆其实就是一个完全二叉树的结构,经常利用数组来实现。包含最大堆和最小堆两种。最大堆的性质:针对每个根节点,其节点值大于其后继节点。最小堆的性质:针对每个根节点,其节点值小于后继节点。 算法设计中堆数据结构一般直接利用STL中实现好的数据结构。其中针...

aai7747的博客 291

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

算法基础学习笔记——⑧堆\哈希表

算法基础学习笔记——⑧堆\哈希表

VLOKL的博客 1391

零基础该怎么学习Java编程 堆和栈区别是什么

零基础该怎么学习Java编程?堆和栈区别是什么?作为应用最广泛的编程语言,Java吸引了大量的人学习。为了能够更快更好的入门,参加专业学习成为绝大多数零基础转行人士的选择,下面就给大家讲解一下郑州Java零基础学习中堆和栈的区别。 内存是Java中的重要概念,而栈和堆又是内存中的两个重要部分,因此零基础学Java时,一定会接触到堆和栈。那么该如何区别堆和栈呢? 从优势及不...

qq_43444478的博客 191

JVM基础:深入学习JVM堆与JVM栈

个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈 以前堆是干啥栈是干啥都知道,就是没连在一起想想。感觉讲的不错的一篇儿~~JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题,即数据怎么放、放在哪儿,另外JVM堆中存的是对象。JVM栈中存的是基本数据类型和JVM堆中对象的引用。 JVM基础概念:JVM堆与JVM栈 数据类型 ...

JKX_geek的博客 576

有c基础学习C++第五天(内存模型,栈区,堆区)

栈区,堆区 将数据开辟到堆区,利用关键字new。 放堆区的数据,利用关键字 delete。

wdnmd____c的博客 194

Java基础学习之JVM篇:说说栈和堆的区别

学习目标 当说到JVM(Java虚拟机)我们不得不理解栈和堆,面试官也会经常请你说一说这两者之间的区别和主要作用。本节文章将以HotSpot虚拟机为例,重点围绕栈和堆来让我们一起认识Java虚拟机内存的分配方式和基础原理。 本节将一起学习: 栈的作用 堆的作用 JVM内存分配 元数据、编译后代码是存放堆内还是堆外 常量是放在堆内还是堆外 栈的作用 栈(Stack)作为一种先进后出的(FILO)数据结构,大家都有所了解,但在JVM角度来看大家都会给出栈时调用函数临时变量,而对象存放在堆中。这样从存储的角

h16407的博客 1034

Java基础学习---3、堆、GC

Java基础学习---3、堆、GC

星光不问赶路人,岁月不负有心人 946

JVM基础:深入学习JVM堆与JVM栈-堆与栈的经典问题

JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据; JVM堆解决的是数据存储的问题,即数据怎么放、放在哪儿,另外JVM堆中存的是对象。JVM栈中存的是基本数据类型和JVM堆中对象的引用。JVM基础概念:JVM堆与JVM栈数据类型Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。“引用值”代表了

beloveddarling的博客 1096

pwn学习笔记(6)--堆基础概述

​ chunk 被释放时,glibc 会将它们重新组织起来,构成不同的 bin 链表,当用户再次申请时,就从中寻找合适的 chunk 返回用户。不同大小区间 chunk 被划分到不同的 bin 中,再加上一种特殊的 bin,一共有四种:Fast bin 、Samll bin 、 Large bin 、和 Unsorted bin。这些bin记录在 malloc_state 结构中。fastbinsY :这是一个 bin 数组,里面有 NFASTBINS 个 fast bin。

qq_66013948的博客 1206
上一篇: 并查集-初步了解
下一篇: 图的基本算法
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值