heap

heap

默认追加元素push_heap()

在范围[first, last)的最后一个位置存放着新添加的元素,调整该元素的位置,使[first, last)满足堆的要求

默认大顶堆

template <class RandomAccessIterator>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) {//注意新元素已经被放置在最尾部
  __push_heap_aux(first, last, distance_type(first), value_type(first));
}
template <class RandomAccessIterator, class Distance, class T>
inline void __push_heap_aux(RandomAccessIterator first,
                            RandomAccessIterator last, Distance*, T*) {
  __push_heap(first, Distance((last - first) - 1)/*新插入节点下标*/, Distance(0), 
              T(*(last - 1))/*新插入节点值*/);
}

以first+holeIndex作为需要调整的初始位置,value作为需要调整的值,不断向上调整,直到满足堆要求。

//以first作为容器开始,以first+topIndex作为堆开始,以first+holeIndex作为需要调整的位置。value为需要调整的值
template <class RandomAccessIterator, class Distance, class T>
void __push_heap(RandomAccessIterator first, Distance holeIndex/*堆顶下标,相对与first为0*/,
                 Distance topIndex/*插入位置下标,也是相对于first的下标*/, T value/*插入元素的值*/) {
  Distance parent = (holeIndex - 1) / 2;//获取插入节点父节点下标(i-1)/2
  while (holeIndex > topIndex && *(first + parent) < value) {//判断是否上溯:当前节点下标大于顶点下标并且父节点
      														 //值小于插入节点的值。
    *(first + holeIndex) = *(first + parent);//将父节点数据复制到子节点当中
    holeIndex = parent;//修改需要调整的下标位置
    parent = (holeIndex - 1) / 2;//获取父节点
  }    
  *(first + holeIndex) = value;//最后将该值插入合适位置
}

可选择方式追加元素push_heap()

template <class RandomAccessIterator, class Compare>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last,
                      Compare comp/*可以指定比较方式*/) {
  __push_heap_aux(first, last, comp, distance_type(first), value_type(first));
}
template <class RandomAccessIterator, class Compare, class Distance, class T>
inline void __push_heap_aux(RandomAccessIterator first,
                            RandomAccessIterator last, Compare comp,
                            Distance*, T*) {
  __push_heap(first, Distance((last - first) - 1), Distance(0), 
              T(*(last - 1)), comp);
}
template <class RandomAccessIterator, class Distance, class T, class Compare>
void __push_heap(RandomAccessIterator first, Distance holeIndex,
                 Distance topIndex, T value, Compare comp) {
  Distance parent = (holeIndex - 1) / 2;
  while (holeIndex > topIndex && comp(*(first + parent), value)) {//如果comp实现为:
      															  //1)a<b true则为大顶堆
      															  //2)a>b true则为小顶堆
    *(first + holeIndex) = *(first + parent);
    holeIndex = parent;
    parent = (holeIndex - 1) / 2;
  }
  *(first + holeIndex) = value;
}

默认取出堆顶元素pop_heap()

当前堆范围为[first, last),提取堆顶元素放在last-1位置,然后对[first, last-1)进行调整。

由于提取了极值,所以堆顶为空,因此不断从左右子树中提取较大值放入父节点中,最后结果为某个叶子节点为空,因此被极值占用的节点中的元素数据应该放在此处,但是当插入此节点之后,还需要调整。

template <class RandomAccessIterator>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) {
  __pop_heap_aux(first, last, value_type(first));
}
template <class RandomAccessIterator, class T>
inline void __pop_heap_aux(RandomAccessIterator first,
                           RandomAccessIterator last, T*) {
  __pop_heap(first, last - 1, last - 1, T(*(last - 1)), distance_type(first));//提取的值被放在last-1位置,
    																		  //重新调整first,last-1
}
template <class RandomAccessIterator, class T, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,//新范围
                       RandomAccessIterator result, T value/*需要调整的值*/, Distance*) {//结果位置,末尾值(待调整值)
  *result = *first;//将极值放在末尾
  __adjust_heap(first, Distance(0), Distance(last - first), value);
}
//取出极值之后的调整+插入末尾值之后的调整
template <class RandomAccessIterator, class Distance, class T>
void __adjust_heap(RandomAccessIterator first/*堆顶位置*/, Distance holeIndex,/*待调整位置*/
                   Distance len/*堆中元素个数*/, T value/*被占用的元素的值*/) {
  Distance topIndex = holeIndex;
  Distance secondChild = 2 * holeIndex + 2;
  //由于提取出了极值,导致顶部为空,则需要比较左右子树,将最大的值提取到父节点位置
  while (secondChild < len) {//第二个节点位置没有超出范围
    if (*(first + secondChild) < *(first + (secondChild - 1)))//第二个节点值小于第一个节点的值
      secondChild--;
    *(first + holeIndex) = *(first + secondChild);//将子节点中较大的值放入父节点
    holeIndex = secondChild;//重新设置需要调整的子节点
    secondChild = 2 * (secondChild + 1);
  }
  if (secondChild == len) {//最后空出的位置正好是父节点仅有的左子树(最后一个叶子节点,该叶子节点为父节点的左子树)
    *(first + holeIndex) = *(first + (secondChild - 1));
    holeIndex = secondChild - 1;
  }
  __push_heap(first, holeIndex, topIndex, value);//调整空出来的位置
}

可选择方式取出元素

template <class RandomAccessIterator, class Compare>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last,
                     Compare comp) {
    __pop_heap_aux(first, last, value_type(first), comp);
}
template <class RandomAccessIterator, class T, class Compare>
inline void __pop_heap_aux(RandomAccessIterator first,
                           RandomAccessIterator last, T*, Compare comp) {
  __pop_heap(first, last - 1, last - 1, T(*(last - 1)), comp,
             distance_type(first));
}
template <class RandomAccessIterator, class T, class Compare, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,
                       RandomAccessIterator result, T value, Compare comp,
                       Distance*) {
  *result = *first;
  __adjust_heap(first, Distance(0), Distance(last - first), value, comp);
}
template <class RandomAccessIterator, class Distance, class T, class Compare>
void __adjust_heap(RandomAccessIterator first, Distance holeIndex,
                   Distance len, T value, Compare comp) {
  Distance topIndex = holeIndex;
  Distance secondChild = 2 * holeIndex + 2;
  while (secondChild < len) {
    if (comp(*(first + secondChild), *(first + (secondChild - 1))))//如果a<b则为大顶堆
      secondChild--;
    *(first + holeIndex) = *(first + secondChild);
    holeIndex = secondChild;
    secondChild = 2 * (secondChild + 1);
  }
  if (secondChild == len) {
    *(first + holeIndex) = *(first + (secondChild - 1));
    holeIndex = secondChild - 1;
  }
  __push_heap(first, holeIndex, topIndex, value, comp);
}

构造默认堆make_heap()

从最后一个非叶子节点开始到堆顶元素为止,先保存当前节点的值,然后将该节点作为空,不断从子节点中抽取最大值填充,直到叶子节点,然后调整向上调整该节点的位置。

template <class RandomAccessIterator>
inline void make_heap(RandomAccessIterator first, RandomAccessIterator last) {//可以看到必须为随机迭代器
  __make_heap(first, last, value_type(first), distance_type(first));//之后的两个参数为传递元素类型和距离类型
    																//之所以为指针是为了避免分配内存,因为不需要变量,只需要传递类型
}
template <class RandomAccessIterator, class T, class Distance>
void __make_heap(RandomAccessIterator first, RandomAccessIterator last, T*,
                 Distance*) {
  if (last - first < 2) return;//如果小于2个元素,则不需构建堆
  Distance len = last - first;
  Distance parent = (len - 2)/2;//计算最后一个非叶子节点
    
  while (true) {
    __adjust_heap(first, parent, len, T(*(first + parent)));//以parent为空的调整+插入原始parent中值的调整
    if (parent == 0) return;//直到调整过堆顶之后退出
    parent--;
  }
}

可选择构造堆make_heap()

template <class RandomAccessIterator, class Compare>
inline void make_heap(RandomAccessIterator first, RandomAccessIterator last,
                      Compare comp) {
  __make_heap(first, last, comp, value_type(first), distance_type(first));
}
template <class RandomAccessIterator, class Compare, class T, class Distance>
void __make_heap(RandomAccessIterator first, RandomAccessIterator last,
                 Compare comp, T*, Distance*) {
  if (last - first < 2) return;
  Distance len = last - first;
  Distance parent = (len - 2)/2;
    
  while (true) {
    __adjust_heap(first, parent, len, T(*(first + parent)), comp);
    if (parent == 0) return;
    parent--;
  }
}

堆排序

template <class RandomAccessIterator>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last) {
  while (last - first > 1) pop_heap(first, last--);	//不断从极值提取元素放在last-1位置
}
template <class RandomAccessIterator, class Compare>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last,
               Compare comp) {
  while (last - first > 1) pop_heap(first, last--, comp);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值