数据结构与算法——堆

一、堆的基本概念

优先队列:
特殊的“队列”,取出元素的顺序是依照元素的优先权(或关键字大小,如权重),而不是进入队列的先后顺序。
堆的存储结构:是否可以采取形同二叉树的链表形式?
答:是可以的,但是由于堆经常需要加入和删除元素,采取不同的链表二叉树,可能会导致二叉树退化形成单链表,从而增加了树的高度,搜索复杂度增加。
堆的存取形式采取优先队列的完全二叉树
堆的性质:
1.结构性:堆是用数组表示的二叉树;
2.有序性:任一结点的关键字是其子树所有结点的最大值或最小值,即这种树称为最大堆或最小堆。

二、堆的抽象数据类型

ADT:
类型名称:最大堆
对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值
操作集:创建最大堆,判断是否为空/满,插入,删除

typedef struct HeapStruct* MaxHeap;
struct HeapStruct{
ElementType *Elements;
int size;
int capacity;
};

三、最大堆的代码实现

#include<iostream>
#include<cmath>
using namespace std;
#define MAXDATA 100;//哨兵

typedef struct HeapStruct* MaxHeap;
struct HeapStruct
{
    int *arr;
    int size;//当前元素个数
    int capacity;//最大容量
};

//建立最大堆
MaxHeap Create(int maxsize)
{
    MaxHeap H = new struct HeapStruct;
    H->arr = new int[maxsize+1];
    H->size = 0;
    H->capacity = maxsize;
    H->arr[0] = MAXDATA;//哨兵元素
    return H;
}

//判断是否为空
int IsFull(MaxHeap H)
{
    if(H->size==H->capacity) return 1;
    else return 0;
}

void Insert(MaxHeap H,int item)
{
    int i;
    if(IsFull(H))
    {
        cout << "最大堆已满"<<endl;
        return;
    }
    i = ++H->size;
    for(; H->arr[i/2]<item;i/=2)//其实如果最顶层元素仍比待插入元素小,那么还会继续往上顶,出现下标下益,解决方法加一个与条件:i>1,或者加一个哨兵,这里我没加
    {
        H->arr[i] = H->arr[i/2];
    }
    H->arr[i] = item;
}

//按路径遍历,输入一个结点号,会沿着一条该叶结点一路向上遍历
void Ergodic(MaxHeap H,int i)
{
    for(;i>=1;i/=2)
    {
        cout << H->arr[i]<<endl;
    }
}

int main()
{
    MaxHeap H;
    H = Create(9);//建立空堆
    Insert(H,10);//依次插入9个元素
    Insert(H,23);
    Insert(H,26);
    Insert(H,46);
    Insert(H,24);
    Insert(H,28);
    Insert(H,36);
    Insert(H,42);
    Insert(H,0);
    Ergodic(H,9);遍历其中一条路径,第9号是0,所以结果应为0264246
}

结果
结果
对应插入形成的二叉树:懒得用word做了。。。在这里插入图片描述

另附最大堆的删除:哈夫曼树中有实现堆删除的代码

Temp是取出的最大堆的最后一个元素,且容量-1
For循环从根节点开始,判定条件是是否有左儿子,parent*2=H->size是说左儿子的序号在当前容量之内,即左儿子存在。
Child是左儿子,然后比较该节点下的左右儿子大小,前提条件是右儿子也存在,即child!=H->size,即左儿子不是最后一个元素
比较完左右儿子后,再和temp比较
循环结束后,即从上向下过滤结束,parent等于要替换的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值