PAT知识点-堆

基本定义

​ 堆是一个完全二叉树,可以用数组来映射这个树。
​ 建立堆就是根据一个已知的未排序的数组,根据建堆的规则,将数组中的元素按照一定规则重新排列而已

堆的分类

​ 大根堆:根结点是最大的元素,每个结点都大于等于其左右孩子结点
​ 小根堆:根结点是最小的元素,每个结点都小于等于其左右孩子结点

堆的特点

​ 由于堆的第一个元素总是最大/最小的,所以每次取堆的第一个元素就能得到整个堆中的最值,并且!每次取完这个最值后,[堆可以进行调整,保持第一个元素是堆的最值],就是优先队列!

堆的建立

​ 就是不断调整/筛选的过程

  • 调整/筛选:

    ​ 要调整结点x,就把结点x和其左右结点中最大的孩子交换,对于结点x和其左右结点构成的树而言,就成了一个堆。
    ​ 从最后一个有分支的结点开始调整,直到根节点也调整了,就ok了。为什么这样就ok?这其实是一个分治的思想,要想在一个树上建立一个堆,首先要把树的最底下的子树建立成堆,然后上面再执行同样的操作,整体就成堆了。
    ​ 比如a,b,c, b,c是a的子树, b,c成堆后,b,c就是其堆的最值,这样再跟a的根节点较量一番,a的根节点更新后,整体就成堆了。

int heap[MAXN+1];//MAXN为堆元素个数,从heap[1]开始存元素
//给出要调整元素的位置low和最后一个元素的位置high,将该元素向下调整到相应的位置,这里如果跟顶点小于子节点,则和子节点交换
void downAdjust(int low,int high)
{
    int i=low,j=i*2;
    while(j<=high)//只要左子节点还没超过界限,表明还能继续下调
    {
        //让j指向左右节点中较大的那一个
        if(j+1<=high&&heap[j+1]>heap[j])
            j++;
        //如果该较大的子节点大于根节点
        if(heap[j]>heap[i])
        {
            //根节点和子节点交换
            swap(heap[low],heap[j]);//swap在头文件algorithm里
            //i指向子节点原来的位置,继续下调
            i=j;
            j=i*2;
        }
        else//左右子节点都没有根节点大,不能继续下调了,直接结束
        {
            break;
        }
    }
}
//根据数组,建立堆,n为堆的元素个数
void createHeap(int n)
{
    //从最后一个非叶节点到根节点,依次向下调整,想想画面
    for(int i=n/2;i>=1;i--)
    {
        downAdjust(i,n);
    }
}

这里注意heap[]数组从下标1开始存放数据,这是为了在处理完全二叉树的时候方便地索引左右子节点。

完全二叉树的最后一个非叶子结点的位置为n/2向下取整

堆排序

​ 拿大根堆来说,堆排序的实质就是把当前最大的元素(堆顶)和堆中最后一个元素交换,此时堆中的最大值排到了heap数组的最后,此时在[1,high-1]的范围内把现在堆顶(已交换)向下调整,调整完后,在[1,high-1]范围内又形成了一个大根堆,之后重复交换、调整的步骤,直到堆只有1个元素就行了。结束后,heap就会变成一个从小到大排列的数组。

void heapSort()
{
    createHeap();//先建立一个堆
    for(int i=n;i>=1;i--)
    {
        swap(heap[1],heap[i]);//堆顶和堆尾互换
        downAdjust(1,i-1);//在[1,i-1]范围内将其重新调整为堆
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值