关闭

[置顶]

标签: 数据结构
326人阅读 评论(0) 收藏 举报
分类:

概念

堆是一个用数组表示的完全二叉树,并满足以下两个特性:
1)父节点的键值总是大于或等于(小于等于)其子树上的任意结点
2)每个结点的左子树和右子树都是个堆。
如果父节点的键值总是大于等于任何一个子节点的键值,那么这时称之为最大堆或者大顶堆。反之,如果父节点的键值总是小于等于任何一个子节点的键值,那么这时称之为最小堆或者小顶堆。


插入操作

算法如下:
1)如果堆已满则不能插入
1)否则,把需要插入的值x插入到数组最后然后进行调整
2)从最后一个结点的父节点开始循环,如果父节点大于(小于)x,把父节点与x进行对换。
最大堆算法如下(最小堆与之类似,不在此赘述):

//最大堆的插入操作 
bool Insert(int num){
    //最大堆已满则无法插入 
    if(this->IsFull()){
        return false;
    }
    //保存最后一个元素的位置
    int i = ++size; 
    //从最后一个元素的父节点开始进行过滤
    //如果父节点小于num,那么把父节点下移 
    //data[0]控制哨兵元素,它不小于最大堆中最大元素,控制循环结束 
    for(; this->data[i/2] < num ; i /= 2){
        this->data[i] = this->data[i/2];
    }
    this->data[i] = num;
    return true;
}

删除操作

算法如下:
1)如果堆为空,那么不能进行删除
2)否则,首先保存根节点的键值,之后用最后一个结点来代替根节点,对堆进行相应的调整使之称为最大堆或者最小堆。
3)遍历整个堆,找到左右孩子中的最大值(最小值),之后与根节点进行比较,如果根结点小于(大于)左右孩子中则把根结点下移。如果根结点大于等于(小于等于)则跳出循环。

//把data[n]为根的子堆调整为最大堆
void Predown(int n){
    //保存下标为n的元素
    int x = this->data[n];
    int parent,child = 1;
    //用最后一个元素来替代第一个最大值 
    for(parent = n ; parent*2 <= this->size ; parent = child){
        //child指向当前结点的左孩子 
        child = parent*2;
        //左孩子的下标不等于最大堆容量,则说明有右孩子
        //右孩子的键值如果父节点,那么child指向右孩子,否则仍指向左孩子 
        if(child != this->size && this->data[child] < this->data[child+1]){
            child++;//选择左右孩子中最大值 
        }
        if(x >= this->data[child]){//找到了合适的位置 
            break;
        }else{//把孩子上移
            this->data[parent] = this->data[child];
        }
    }
    this->data[parent] = x; 
}

//最大堆的删除最大值操作
int DeleteMax(){
    //最大堆是空时 
    if(this->IsEmpty()){
        return MaxData;
    } 
    int max = this->data[1];
    this->data[1] = this->data[size];
    //最大堆规模减一 
    this->size--;
    //然后把最后一个元素为根结点进行调整为最大堆 
    this->Predown(1);
    return max; 
}

建堆操作

建堆操作有以下两种方式:
1)通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中,其时间代价最大为O(NlogN)
2)线性时间复杂度下建堆:
a)将N个元素依次存入数组里,满足完全二叉树的顺序 储性质
b)调整各个结点的位置,以满足最大堆的有序性
通常采取第二种方式建堆
算法如下:
1)首先把数据输入到堆中
2)从倒数第一个有子节点的父节点开始调整,把这个父节点为根节点的子树调整为堆,直至到根节点

//把data[n]为根的子堆调整为最大堆
void Predown(int n){
    //保存下标为n的元素
    int x = this->data[n];
    int parent,child = 1;
    //用最后一个元素来替代第一个最大值 
    for(parent = n ; parent*2 <= this->size ; parent = child){
        //child指向当前结点的左孩子 
        child = parent*2;
        //左孩子的下标不等于最大堆容量,则说明有右孩子
        //右孩子的键值如果父节点,那么child指向右孩子,否则仍指向左孩子 
        if(child != this->size && this->data[child] < this->data[child+1]){
            child++;//选择左右孩子中最大值 
        }
        if(x >= this->data[child]){//找到了合适的位置 
            break;
        }else{//把孩子上移
            this->data[parent] = this->data[child];
        }
    }
    this->data[parent] = x; 
}

//最大堆的建立函数 
void Create(int* data ,int n){
    //把数据导入最大堆 
    for(int i = 0 ; i < n ; i++){
        this->data[++size] = data[i];
    }
    //从最后一个结点的父节点开始逐步之为根结点的子堆调整为最大堆 
    for(int i = this->size/2 ; i >= 1 ; i--){
        this->Predown(i); 
    }
} 

具体例子

全部代码如下:

#include <iostream>
using namespace std;

//作为最大堆的第0个元素,以之为哨兵 
const int MaxData = 1000000;

class MaxHeap{
    private:
        int* data;          //存储数据的数组 
        int size;           //当前规模 
        int capacity;       //最大容量
    public:
        //最大堆的构造函数 
        MaxHeap(int MaxSize){
            this->data = new int[MaxSize];
            this->size = 0;
            this->capacity = MaxSize;
            this->data[0] = MaxData;
        }

        //把data[n]为根的子堆调整为最大堆
        void Predown(int n){
            //保存下标为n的元素
            int x = this->data[n];
            int parent,child;
            //用最后一个元素来替代第一个最大值 
            for(parent = n ; parent*2 <= this->size ; parent = child){
                //child指向当前结点的左孩子 
                child = parent*2;
                //左孩子的下标不等于最大堆容量,则说明有右孩子
                //右孩子的键值如果父节点,那么child指向右孩子,否则仍指向左孩子 
                if((child != this->size) && this->data[child] < this->data[child+1]){
                    child++;//选择左右孩子中最大值 
                }
                if(x >= this->data[child]){//找到了合适的位置 
                    break;
                }else{//把孩子上移
                    this->data[parent] = this->data[child];
                }
            }
            this->data[parent] = x; 
        }

        //最大堆的建立函数 
        void Create(int* data ,int n){
            //把数据导入最大堆 
            for(int i = 0 ; i < n ; i++){
                this->data[++size] = data[i];
            }
            //从最后一个结点的父节点开始逐步之为根结点的子堆调整为最大堆 
            for(int i = this->size/2 ; i > 0 ; i--){
                this->Predown(i); 
            }
        } 

        //判断最大堆是否已满
        bool IsFull(){
            return this->size == this->capacity;
        } 

        bool IsEmpty(){
            return this->size == 0;
        }

        //最大堆的插入操作 
        bool Insert(int num){
            //最大堆已满则无法插入 
            if(this->IsFull()){
                return false;
            }
            //保存最后一个元素的位置
            int i = ++size; 
            //从最后一个元素的父节点开始进行过滤
            //如果父节点小于num,那么把父节点下移 
            //data[0]控制哨兵元素,它不小于最大堆中最大元素,控制循环结束 
            for(; this->data[i/2] < num ; i /= 2){
                this->data[i] = this->data[i/2];
            }
            this->data[i] = num;
            return true;
        }

        //最大堆的删除最大值操作
        int DeleteMax(){
            //最大堆是空时 
            if(this->IsEmpty()){
                return MaxData;
            } 
            int max = this->data[1];
            this->data[1] = this->data[size];
            //最大堆规模减一 
            this->size--;
            //然后把第一个元素为根结点进行调整为最大堆 
            this->Predown(1);
            return max; 
        }

        //打印最大堆
        void Print(){
            for(int i = 1 ; i <= this->size ; i++){
                cout<<this->data[i]<<" ";
            }
        } 
};

int main()
{
    cout<<"请输入最大堆的最大容量:"<<endl;
    int capacity;
    cin>>capacity;
    MaxHeap maxheap(capacity); 
    cout<<"请输入初始化最大堆的元素个数:"<<endl;
    int size,*data;
    cin>>size;
    data = new int[size];
    cout<<"请初始化元素:"<<endl;
    for(int i = 0 ; i < size ; i++){
        cin>>data[i];
    }
    maxheap.Create(data,size);
    cout<<"最大堆为:"<<endl;
    maxheap.Print();
    cout<<endl;

    //在最大堆中插入元素
    cout<<"请输入要插入的元素:"<<endl;
    int num;
    cin>>num;
    maxheap.Insert(num);
    cout<<"最大堆为:"<<endl;
    maxheap.Print(); 
    cout<<endl;

    cout<<"进行删除操作"<<endl;
    int x = maxheap.DeleteMax();
    cout<<"删除元素为:"<<x<<endl;
    cout<<"最大堆为:"<<endl;
    maxheap.Print();

    return 0;
 } 

截图如下:
这里写图片描述

2
0
查看评论

堆的C++实现

堆 性质: 1.堆是一颗完全二叉树,用数组实现。    2.堆中存储数据的数据是局部有序的。 最大堆:1.任意一个结点存储的值都大于或等于其任意一个子结点中存储的值。      2.根结点存储着该树所有结点中的最大值。 最小堆:1.任意一个结点存储的值都小于或等于其惹你一个子结点存储的值。  ...
  • Alfa_
  • Alfa_
  • 2016-12-22 21:00
  • 814

Java堆和native堆

为什么引进非Java堆? 1 Java如果和外界通讯,把Java 堆中的内容传输到外界,则需要把Java堆复制到非Java堆,如果使用native堆,则避免了内容在Java堆和非Java堆之间的copy.
  • u012333307
  • u012333307
  • 2015-10-03 15:11
  • 1460

数据结构::堆及堆的应用~

【堆】: 1.概念:   堆是一种特殊的树形结构,堆的把每一个节点都有一个值,我们通常所说的堆这种数据结构,指的就是二叉堆。     其实它可以被看做一个完全二叉树。   它的每个节点的子树又可以被看做是堆。 2.分类:    堆可以分...
  • lalu58
  • lalu58
  • 2016-12-31 13:47
  • 940

5. 堆,建堆算法,堆排序

堆 堆实际上是一棵完全二叉树,其任何一非叶节点满足性质: Key[i]=Key[2i+1]&&key>=key[2i+2] 即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。 堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&...
  • xie294777315
  • xie294777315
  • 2014-08-07 20:12
  • 1448

C++ STL中堆的使用

<br /><br />#include<algorithm><br />#include <functional><br />using namespace std;<br /> <br />...
  • shiweisi_hqu
  • shiweisi_hqu
  • 2010-12-01 15:44
  • 3500

【c++】数据结构———堆

堆是一种特殊的数据结构,它通常是一个可以被看做一棵树的数组对象。 What?那它到底是一棵树,还是一个数组呢?答案是数组。这个数组以二叉树的形式来维护。注意:这个二叉树必须是完全二叉树 堆结构的二叉树存储有两种:        最大堆:每个父亲结点的值...
  • LLZK_
  • LLZK_
  • 2016-10-20 09:57
  • 1891

堆和二叉树的区别

以小根堆为例,堆的特点是双亲结点的关键字必然小于等于孩子结点的关键字,而两个孩子结点的关键字没有次序规定,而二叉排序数中,每个双亲结点的关键字均大于左子树结点的关键字,均小于右子树j结点的关键字,也就是说,每个双亲结点的左右孩子的关键字有次序关系,这样,当对两种树执行中序遍历后,二叉树会得到一个有序...
  • wang19890326
  • wang19890326
  • 2013-09-08 18:16
  • 4153

jvm中堆和非堆的划分

哪位大神能给我讲解一个问题,我们使用参数-Xms -Xmx设置堆内存的最小值和最大值,-XX:PermSize -XX:MaxPermSize设置非堆内存的最小值和最大值,这里的非堆内存包括Permanent Space(永久存储区)。但是为什么又说jvm中的堆内存分为三部分:Permanent...
  • gtt875
  • gtt875
  • 2017-04-21 11:47
  • 858

数据结构-堆(heap)

堆(heap)也被称为优先队列(priority queue)。队列中允许的操作是先进先出(FIFO),在队尾插入元素,在队头取出元素。而堆也是一样,在堆底插入元素,在堆顶取出元素,但是堆中元素的排列不是按照到来的先后顺序,而是按照一定的优先顺序排列的。这个优先顺序可以是元素的大小或者其他规则。
  • juanqinyang
  • juanqinyang
  • 2016-05-15 20:00
  • 2115

java 浅堆和深堆

浅堆和深堆 浅堆(Shallow Heap)和深堆(Retained Heap)是两个非常重要的概念,它们分别表示一个对象结构所占用的内存大小和一个对象被GC回收后,可以真实释放的内存大小。 浅堆(Shallow Heap)是指一个对象所消耗的内存。在32位系统中,一个对象引用会占据4个...
  • luohai859
  • luohai859
  • 2016-02-29 16:47
  • 1182
    个人资料
    • 访问:155563次
    • 积分:4927
    • 等级:
    • 排名:第6843名
    • 原创:329篇
    • 转载:0篇
    • 译文:0篇
    • 评论:80条
    博客专栏
    最新评论