#define LEFT(a) ((a)<<1)
#define RIGHT(a) (((a)<<1)+1)
#define PARENT(a) ((a)>>1)
using std::string;

template <typename T>
struct Heap
{
  unsigned int heap_size;//有效数据个数
  unsigned int length;//最大容量
  T *array;
  Heap(unsigned int length):heap_size(0),length(length),array(new T[length+1]){}//这里多申请了一个空间,因为第0个位置不使用
  Heap &justAppend(T elem)
  {
    if(heap_size==length)
      throw "too many elem";
    array[++heap_size]=elem;
    return *this;
  }

//用于构建最大堆
  void MAX_HEAPIFY(unsigned int i)
  {
    unsigned int left=LEFT(i);
    unsigned int right=RIGHT(i);
    unsigned int largest=i;
    if(left<=heap_size && array[left]>array[largest])
      largest=left;
    if(right<=heap_size && array[right]>array[largest])
      largest=right;
    if(largest!=i)
    {
      T tmp=array[i];
      array[i]=array[largest];
      array[largest]=tmp;
      MAX_HEAPIFY(largest);
    }
  }
//用于构建最小堆
  void MIN_HEAPIFY(unsigned int i)
  {
    unsigned int left=LEFT(i);
    unsigned int right=RIGHT(i);
    unsigned int min=i;
    if(left<=heap_size && array[left]<array[min])
      min=left;
    if(right<=heap_size && array[right]<array[min])
      min=right;
    if(min!=i)
    {
      T tmp=array[i];
      array[i]=array[min];
      array[min]=tmp;
      MIN_HEAPIFY(min);
    }
  }

  void MAX_ADD(T elem)
  {
    //向大根堆中添加一个元素,这里假设数组已经是一个大根堆了
    if(heap_size==length)
    {
      printf("to many elem\n");
      return;
    }
    ++heap_size;//先在数组的最后面申请一个位置
    unsigned int i;
    for(i=heap_size;array[PARENT(i)]<elem;i=PARENT(i))
    array[i]=array[PARENT(i)];//依次向上查找父节点,直到找到那个比elem小的父节点,如果没有这样的点,那么最后一个位置就是为elem准备的
    array[i]=elem;
    return;
  }

  void MAX_DELETE_ROOT()
  {
    //删除大根堆的根节点
    if(heap_size==0)
    {
      printf("no elem\n");
      return;
    }
    --heap_size;
    if(heap_size==0)
    return;//不需要调整堆
    array[1]=array[heap_size+1];//将原来的堆中的最后一个elem放到堆的根,保证原来根节点的左右子树还是大根堆
    MAX_HEAPIFY(1);//从堆的根开始调整,时间复杂度和堆的高度正相关,堆的高度为log2(n),因此时间复杂度为log2(n)
  }

  void MIN_DELETE_ROOT()
  {
    if(heap_size==0)
    {
      printf("no elem\n");
      return;
    }
    --heap_size;
    if(heap_size==0)
    return;//不需要调整堆
    array[1]=array[heap_size+1];//将原来的堆中的最后一个elem放到堆的根,保证原来根节点的左右子树还是大根堆
    MIN_HEAPIFY(1);
  }

  void MAX_SORT()
  {
    //在此堆已经是大根堆的基础上排序
    while(heap_size!=0)
    {
      printf("%d ",array[1]);//每次输出大根堆的根
      MAX_DELETE_ROOT();//log2(n)的复杂度
    }
    printf("\n");
    //总的时间复杂度为nlog2(n);因为删除了n个点,进行了n次调整,每次调整的时间复杂度是log2(n)
  }

  void MIN_SORT()
  {
    //在此堆已经是小根堆的基础上排序
    while(heap_size!=0)
    {
      printf("%d ",array[1]);
      MIN_DELETE_ROOT();
    }
    printf("\n");
  }
  void MIN_ADD(T elem)
  {
    //向小根堆中添加一个元素,这里假设此数组已经是一个小根堆了
    if(heap_size==length)
    {
      printf("to many elem\n");
      return;
    }
    ++heap_size;//先在数组的最后面申请一个位置
    unsigned int i;
    for(i=heap_size;array[PARENT(i)]>elem;i=PARENT(i))
    array[i]=array[PARENT(i)];//依次向上查找父节点,直到找到那个比elem大的父节点,如果没有这样的点,那么最后一个位置就是为elem准备的
    array[i]=elem;
    return;
  }

  void BUILD_MAX_HEAP()
  {
    //对非叶子节点从最底层向最高层调用MAX_HEAPIFY
    //从[heap_size/2+1,heap_size]都是该堆的叶子节点,所以非叶子节点是从[1,heap_size/2]
    for(unsigned int i=heap_size/2;i>=1;--i)
    MAX_HEAPIFY(i);
  }

  void BUILD_MIN_HEAP()
  {
    for(unsigned int i=heap_size/2;i>=1;--i)
    MIN_HEAPIFY(i);
  }

  void print()
  {
    for(unsigned int i=1;i<=heap_size;++i)
    std::cout<<array[i]<<"\t";
    std::cout<<std::endl;
  }
  ~Heap()
  {
    if(!array)
    {
      delete [] array;
      array=0;
    }
  }
};

int main()
{
  Heap<int> heap(100);
  heap.justAppend(4).justAppend(1).justAppend(3).justAppend(2).justAppend(16).
  justAppend(9).justAppend(10).justAppend(14).justAppend(8).justAppend(7);
  heap.print();
  heap.BUILD_MAX_HEAP();
  heap.MAX_SORT();
  heap.justAppend(4).justAppend(1).justAppend(3).justAppend(2).justAppend(16).
  justAppend(9).justAppend(10).justAppend(14).justAppend(8).justAppend(7);
  heap.BUILD_MIN_HEAP();
  heap.MIN_SORT();
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值