最大堆的建立插入删除

堆(优先队列)priority queue
特殊的队列,取出元素的顺序是依照元素的优先权(关键字)大小,而出元素进入队列的先后顺序
操作:查找最大值(最小值),删除(最大值)

数组:
链表:
有序数组:
有序链表:

采用二叉搜索树? NO

采用完全二叉树 YES
堆的连个特性
结构性:用数组表示的完全二叉树:
有序性:任一结点的关键字是其字树所有结点的最大值(或最小值)
最大堆(MaxHeap)也称大顶堆:最大值
最小堆(MinHeap)也称“小顶堆”:最小值
从根节点到任意结点路径上结点序列的有序性
操作:插入任意一个元素,删除最 大值元素
最大堆的删除:取出根节点(最大值)元素,同时删除堆的一个结点

最大堆的建立:将已存在的N个元素按最大堆的要求存放在一个以为数组中

#include <stdio.h>
#include <stdlib.h>
//最大堆

#define MaxData 1000        //哨兵,该值应该根据具体情况定义为大于堆中所有可能元素的值

typedef int ElementType;

typedef struct HeapNode * MaxHeap;
struct HeapNode {
    int Capacity;            //堆的最大容量
    int Size;                //堆中当前元素个数
    ElementType *Data;    //用于存储元素的数组
};

建一个空的最大堆:

//建立一个空的最大堆
MaxHeap InitHeap(int maxsize)
{
    MaxHeap H = (MaxHeap)malloc(sizeof(struct HeapNode));
    H->Data = (ElementType*)malloc(sizeof(struct HeapNode) * (maxsize + 1));        //堆中的元素是从下标为1开始存储的,但是为了保证这个堆能存下maxsize个元素,所以要分配maxsize + 1个内存单元
    H->Capacity = maxsize;
    H->Size = 0;
    H->Data[0] = MaxData;            //将0下标的单元存储哨兵
    for (int i = 1; i < maxsize + 1; i++)
        H->Data[i] = 0;
    return H;
}

判断堆是否已满或是否为空:

int IsEmpty(MaxHeap H)
{
    return H->Size == 0;
}

//判断堆是否已满
int IsFull(MaxHeap H)
{
    return H->Size == H->Capacity;
}

插入一个元素:

//最大堆中插入一个元素
void Insert(MaxHeap H, ElementType item)
{
    int i;
    if (IsFull(H))
    {
        printf("The heap is full\n");
        return;
    }
    i = ++H->Size;        //i为插入后堆中最后一个元素的位置
    for (; H->Data[i / 2] < item; i /= 2)
        H->Data[i] = H->Data[i / 2];        //循环退出时,父节点的数据已经大于item, item已经找到了正确的位置
    H->Data[i] = item;    //将item赋给正确的下标单元
}

删除一个元素:

ElementType Delete(MaxHeap H)
{
    ElementType temp, Max;
    int parent = 1, child;
    if (IsEmpty(H))
    {
        printf("The heap is empty!\n");
        return 0;
    }
    Max = H->Data[1];            //现将最大值即根节点的值记录下来
    temp = H->Data[H->Size--];        //用最后的结点元素暂时代替根节点的数据,然后将堆的数据大小减1

    //如果2 * parent > 0,那么说明parent已经是根节点了
    for (; 2 * parent <= H->Size; parent = child)
    {
        child = 2 * parent;

        //如果Child != H->Size说明child不是最后一个结点,该parent结点还有右节点,
        //并且如果右节点的值大于左结点,那么child++;
        if (child != H->Size && (H->Data[child + 1] < H->Data[child]))
            child++;        //child指向左右子节点的较大者
        if (temp > H->Data[child]) break;            //如果孩子结点已经小于temp了, 说明找到了合适的位置
        else
            H->Data[parent] = H->Data[child];
    }
    H->Data[parent] = temp;
    return Max;
}

最大堆的建立:

1.第一步,将N个元素按输入顺序存入二叉树中,这一步需要求满足完全二叉树的结构特性,而不管其有序性

2.从最后一个右孩子的结点开始调整,做类似删除元素时的下滤操作,逐个结点调整,直至根节点

//创建一个最大堆
MaxHeap CreateMaxHeap()
{
    int dt, i = 0, j;
    int parent, child;
    ElementType X;
    MaxHeap H = InitHeap(20);        //先创建一个空的最大堆,然后往里面填充元素
    while (scanf_s("%d", &dt) != EOF)
    {
        H->Data[i + 1] = dt;
        i++;
        H->Size++;
    }
    for (j = i / 2; j >= 1; j--)        //从i / 2开始逐一向下过滤
    {
        //下面的操作和删除元素是一模一样的,只是不用将的元素个数减一
        X = H->Data[j];
        for (parent = j; 2 * parent <= H->Size; parent = child)
        {
            child = 2 * parent;
            if (child != H->Size && H->Data[child] < H->Data[child + 1])
                child++;
            if (H->Data[child] < X)
                break;
            else
                H->Data[parent] = H->Data[child];
        }
        H->Data[parent] = X;
    }
    return H;
}

打印堆中的元素:

//打印堆中元素
void printHeap(MaxHeap H)
{
    for (int i = 1; i <= H->Size; i++)
        printf("%d ", H->Data[i]);
    printf("\n");
}

先序建立树:

void PreOrderCreateHeap(MaxHeap H, int index)
{
    int dt;
    scanf_s("%d", &dt);
    if (dt == 0)
    {
        return;
    }
    H->Size++;
    H->Data[index] = dt;
    printf("please enter the left child of %d :", dt);
    PreOrderCreateHeap(H, 2 * index);
    printf("please enter the right child of %d: ", dt);
    PreOrderCreateHeap(H, 2 * index + 1);
}

主函数:

int main()
{
    MaxHeap H = CreateMaxHeap();
    PreOrderCreateHeap(H, 1);
    printHeap(H);

    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值