一、堆
堆就是用数组实现的二叉树.
堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。
堆的常用方法:
构建优先队列
支持堆排序
快速找出一个集合中的最小值(或者最大值)
堆属性
堆分为两种:最大堆和最小堆,两者的差别在于节点的排序方式。
在最大堆中,父节点的值比每一个子节点的值都要大。
在最小堆中,父节点的值比每一个子节点的值都要小。
这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。
注意:堆的根节点中存放的是最大或者最小元素,但是其他节点的排序顺序是未知的。
例如,在一个最大堆中,最大的那一个元素总是位于 index 0的位置,但是最小的元素则未必是最后一个元素。
唯一能够保证的是最小的元素是一个叶节点,但是不确定是哪一个。
下面的公式就给出了它的父节点和子节点在数组中的位置
parent(i)=i/2;
left son(i)=i*2;
right son(i)=i*2+1;
堆的几个基本操作:
上浮 shift_up;
下沉 shift_down
插入 push 复杂度o(logn)
弹出 pop 复杂度o(logn)
取顶 top
堆排序 heap_sort(本文没有实现)
这里对于这些实现的原理不一一赘述,想要知道的同学可以看 数据结构:堆 这里对于原理的实现讲述的非常清楚,本文主要在于代码的实现。
既然如此,那就上代码。
代码部分:如有不对,请指正qwq
class Heap{
public:
Heap(int p=0):op(p){size=0;};
void push(int);
void pop();
int top();
void shiftUp(int);
void shiftDown(int);
private:
int a[100010];
int size;
int op;//op=0为大根堆,反之为小根堆
};
void Heap::shiftUp(int i){
if(op==1){//小根堆
while(i/2>=1){
if(a[i]<a[i/2]){
swap(a[i],a[i/2]);
i=i/2;
}
}
}else{//大根堆
while(i/2>=1){
if(a[i]>a[i/2]){
swap(a[i],a[i/2]);
i=i/2;
}else break;
}
}
}
void Heap::shiftDown(int i){
if(op==1){//小
while(i*2<=size){
int t=i*2;
if(t+1<=size&&a[t+1]<a[t]) t++;//取左右儿子中的最小
if(a[i]>a[t]){
swap(a[i],a[t]);
i=t;
}else break;
}
}else{//大
while(i*2<=size){
int t=i*2;
if(t+1<=size&&a[t+1]>a[t]) t++;//取左右儿子中的最大
if(a[i]<a[t]){
swap(a[i],a[t]);
i=t;
}else break;
}
}
}
void Heap::push(int x){
size++;
a[size]=x;
shiftUp(size);
}
void Heap::pop(){
swap(a[1],a[size]);
size--;
shiftDown(1);
}
int Heap::top(){
return a[1];
}
参考:
https://www.jianshu.com/p/6b526aa481b1
https://www.cnblogs.com/JVxie/p/4859889.html
二、优先队列
优先队列和其实是队列的一种
普通队列:先进先出;后进先出
优先队列:出队顺序和入队顺序无关;和优先级相关
优先队列的接口和普通队列的接口是完全相同的,只是在出队和查看队首的实现方式会不同(优先级最高的在队首)
优先队列的实现方式多样,这里使用堆来实现优先队列,即在堆的基础上填加优先队列的接口,其实我个人认为这里堆等价于优先队列…(不大确定…如果有我遗漏或者不对的地方一定请指出来)
//用堆实现的优先队列
/*
使用函数指针
greatter:从大到小
lesss:从小到大
void push(T);压入堆中
void pop();弹出堆顶元素
T top()const;返回堆顶元素的值
int getSize()const;返回堆的大小
bool empty()const;判断堆是否为空
void clear();清空堆
*/
#include<iostream>
#include<vector>
using namespace std;
template<class T>
bool greatter(T a,T b){
return a>b;
}
template<class T>
bool lesss(T a,T b){
return a<b;
}
template <class T,bool (*cmp)(T,T)>
class PriorityQueue{
private:
vector<T> a;
public:
PriorityQueue(){};
~PriorityQueue(){};
void push(T);
void pop();
T top() const;
void shiftUp(int);
void shiftDown(int);
int getSize() const;
bool empty() const;
void clear();
};
template <class T,bool (*cmp)(T,T)>
void PriorityQueue<T,cmp>::shiftUp(int i){
int t=i>>1;
while(t>=0){
if(cmp(a[i],a[t])){
swap(a[i],a[t]);
i=t;
t>>=1;
}else break;
}
}
template <class T,bool (*cmp)(T,T)>
void PriorityQueue<T,cmp>::shiftDown(int i){
int size=a.size();
int t=i<<1;
while(t<size){
if(t+1<size&&cmp(a[t+1],a[t])) t++;
if(cmp(a[t],a[i])){
swap(a[i],a[t]);
i=t;
t<<=1;
}else break;
}
}
template <class T,bool (*cmp)(T,T)>
void PriorityQueue<T,cmp>::push(T x){
a.push_back(x);
int n=a.size()-1;
shiftUp(n);
}
template <class T,bool (*cmp)(T,T)>
void PriorityQueue<T,cmp>::pop(){
int n=a.size()-1;
a[0]=a[n];
a.pop_back();
shiftDown(0);
}
template <class T,bool (*cmp)(T,T)>
T PriorityQueue<T,cmp>::top() const{
return a[0];
}
template <class T,bool (*cmp)(T,T)>
int PriorityQueue<T,cmp>::getSize() const{
return a.size();
}
template <class T,bool (*cmp)(T,T)>
bool PriorityQueue<T,cmp>::empty() const{
if(a.size()==0) return true;
return false;
}
template <class T,bool (*cmp)(T,T)>
void PriorityQueue<T,cmp>::clear(){
a.clear();
}
int main()
{
cout<<"测试:"<<endl;
PriorityQueue<int,greatter> h1;
PriorityQueue<int,lesss> h2;
cout<<"输入测试数据的个数:"<<endl;
int n;cin>>n;
cout<<"输入测试数据"<<endl;
for(int i=1;i<=n;i++){
int x;cin>>x;
h1.push(x);
h2.push(x);
}
cout<<"堆的大小为:"<<h1.getSize()<<endl;
cout<<"大根堆按序输出:"<<endl;
for(int i=1;i<=n;i++){
cout<<h1.top()<<" ";
h1.pop();
}
if(h1.empty()) cout<<"元素已被完全弹出"<<endl;
else{
cout<<"有元素未被弹出"<<endl;
h1.clear();
}
cout<<"堆的大小为:"<<h2.getSize()<<endl;
cout<<"小根堆按序输出:"<<endl;
for(int i=1;i<=n;i++){
cout<<h2.top()<<" ";
h2.pop();
}
if(h2.empty()) cout<<"元素已被完全弹出"<<endl;
else{
cout<<"有元素未被弹出"<<endl;
h2.clear();
}
}