(第七步) STL: heap算法实现

该算法内容放在Algorithm.h中

heap并不归属于STL容器组件,用于辅助实现priority queue。priority queue允许用户以任何次序将任何元素推入容器内,但取出时一定是从优先权最高(也就是数值最高)的元素开始取。binary max heap正是具有这样的特性,适合作为priority queue的底层机制。

选择方法的分析:

  • list:虽然插入、删除可以常数时间,但是找极值需要遍历

  • 红黑树:插入、找极值都是​,但是实现较为复杂

  • binary heap:其实是一种完全二叉树,介于上面两者之间,就可以使用array来储存数据,但是heap需要动态改变内存,所以最优为vector容器实现max-heap或者min-heap

四个heap相关算法:

  • make_heap ( ) :将现有数据转化为heap

  • push_heap ( ) :将元素插入vector的end()位置,然后进行上溯up算法

  • pop_heap ( ):默认弹出最大值,然后取最下层最右边叶子结点(数组元素最后一位)进行下溯down算法,注意这里弹出是放到heap的结尾的,并不会删除

  • sort_heap ( ):根据pop_heap算法进行从小到大进行排序

额外增加了判断是否是heap的函数is_heap()

辅助算法up、down

up上溯算法

 //********* [Algorithm Complexity: O(N)] ****************
 template<class RandomAccessIterator, class Compare>
     static void up(RandomAccessIterator first, RandomAccessIterator last, 
                    RandomAccessIterator head, Compare comp)
 {//1.[first, last], 2.headr points the header of the heap
     if (first != last)
     {
         if (first != last)
         {
             int index = last - head;                // 尾部,刚刚插入元素的索引
             auto parentIndex = (index - 1) / 2;     // 父节点位置
             for (auto cur = last; parentIndex >= 0 && cur != head; parentIndex = (index - 1) / 2)
             {
                 auto parent = head + parentIndex;   // get parent index position
                 if (comp(*parent, *cur))            // 选择排序方式
                     mySTL::swap(*parent, *cur);
                 cur = parent;                       // 更新位置
                 index = cur - head;                 // 更新索引
             }
         }
     }
 }

down下溯算法

//********* [Algorithm Complexity: O(N)] ****************
 template<class RandomAccessIterator, class Compare>
     //heap下降算法
     static void down(RandomAccessIterator first, RandomAccessIterator last, 
                      RandomAccessIterator head, Compare comp)
 {//1.[first, last], 2.headr points the header of the heap
     if (first != last)
     {
         // 此时根节点已经下沉了
         auto index = first - head;                              // 返回除根节点外,最后一个元素索引
         auto leftChildIndex = index * 2 + 1;                    // 左子树节点
         for (auto cur = first; leftChildIndex < (last - head + 1) && cur < last; leftChildIndex = index * 2 + 1)
         {
             auto child = head + leftChildIndex;                 // get the left child
             if ((child + 1) <= last && *(child + 1) > *child)   // 右子树 > 左子树时切换
                 child = child + 1;
             if (comp(*cur, *child))                             // 排序方式
                 mySTL::swap(*cur, *child);
             cur = child;                                        // 更新当前节点
             index = cur - head;                                 // 更新左子树节点
         }
     }
 }

make_heap

 template <class RandomAccessIterator, class Compare>
     void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp){
     const auto len = last - first;  // 确定元素个数
     // cur 为父节点 len - 2其实为len - 1 - 1,前面-1为back元素, 后面-1为计算父节点
     for (auto cur = first + (len - 2) / 2 ; cur >= first; --cur)    
     {
         mySTL::down(cur, last - 1, first, comp);    // cur数值按条件的下沉
         if (cur == first) return;                   // 遍历出叶子节点以外的节点
     }
 }
 ​
 template <class RandomAccessIterator>
     void make_heap(RandomAccessIterator first, RandomAccessIterator last){
     mySTL::make_heap(first, last,
                      typename mySTL::less<mySTL::iterator_traits<RandomAccessIterator>::value_type>());
 }

push_heap

 

 //********* [push_heap] ***************
 //********* [Algorithm Complexity: O(lgN)] ****************
 template <class RandomAccessIterator, class Compare>
     void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
 {
     // 插入为begin()~end(), last - 1为刚刚插入的元素
     mySTL::up(first, last - 1, first, comp);
 }
 ​
 template <class RandomAccessIterator>
     void push_heap(RandomAccessIterator first, RandomAccessIterator last)
 {
     mySTL::push_heap(first, last,
                      mySTL::less<typename mySTL::iterator_traits<RandomAccessIterator>::value_type>());
 }
 ​

pop_heap

 

 

//********* [pop_heap] ***************
 //********* [Algorithm Complexity: O(lgN)] ****************
 template <class RandomAccessIterator, class Compare>
     void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
 {
     // 完成首尾互换,根节点放到最后的叶子节点中,然后进行下沉操作
     mySTL::swap(*first, *(last - 1));
     if (last - first >= 2)
         mySTL::down(first, last - 2, first, comp);
 }
 ​
 template <class RandomAccessIterator>
     void pop_heap(RandomAccessIterator first, RandomAccessIterator last)
 {
     mySTL::pop_heap(first, last, 
                     mySTL::less<typename mySTL::iterator_traits<RandomAccessIterator>::value_type>());
 }

sort_heap

 

 

 //********* [sort_heap] ***************
 //********* [Algorithm Complexity: O(N)] ****************
 template <class RandomAccessIterator, class Compare>
     void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
 {
     // 利用pop_heap的特性,每次都把最大值放最后
     // 把end()进行前移1位,但不删除原先的end(),从而实现从小到大
     for (auto cur = last; cur != first; --cur)
     {
         mySTL::pop_heap(first, cur, comp);
     }
 }
     
 template <class RandomAccessIterator>
     void sort_heap(RandomAccessIterator first, RandomAccessIterator last)
 {
     return mySTL::sort_heap(first, last,
                             mySTL::less<typename mySTL::iterator_traits<RandomAccessIterator>::value_type>());
 }

is_heap

 //********* [is_heap] ***************
 //********* [Algorithm Complexity: O(N)] ****************
 template <class RandomAccessIterator, class Compare>
     bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp){
     const auto len = last - first;
     auto index = (len - 2) / 2;
     for (auto cur = first + index; cur >= first; --cur, --index){
         if (*(first + (index * 2 + 1)) > *cur ||//left child > cur
             ((first + (index * 2 + 2)) <= last && *(first + (index * 2 + 2)) > *cur))//right child > cur
             return false;
         if (cur == first)
             break;
     }
     return true;
 }
 ​
 template <class RandomAccessIterator>
     bool is_heap(RandomAccessIterator first, RandomAccessIterator last){
     return mySTL::is_heap(first, last,
                           mySTL::less<typename mySTL::iterator_traits<RandomAccessIterator>::value_type>());
 }

stl_heap_test.h

 #ifndef _HEAP_TEST_H_
 #define _HEAP_TEST_H_
 ​
 #include "../Includes/Algorithm.h"
 #include "../p2_STL_Source/stl_vector.h"
 ​
 ​
 namespace mySTL 
 {
     namespace heapTest
     {
         template<class T>
         using myVec = mySTL::vector<T>;
 ​
         void myPrint(mySTL::vector<int>& v);
         void test01();
 ​
     }
 }
 ​
 #endif // !_STL_HEAP_TEST_H_

stl_heap_test.cpp

 
#include "stl_heap_test.h"
 ​
 using namespace std;
 ​
 namespace mySTL
 {
     namespace heapTest
     {
         void myPrint(mySTL::vector<int>& v)
         {
             for (int i = 0; i < v.size(); i++)
             {
                 cout << v[i] << " ";
             }
             cout << endl;
         }
 ​
         void test01()
         {
             int a[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };
             myVec<int> v1(a, a + 9);
             cout << "-------------raw data----------" << endl;
             myPrint(v1);
 ​
             cout << "-------------make_heap test----------" << endl;
             mySTL::make_heap(v1.begin(), v1.end());
             myPrint(v1);
 ​
             cout << "-------------is_heap test----------" << endl;
             cout << "is heap: " << boolalpha << (mySTL::is_heap(v1.begin(), v1.end())) << endl;
 ​
             cout << "-------------push_heap test----------" << endl;
             v1.push_back(7);
             mySTL::push_heap(v1.begin(), v1.end());
             myPrint(v1);
 ​
             cout << "-------------pop_heap test----------" << endl;
             mySTL::pop_heap(v1.begin(), v1.end());
             cout << "remove data: " << v1.back() << endl;
             v1.pop_back();
             myPrint(v1);
 ​
             cout << "-------------sort_heap test----------" << endl;
             mySTL::sort_heap(v1.begin(), v1.end());
             myPrint(v1);
 ​
 ​
         }
 ​
     }
 }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值