最大最小堆的插入与删除

/删除操作的BUG已经修复 /
最大堆、最小堆是一种用可用数组存储,并模拟实现二叉树的数据结构。
最大(小)堆具有以下的显著性质:
●最大(小)堆是一棵树,且是完全二叉树。
●最大(小)堆是每个根节点都一定大(小)于等于其子节点。
●在具体的存储时数组的[0]位置存放一个哨兵元素用于插入时防止越界,且由于这是 一棵完全二叉树,位于[i]的节点其对应的父节点刚好是[i/2]。
●这里讨论的是二叉堆,以下代码对应二叉堆的性质。

最大堆的实例
这里写图片描述
最小堆的实例
这里写图片描述

最大堆的删除操作:
这里写图片描述
最大堆的删除每次是从堆中删除最大的元素,即堆顶
删除的基本步骤:
1、堆的size减一,用变量保存堆的末尾元素(本图中是30)
2、删除堆顶,并上浮两个节点中的较大的子节点补位。
3、判断child指向的节点是否越界,没有的话,进入下一层,并重复第二步。
4、将末尾元素补位上浮到parent指向的节点。

最小堆的删除操作:
这里写图片描述
最大堆的删除每次是从堆中删除最小的元素,即堆顶
删除的基本步骤:
1、堆的size减一,用变量保存堆的末尾元素(本图中是30)
2、删除堆顶,并上浮两个节点中的较小的子节点补位。
3、判断child指向的节点是否越界,没有的话,进入下一层,并重复第二步。
4、将末尾元素补位上浮到parent指向的节点。

最大堆的插入操作:
这里写图片描述
插入元素每次都从数组末尾开始查找查找点:
1、若此时插入点不符合条件,则将插入点的父节点下沉。
2、判断是否到顶(有哨兵在可以防住越界),没有到顶继续第一步。
3、找到插入点时插入。

最小堆的插入操作:
这里写图片描述
插入元素每次都从数组末尾开始查找查找点:
1、若此时插入点不符合条件,则将插入点的父节点下沉。
2、判断是否到顶(有哨兵在可以防住越界),没有到顶继续第一步。
3、找到插入点时插入。

具体的代码

/*
时间:2015.7.18
名称:哈夫曼树
操作:二叉堆的建立(构造函数)、最大最小堆的插入、最大最小堆的删除、判断堆空、判断堆满
简述:
*/
#include<iostream>
using namespace std;
const int MAX_DATA=10000;//堆的可容纳的最大元素,当做首位的哨兵用
const int MIN_DATA = -10000;//堆的可容纳的最小元素,当做首位的哨兵用
enum Type{ Maximum, Minimum };//分别代表最大最小堆
class Heap
{
private:
    int *data;      //存放堆中元素
    int size;       //堆的目前大小
    int capacity;//堆的最大容量
    Type type;  //堆的具体类型
public:
    Heap()
    {
        int c, t;
        cout << "堆的最大容量为";
        cin >> c;
        cout << "堆的类型为(1为最大堆,0为最小堆):";
        cin >> t;
        size = c;//初始化是没有元素
        capacity = MAX_DATA;//设置容量为最大
        if (t) type = Maximum;//设置堆的类型
        else type = Minimum;

        data = new int[capacity + 1];//动态申请内存
        if (type==Maximum) data[0] = MAX_DATA;//最大堆的0位置处放最大元素
        else data[0] = MIN_DATA;//最大堆的0位置处放最小元素

        //最大堆的元素输入按照从大到小
        //最小堆的元素输入按照从小到大
        for (int i = 1; i <= c; i++)
            cin >> data[i]; 
    };
    ~Heap()
    {
        delete[]data;
    };  

    //判断堆是否满
    int isFull()
    {
        if (size == capacity)
            return 1;
        else
            return 0;
    }

    //判断堆是否空
    int isEmpty()
    {
        if (size == 0)
            return 1;
        else
            return 0;
    }

    //最大堆的插入
    void insertMaxHeap()
    {
        int i,item;
        cout << "输入插入的元素";
        cin >> item;
        if (isFull())
        {
            cout << "堆已满" << endl;
            return;
        }
        i = size + 1; size++;//先指向数组的末尾,size增加1是因为插入时增加了一个元素    
        for (; data[i/2] < item; i /= 2)//找到第一个比item大的元素时结束
        {
            data[i] = data[i/2];//若没有找到,则将上一层的元素挪到下一层
        }
        data[i] = item;//找到插入点,插入item
    }

    //最小堆的插入
    void insertMinHeap()
    {
        int i, item;
        cout << "输入插入的元素";
        cin >> item;
        if (isFull())
        {
            cout << "堆已满" << endl;
            return;
        }
        i = size + 1; size++;
        for (; data[i/2] > item; i /= 2)//找到第一个比item小的元素时结束
        {
            data[i] = data[i / 2];//没有找到则将上一层元素挪到下一层
        }
        data[i] = item;//找到插入点,插入item
    }

    //最大堆的删除
    int deleteMaxHeap()
    {
        //原理如下:记录并删除最大元素,然后自顶向下上浮其较大的子节点
        //上浮完毕后进入向下进入一层,最后将最小的元素补位上浮
        if (isEmpty())
        {
            size = 0;
            return MAX_DATA;//为空返回不可能的值
        }

        int child=1, parent=1;//指向父节点和子节点的游标
        int max = data[1];//记录最大值用于返回
        int last = data[size--];//记录末尾最小值,并且size减1

        for (parent = 1; parent * 2 <= size; parent = child)//循环上浮子节点
        {
            child = parent * 2;//child指向其子节点
            if (child!=size)//有时只有一个子节点,这里要防止越界
            if (data[child] < data[child + 1])//child指向的是较大的子节点
                child++;

            if (last<data[parent])//找到了min的插入点就代表上浮完毕,结束循环并插入
            if (last>data[child])
                break;
            else
                data[parent] = data[child];//没有找到就继续上浮
        }
        data[parent] = last;//将末尾的最小值补位上浮
        return max;
    }

    //最小堆的删除
    int deleteMinHeap()
    {
        //原理如下:记录并删除最小元素,然后自顶向下上浮其较小的子节点
        //上浮完毕后进入向下进入一层,最后将最大的元素补位上浮
        if (isEmpty())
        {
            size = 0;
            return MIN_DATA;//为空返回不可能的值
        }
        int child=1, parent=1;//指向父节点和子节点的游标
        int min = data[1];//记录最小值用于返回
        int last= data[size--];//记录末尾最后一个值

        for (parent=1; parent*2 <= size; parent = child)//循环上浮子节点
        {
            child = parent * 2;//child指向其子节点
            if (child!=size)
            if (data[child] > data[child + 1])//child指向的是较小的子节点
                ++child;

            if (last > data[parent])//找到了last的插入点就代表上浮完毕,结束循环并插入
            if (last < data[child])
                    break;
            else
                data[parent] = data[child];//没有找到就继续上浮
        }
        data[child] = last;//将末尾的最大值补位上浮
        return min;
    }

    //堆的查看
    void show()
    {
        int change = 1,tota1 = 0;
        for (int i = 1; i <= size; i++)
        {
            if (change == i)
            {
                cout << endl;
                change *= 2;
            }
            cout << data[i] << ' ';
            tota1++;
        }
        cout << endl;
    }
};

int main()
{
    //主函数是测试代码
    Heap heap;
    heap.show();

    //heap.insertMaxHeap();
    heap.insertMinHeap();
    heap.show();

    //int i = heap.deleteMaxHeap();
    int i = heap.deleteMinHeap();
    heap.show();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值