数据结构 二叉堆 数组实现

本文介绍了数据结构中的二叉堆,特别是通过数组实现二叉堆的方法。二叉堆具有非叶子节点值不大于(或不小于)其左右孩子值的性质。在数组上实现堆可以方便地进行节点比较。堆操作包括插入元素和取出元素,其中插入时要保持堆性质,取出元素通常取最大或最小值,可通过大顶堆和小顶堆实现。详细步骤以小顶堆为例进行了说明。

堆还是比较常用的数据结构

二叉堆也就是以二叉树形式构造的堆

我们知道二叉树可以用数组很方便的实现

所以用数组实现二叉堆也不是很难的事情

首先我们来了解一下二叉堆的性质:非叶子节点的值均不大于(或不小于)其左右孩子的值

如果用二叉堆用数组来实现就是n个元素{k1,k2,k3,...,kn}

ki<=k(2*i)&&ki<=k(2*i+1)  或者 ki>=k(2*i)&&ki>=k(2*i+1)    其中(i=1,2,...,n/2);

如此我们就能很方便的在数组上实现根节点和孩子节点的比较

堆中插入元素,插入元素之后还需要保持堆的性质

堆中取元素的时候一般都是取得堆中最大或者最小的元素

这时我们就可以使用大顶堆来维护取最大值,小顶堆来维护取最小值

堆中取出元素时也需要继续维护堆的性质


以小顶堆的数组 实现为例

插入元素:

1.从堆末尾插入元素

2.比较和其父节点元素的大小

    2.1.比父节点小,对元素和父节点的元素执行交换操作,

    2.2.比父节点大,结束

3.重复2直到根节点


取出最小元素:

1.取出堆的根节点

2.取出堆的最后一个元素插入到根节点

3.比较根节点和左右孩子的大小

   3.1.比左右孩子都大,结束

   3.2.只比一个大,交换根节点元素和孩子节点元素

   3.3.比两个都大,和最小的那个孩子节点交换

4.重复3直到结束,返回1取出的根节点


下面实现一个小顶堆来维护取最小值。

#include<stdlib.h>
#include<stdio.h>
int heap[1000];//定义堆的大小
int end=0;//指向堆中的最后一个元素并且标记元素的个数

void insert(int a){
    int e,p,tmp;//e最后一个元素在数组的位置,p为e的父节点。
    heap[++end]=a;//从尾部插入元素
    e=end;
    //对插入的元素进行上升操作
    while(e>1){
        p=e>>1;
        if(heap[e]<heap[p]){//如果比父节点小就上升
            tmp=heap[e];
            heap[e]=heap[p];
            heap[p]=tmp;
        }else break;//比父节点大直接break,小顶堆的性质决定
        e=p;
    }
}
int getMin(){

    int ls,rs,rt=1;            //rt指向堆的根节点,ls指向根节点的左孩子,rs指向根节点的右孩子
    int res,last,tmp;       //res堆中的最小值,也就是堆的根节点,last为堆中的最后一个元素
    res=heap[rt];           //取出根节点,所以堆的元素个数需要减一
    last=heap[end--];    //得到堆的最后一个元素
    heap[rt]=last;          //把最后一个元素从根节点插入

    //对根节点进行下降操作
    while(1){
        ls=rt<<1;rs=rt<<1|1;

        if(ls>end||rs>end){//如果左孩子或者右孩子指向超出元素的总数,也就是指向空
            if(ls<=end&&heap[rt]>heap[ls]){//左孩子没有超出,并且需要交换
                tmp=heap[rt];
                heap[rt]=heap[ls];
                heap[ls]=tmp;
            }
            break;
        }

        if(heap[rt]<=heap[ls]&&heap[rt]<=heap[rs])break;//左孩子右孩子都比根节点大,不需要交换

        if(heap[rt]>heap[ls]&&heap[rs]>=heap[ls]){//比较根节点和左右孩子,和最小的交换
            tmp=heap[rt];
            heap[rt]=heap[ls];
            heap[ls]=tmp;
            rt=ls;
        }else{
            tmp=heap[rt];
            heap[rt]=heap[rs];
            heap[rs]=tmp;
            rt=rs;
        }

    }
    return res;
}
int main(){
    //插入20个数据进行测试一下
    int a,i;
    for(i=1;i<=20;i++){
        a=rand()%100;
        printf("%2d ",a);
        insert(a);
    }
    printf("\n");
    while(end>0){
      printf("%2d ",getMin());
    }
    printf("\n");
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值