1.堆

    堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构。它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序优先队列等。

2. 堆的基本操作

    堆是一棵完全二叉树,高度为O(lg n),其基本操作至多与树的高度成正比。

  Parent(t)  t/2 表示父节点

      Right(t)  t*2 左孩子

      Left(t)  t*2+1 右孩子

      HeapSize 堆的长度

详解参考:

http://www.cnblogs.com/Jason-Damon/archive/2012/04/18/2454649.html

http://blog.csdn.net/morewindows/article/details/6967409

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define maxn 100010
int a[maxn],n;
void heapify(int a[],int n,int t)//调整根为t的树
{
    int left=t<<1;
    int right=t<<1|1;
    int max=t;
    if(left<=n)max=a[left]>a[max]?left:max;
    if(right<=n)max=a[right]>a[max]?right:max;
    if(max!=t)//当前根不是最大值
    {
        swap(a[t],a[max]);
        //交换后子树可能会不满足最大堆的性质
        heapify(a,n,max);
    }
}
void heapsort(int a[],int n)
{
    //构建一个最大堆
    for(int i=n/2;i>=1;i--)heapify(a,n,i);
    for(int i=n;i>1;i--)
    {
        //将最大值放在末尾
        swap(a[i],a[1]);
        //交换后堆的容量减一,对堆重新调整(第一个节点的左右子树都是最大堆,所以只要对第一个节点进行调整)
        heapify(a,i-1,1);
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        heapsort(a,n);
        for(int i=1;i<=n;i++)printf("%d\n",a[i]);
    }
    return 0;
} 

 

tip:要得到从小到大的序列则构建最大堆,每次把最大值放在堆的末尾,要得到从大到小的序列则构建最小堆,每次把最小值放在末尾

 

 模板化的代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define Parent(t) t/2
#define Right(t) t<<1
#define Left(t) t<<1|1
int HeapSize;
//数组A的数据是从1-n的
/*
保持堆的性质 Heapify(A,n,t)
该操作主要用于维持堆的基本性质。假定以RIGHT(t)和LEFT(t)为根的子树都已经是堆,然后调整以t为根的子树,使之成为堆。
*/
class Rough
{
public:
    int x,y;
    double ratio;
    Rough(){}
    Rough(int _x,int _y,double _ratio)
    {
        x=_x;
        y=_y;
        ratio=_ratio;
    }
     bool operator >(const Rough& t)
    {
        return ratio-t.ratio>0.01;
    }

    bool operator <(const Rough& t)
    {
        return ratio<t.ratio;
    }
    bool operator ==(const Rough& t)
    {
        return ratio==t.ratio;
    }
};

template<class T> void Heapify(T A[],int n,int t)
{
    int left=Left(t);
    int right=Right(t);
    int max=t;
    if(left<=n)max=A[left]<A[max]?left:max;
    if(right<=n)max=A[right]<A[max]?right:max;
    if(max!=t)
    {
        T tmp=A[max];
        A[max]=A[t];
        A[t]=tmp;
        Heapify(A,n,max);
    }
}
/*
建堆 BuildHeap(A,n)
操作主要是将数组A转化成一个大顶堆。思想是,先找到堆的最后一个非叶子节点(即为第n/2个节点),然后从该节点开始,从后往前逐个调整每个子树,使之称为堆,最终整个数组便是一个堆。子数组A[(n/2)+1..n]中的元素都是树中的叶子,因此都可以看作是只含有一个元素的堆。
*/
template<class T> void BuildHeap(T A[],int n)
{
    for(int i=n/2;i>=1;i--)
        Heapify(A,n,i);
}
/*
堆排序算法
先用BuildHeapo将数组A[1..n]构造成一个最大堆。因为数组中最大元素在根A[1],则可以通过把它与A[n]交换来达到最终正确的位置。
*/
template<class T> void HeapSort(T A[],int n)
{
    BuildHeap(A,n);
    for(int i=n;i>1;i--)
    {
        T tmp=A[1];
        A[1]=A[i];
        A[i]=tmp;
        Heapify(A,i-1,1);//交换后堆的长度减1,对堆重新调整
    }
}
int main()
{
    //int a[6]={0,3,5,2,7,1};
    Rough A[6];
    A[1]=Rough(26,35,0.2);
    A[2]=Rough(522,1,5.5);
    A[3]=Rough(2132,2513,23);
    A[4]=Rough(1,2,3232);
    A[5]=Rough(-122,232,33);
   // BuildHeap(a,5);
    HeapSort(A,5);
    for(int i=1;i<=5;i++)printf("%d %d %lf\n",A[i].x,A[i].y,A[i].ratio);
    return 0;
}

 

STL中优先队列的用法:

#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
struct node
{
    int x,y;
    friend bool operator < (node a,node b)
    {
        return a.x<b.x;
    }
};
//数据越小优先级越大
priority_queue<int,vector<int>,greater<int> >q;
//数据越大优先级越大
priority_queue<int,vector<int>,less<int> >p;

//默认是less

int main()
{
    int a[5]={6,9,3,5,7};
    for(int i=0;i<5;i++)q.push(a[i]);
    while(!q.empty())
    {
        printf("%d\n",q.top());
        q.pop();
    }

    for(int i=0;i<5;i++)p.push(a[i]);
    while(!p.empty())
    {
        printf("%d\n",p.top());
        p.pop();
    }

    return 0;
}

 

posted on 2014-12-03 09:02  kylehz  阅读(188)  评论(0编辑  收藏  举报