一、堆
1.概念
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<=K2i+2 ,则称为小堆(或大堆)。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
2.性质
堆基于完全二叉树
堆的父节点总是大于或者小于它的左右儿子
3.分类
小根堆和大根堆
二、塔建堆
1.下沉算法
1.先找到第一个叶子节点
2.如果儿子节点小于(大于)父节点符合大根堆(小根堆)则不需要交换,否则交换
3.接着循环上面操作
2.上浮算法
1.找到最后一个节点
2.得到该节点的父节点,如果符合大/小根堆的规则则不交换,否则交换
3.重复上面
贴小代码
#include <bits/stdc++.h>
using namespace std;
class heap
{
private:
/* data */
int *arr=nullptr;
int size=0;
static const int NULL_INDEX=-1;
// 下标是否存在
bool contains(int index){
return index>=0&&index<size;
}
// 获取左节点下标
int getLeft(int parent){
return 2*parent+1;
}
// 获取右节点下标
int getRight(int parent){
return 2*parent+2;
}
// 获取父节点下标
int getParent(int son){
return (son-1)/2;
}
// 获取父节点的小儿子的下标
int getMinSon(int parent){
int left = getLeft(parent), right = getRight(parent);
if (contains(left)==false) //没有子节点
return NULL_INDEX;
return contains(right)==false ? left : arr[left] < arr[right] ? left : right;
}
public:
void init(int index){//初始化,进行下沉操作
while(index--)//得到最后一个非叶子节点
if(contains(getLeft(index))==true) break;
while(index>=0)
{
int parent = index,parentVal=this->arr[index];
while(true)
{
int left=getLeft(parent),right=getLeft(parent);
if(contains(left)==false)//没有左节点
break;
int minSon=getMinSon(parent);
if(parentVal<=arr[minSon])//已经是最小
break;
arr[parent]=arr[minSon];
parent=minSon;
}
arr[parent]=parentVal;
index--;
}
}
heap(int size){
this->size=size;
this->arr=new int[size];
for(int i=0;i<this->size;i++)
cin>>this->arr[i];
init(size);
}
heap(int arr[],int size){
this->size=size;
this->arr=new int[size];
for(int i=0;i<this->size;i++)this->arr[i]=arr[i];
init(size);
};
~heap(){
delete [] arr;
};
void push(int val)//插入,上浮
{
int son=size;//将新元素插入到最后
arr[size++]=val;
while (true)
{
int parent=getParent(son);//找到父节点
if(contains(parent)==false)//没有父节点,结束
break;
if(parent <= val)//符合父亲节点比儿子小,结束
break;
arr[parent]=val;//交换
val=arr[parent];
}
arr[son]=val;
}
void pop()//删除,下沉与初始化一致
{
arr[0]=arr[size-1];//长度减一
size--;
int index=size;
while(index--)//
if(contains(getLeft(index))==true) break;
while(index>=0)
{
int parent = index,parentVal=this->arr[index];
while(true)
{
int left=getLeft(parent),right=getLeft(parent);
if(contains(left)==false)
break;
int minSon=getMinSon(parent);
if(parentVal<=arr[minSon])//已经是最小
break;
arr[parent]=arr[minSon];
parent=minSon;
}
arr[parent]=parentVal;
index--;
}
}
int top(){//返回堆顶
return arr[0];
}
int* sort()//堆排序
{
int n=size;
int yy=size;
int *ans=new int[size];
while(n--)
{
ans[n]=top();
pop();
}
size=yy;
return ans;
}
int length(){
return size;
}
};
int main(void){
int a[10]={10, 9,8,7,6,5,4,3,2,1};
int b[10]={1,2,3,4,5,6,7,8,9,10};
heap h(b,10);
int *arr=h.sort();
for(int i=0;i<h.length();i++){
cout<<arr[i]<<endl;
}
}