堆的简单介绍

目录

一、完全二叉树

二、堆的定义

三、堆的操作

1.上滤

2.自顶向下建堆

3.下滤

4.自下而上建堆

四、堆的应用

1.优先队列弹出最小元素

2.堆排序

下滤

堆排序递归


一、完全二叉树

完全二叉树:只有最后一行不满,且最后一行结点都集中在树的左边。

二、堆的定义

priority_queue<int,vector<int>,less<int>>heap;//大根堆
priority_queue<int,vector<int>,greater<int>>heap;//小根堆

堆结构是一种数组对象,它可以被视为完全二叉树,树的结点和数组中树对应。

我们定义用arr[i]存储完全二叉树中编号为i的结点,这样有以下

例如第i个结点的父结点下标是i/2,左孩子结点的下标2i,右孩子结点下标为2i+1。

大根堆:根结点大于等于左右孩子结点

小根堆:根结点小于等于左右孩子结点

三、堆的操作

1.上滤

以小根堆为例,堆的最后一个元素破坏了堆序性,这时要将破坏堆序性的元素与它的父结点比较如果小于就上移该结点,这个操作主要用于插入元素到堆尾。

2.自顶向下建堆

将新元素不断放在堆尾,然后不断进行上滤操作

int arr[maxsize];int size;
void insert(int x)
{arr[++size]=x;
int i=size;
while(size!=1)
{   if(arr[size]>=arr[size/2])//以小根堆为例,如果大于就结束循环
    {break;}
    swap(arr[size],arr[size/2]);//简写,交换操作
    i/=2;//索引不断向上层父节点移动。
}    
}

3.下滤

例如:大根堆中,堆顶元素10不满足堆序性,这时要从上到下将10不断与左右孩子中数值大的结点进行比较,如果10小于这个数要交换。

4.自下而上建堆

从倒数第二排开始对每一个父结点进行下滤操作直到根节点操作完毕。

以创建小根堆为例:

int arr[maxsize];int size;int len;//len是指一共有几个数要插入
void insert(int x)//size指的是当前位置
{size=len;//从下往上插入
arr[size--]=x;
int i=size;
while(i*2<=len)//下滤操作,这里的while条件用来判断是否是根节点(左孩子是否存在)
{int nex=2*i;
if(i*2+1<len&&arr[2*i+1]<arr[2*i])//右孩子存在,取左右孩子最小值
 {nex=2*i+1;}
if(arr[i]<arr[nex])//如果根节点的值小于左右孩子最小值,交换
{
    swap(arr[i],arr[nex])
}
else break;
i=nex;//下移
}
}

四、堆的应用

1.优先队列弹出最小元素

将最后一个元素赋给根节点,然后进行下滤操作即可。

int arr[maxsize],len;
void del()
{arr[1]=arr[len];//将最后一个赋给根节点
len--;
int position=1;//从根节点开始进行下滤
while(position*2<=len)//左孩子存在,不是根节点
{int nex=position*2;
if(position*2+1<=len&&arr[position*2+1]<arr[position*2])
{
    nex=position;//右孩子存在且比左孩子小
}
if(arr[position]<arr[nex])
{swap(arr[position],arr[nex]);
}
else break;//往下移的过程中当前节点已经小于左右孩子结点
position=nex;
}        
}

2.堆排序

堆排序是在优先队列弹出堆顶元素的基础上,弹出元素仍然占用原存储单元。一般情况下,为保证排序后是正序,我们采用大根堆进行排序。

堆排序主要有两个关键步骤:

  • 下滤

在arr[1]-arr[i]已经是一个大根堆的前提下,将arr[1]和arr[i]交换后,重新调整前i-1个元素使其成为大根堆(实际上就是下滤,下面是另一种写法)

void heapcreat(int arr[],int s,int t)
{int temp=arr[s];
int i=s;int j;
for(j=2*i;j<=t;j*=2)//初始化位置为该结点的左孩子结点
{if(j<t&&arr[j+1]>arr[j])//右孩子存在,现在要在左右孩子里面找一个大的
{j+=1;}
if(temp>arr[j]) break;
arr[i]=arr[j];//这个过程是下面的赋值给上面的,实际上已经覆盖了上面的
i=j;//更新到当前的孩子结点
}
arr[i]=temp;//相当于将已经覆盖的堆顶插入
}
  • 堆排序递归

void heapsort(arr[],int n)
{int i;
for(i=n/2;i>0;i--)
  heapcreat(arr,i,n);
for(i=n;i>1;i--)
{   arr[0]=arr[1];
    arr[1]=arr[i];
    arr[i]=arr[0];
    heapcreat(arr,1,i-1);
}
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值