堆的基本操作

判断一个结点是否在二叉树中
堆的基本操作

什么是堆

堆是一个数据结构的统称,堆通常是一个可以被看做一棵树的数组对象。满足下列性质

  • 堆中某个节点的值总是不大于或不小于其父节点的值
  • 堆总是一棵完全二叉树

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

大堆: 任意一个结点的值关键码(值)均大于等于它的左右孩子的关键码(值),位于对顶结点的关键码最大,从根节点到每个结点的路径上数组元素组成的序列都是递减的。
小堆: 任意一个结点的值关键码(值)均小于等于它的左右孩子的关键码(值),位于对顶结点的关键码最最小,从根节点到每个结点的路径上数组元素组成的序列都是递增的。


堆的基本操作

堆的创建

  • 先申请一块空间,然后对其赋值形成二叉树,在对二叉树进行调整形成小堆
void CreateHeap(Heap * hp, int * array, int size,Compare com)
{
    int i = 0;
    int Root = 0;
    assert(hp);
    hp->_array = (DataType *)malloc(sizeof(DataType)*size);
    if(NULL == hp->_array)
    {
        printf("内存申请失败!!!\n");
        assert(0);
    }

    hp->_size = 0;
    hp->_capacity = size;
    hp->com = com;

    //赋值
    for(i=0; i< size; ++i)
    {
        hp->_array[i] = array[i];
        hp->_size += 1;
    }

    //找出最后一个非叶子结点
    Root = (size-1) >> 1;

    for(; Root >= 0; --Root)
        AdjustDown(hp,Root);
}

向下调整(形成小堆)

  • 找到最后一个非叶子结点
  • 以非叶子结点进行判断是否是小堆
  • 如果不是进行调整
  • 调整完后,可能该结点的孩子结点的值被改变,所以需要继续调整以孩子结点为根节点的二叉树,直到无元素可调或者超出元素的范围
  • 继续调整其他非叶子结点,知道把第一个非叶子结点调整完后,就形成了小堆
void AdjustDown(Heap * hp,int parent)
{
    int child = (parent << 1) + 1;
    assert(hp);

    while(child < hp->_size)
    {
        //找到孩子中较小的一个
        if(child+1 < hp->_size && hp->com(hp->_array[child+1],hp->_array[child]))
        {
            child += 1;
        }
        //括号里面是一个函数指针,根据传来的参数确定需要大堆还是小堆
        //如果双亲大于孩子,则交换
        if(hp->com(hp->_array[child],hp->_array[parent]))
        {
            swap(&hp->_array[parent],&hp->_array[child]);
            parent = child;
            child = (parent+1) << 1;
        }   
        else
        {
            break;
        }
    }
}

插入元素

  • 检测容量,如果空间已满,警醒扩容
  • 将元素插到堆的最后面
  • 进行向上调整
void InsertHeap(Heap* hp, DataType data)
{
    assert(hp);
    CheckCatacity(hp);
    hp->_array[hp->_size] = data;
        hp->_size += 1;   

    if(hp->_size>1)
        //向上调整
        AdjustUp(hp,hp->_size-1);
}

向上调整

  • 使用传来的结点序号为孩子结点,进行与父节点进行比较,小于父节点交换,大于则调整完毕
void  AdjustUp(Heap* hp,int child)
{
    int parent = (child-1) >> 1;
    while(child)
    {
        if(hp->com(hp->_array[child],hp->_array[parent]))
        {
            swap(&hp->_array[parent],&hp->_array[child]);
            child = parent;
            parent = (child-1) >> 1;
        }
        else
            break;
    }
}

删除对顶元素

  • 将堆顶元素与最后一个元素进行交换
  • 有效个数减1
  • 调整二叉树数为需要的堆
void DeleteHeap(Heap* hp)
{
    assert(hp);
    swap(&hp->_array[0],&hp->_array[hp->_size-1]);
    hp->_size -= 1;
    AdjustDown(hp,0);
}

void printHeap(Heap hp)
{
    int i = 0;
    for(i=0; i<hp._size; ++i)
    {
        printf("%d ",hp._array[i]);
    }
    printf("\n");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值