算法学习之路|数据结构--堆

堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki <= k2i,ki = k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
ps:以上定义来自百度百科
1.保持堆的性质
该操作主要用于维持堆的基本性质。假定以节点t的左孩子节点和节点t的右孩子节点为根的子树都已经是堆,然后调整以t为根的子树,使之成为堆。

void Heapify(int A[],int i,int n)//A[]为堆的数组,i表示i节点,n为A中元素个数
{
    int l=2*i;
    int r=2*i+1;
    int largest=i;
    if(l<=n) largest=A[l]>A[i]?l:i;
    if(r<=n) largest=A[r]>A[largest]?r:largest;  //从i,2*i,2*i+1中找出最大的一个
        if(largest!=i)    //i不是最大的
    {
        swap(A[i],A[largest]);//交换
        Heapify(A,largest,n);  //交换后,子树有可能违反最大堆性质
    }
}

2.建堆
操作主要是将数组A转化成一个大顶堆。思想是,先找到堆的最后一个非叶子节点(即为第n/2个节点),然后从该节点开始,从后往前逐个调整每个子树,使之称为堆,最终整个数组便是一个堆。

void BuildHeap(int A[],int n)  
 {    
            int i;
            for(i = n/2; i>=1; i--)    
               Heapify(A, i); 
  } 

3.堆排序
先用BuildHeapo将数组A[1..n]构造成一个最大堆。再将最大的元素A[1]和A[n]交换,再数组A[1..n-1]构造成一个最大堆,直到排序完成

void HeapSort(int A[],int n)
{
    BuildHeap(A,n);
    for(i=n;i>1; i--)
    {
        swap(A[1],A[i]);
        Heapify(A,1,n-1);  //交换后新的根元素可能委培了最大堆的性质
    }
}

4.优先队列
优先队列是一种用来维护由一组元素构成的集合S的数据机构。相信大家对它都有所了解。虽然说c++里面有了priority_queue,但我们还是要了解它的一些基本构成及实现的代码。
GETMAX:
该操作主要是获取堆中最大的元素,同时保持堆的基本性质。堆的最大元素即为第一个元素,将其保存下来,同时将最后一个元素放到A[1]位置,之后从上往下调整A,使之成为一个堆

void GetMaximum(int A[],int n) {
     int max = A[1];
     A[1] = A[n];
     Heapify(A, 1, n-1);
     return max;
   } 

INSERT:

向堆中添加一个元素t,同时保持堆的性质。算法思想是,将t放到A的最后,然后从该元素开始,自下向上调整,直至A成为一个大顶堆。

void Insert(int A[], int i,int n)   {  //i为插入的值
    n++;     
    int p = n;
    while(p >1 && A[floor(p/2)] < i) //floor()向下取整
    {
       A[p] = A[floor(p/2)];
       p =floor(p/2);
     }
      A[p]=i;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值