标准库is_heap()、is_heap_until()、make_heap()、push_heap()、pop_heap()、sort_heap()函数

使用一个东西,不明白它的道理,不高明
——侯捷老师

1. is_heap()函数

判断一个序列是否能形成一个堆

1.1 函数声明

    // defautl(1)
        template
            bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
            
    // custom(2)
        template
            bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)

1.3 源码探究

通过查看源码,发现is_heap()内部调用的是is_heap_until()函数

template
    inline bool
    is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
        _Compare __comp)
    { return std::is_heap_until(__first, __last, __comp) == __last; }

1.3 示例程式

void test_is_heap() {
        /**
        // defautl(1)
        template
            bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
            
        // custom(2)
        template
            bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
            
        */
        #include      // std::cout
        #include     // std::is_heap, std::make_heap, std::pop_heap
        #include        // std::vector
        
        std::vector foo {9,5,2,6,4,1,3,8,7};

        if (!std::is_heap(foo.begin(),foo.end()))
            std::make_heap(foo.begin(),foo.end());
        
        std::cout << "Popping out elements:";
        while (!foo.empty()) {
            std::pop_heap(foo.begin(),foo.end());   // moves largest element to back
            std::cout << ' ' << foo.back();         // prints back
            foo.pop_back();                         // pops element out of container
        }
        std::cout << '\n';  
    }

1.4 参考链接

http://www.cplusplus.com/reference/algorithm/is_heap/

2. is_heap_until()函数

返回第一个不满足堆的元素的迭代器位置

2.1 函数声明

// default(1)
    template 
        RandomAccessIterator is_heap_until (RandomAccessIterator first, RandomAccessIterator last);
// custom(2)    
    template 
        RandomAccessIterator is_heap_until (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

2.2 源码探究

is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Compare __comp) {
      // concept requirements
      __glibcxx_function_requires(_RandomAccessIteratorConcept<
        _RandomAccessIterator>)
      __glibcxx_requires_valid_range(__first, __last);

      return __first
    + std::__is_heap_until(__first, std::distance(__first, __last),
                   __gnu_cxx::__ops::__iter_comp_iter(__comp));
    }

--------------------------分界线--------------------------

template
    _Distance
    __is_heap_until(_RandomAccessIterator __first, _Distance __n,
            _Compare __comp)
    {
      _Distance __parent = 0;
      for (_Distance __child = 1; __child < __n; ++__child)
    {
      if (__comp(__first + __parent, __first + __child))
        return __child;
      if ((__child & 1) == 0)
        ++__parent;
    }
      return __n;
    }

2.3 示例程式

void test_is_heap_until() {
        /**
        // default(1)
        template 
            RandomAccessIterator is_heap_until (RandomAccessIterator first,
                                      RandomAccessIterator last);
        // custom(2)    
        template 
             RandomAccessIterator is_heap_until (RandomAccessIterator first,
                                      RandomAccessIterator last
                                      Compare comp);
        */
        
        std::vector foo {2,6,9,3,8,4,5,1,7};

        std::sort(foo.begin(),foo.end());
        std::reverse(foo.begin(),foo.end());

        auto last = std::is_heap_until (foo.begin(),foo.end());

        std::cout << "The " << (last-foo.begin()) << " first elements are a valid heap:";
        for (auto it=foo.begin(); it!=last; ++it)
        std::cout << ' ' << *it;
        std::cout << '\n';
    }

2.4 输出结果

image.png

3. make_heap()函数

构建一个堆,默认为大根堆;可以通过自定义的comp来构建小根堆。使用greater()来代替默认的less()来创建heap。

3.1 函数声明

   // default(1)
        template
            void make_heap(RandomAccessIterator first, RandomAccessIterator last)
        
  // custom(2)
        template
            void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)

3.2 源码探究

template
    inline void
    make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Compare __comp)
    {
      // concept requirements
      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
        _RandomAccessIterator>)
      __glibcxx_requires_valid_range(__first, __last);

      std::__make_heap(__first, __last,
               __gnu_cxx::__ops::__iter_comp_iter(__comp));
    }

---------------------------
template
    void
    __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
        _Compare __comp)
    {
      typedef typename iterator_traits<_RandomAccessIterator>::value_type
      _ValueType;
      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
      _DistanceType;

      if (__last - __first < 2)
    return;

      const _DistanceType __len = __last - __first;
      _DistanceType __parent = (__len - 2) / 2;
      while (true)
    {
      _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
      std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
                 __comp);
      if (__parent == 0)
        return;
      __parent--;
    }
   }

3.3 示例程式

void test_make_heap() {
        /**
        // default(1)
        template
            void make_heap(RandomAccessIterator first, RandomAccessIterator last)
        
        // custom(2)
        template
            void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
        */
        
                // 默认构建大根堆
        int myints[] = {10,20,30,5,15};
        std::vector v(myints,myints+5);

        std::make_heap (v.begin(),v.end());
        std::cout << "initial max heap   : " << v.front() << '\n';

        std::pop_heap (v.begin(),v.end()); v.pop_back();
        std::cout << "max heap after pop : " << v.front() << '\n';
    
        v.push_back(99); std::push_heap (v.begin(),v.end());
        std::cout << "max heap after push: " << v.front() << '\n';
    
        std::sort_heap (v.begin(),v.end());
    
        std::cout << "final sorted range :";
        for (unsigned i=0; i());
        for (auto &x : arr)  {
            cout << x << " ";
        }
        cout << endl;
    }

3.4 输出结果

标准库is_heap()、is_heap_until()、make_heap()、push_heap()、pop_heap()、sort_heap()函数_第1张图片
image.png

3.5 参考链接

http://www.cplusplus.com/reference/algorithm/make_heap/
https://www.cnblogs.com/deathmr/p/9015644.html

4. push_heap()函数

4.1 函数声明

// default(1)
        template 
            viod push_heap(RandomAccessIterator first, RandomAccessIterator last)
            
// custom(2)
        template
            void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
            

注意事项:使用push_heap(f, l)的话,调用者需要确保[f, l-1)已经是一个堆. push_heap(f, l)仅仅会把*(l-1)插入到[f, l-1)这个区间形成的堆中,时间复杂度是O(logN).

4.2 源码探究

template
    inline void
    push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Compare __comp)
    {
      typedef typename iterator_traits<_RandomAccessIterator>::value_type
      _ValueType;
      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
      _DistanceType;

      // concept requirements
      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
        _RandomAccessIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      __glibcxx_requires_heap_pred(__first, __last - 1, __comp);

      _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
      std::__push_heap(__first, _DistanceType((__last - __first) - 1),
               _DistanceType(0), _GLIBCXX_MOVE(__value),
               __gnu_cxx::__ops::__iter_comp_val(__comp));
    }

---------------------分界线----------------------

template
    void
    __push_heap(_RandomAccessIterator __first,
        _Distance __holeIndex, _Distance __topIndex, _Tp __value,
        _Compare __comp)
    {
      _Distance __parent = (__holeIndex - 1) / 2;
      while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
    {
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
      __holeIndex = __parent;
      __parent = (__holeIndex - 1) / 2;
    }
      *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
    }

4.3 示例程式

void test_push_heap() {
        /**
        // default(1)
        template 
            viod push_heap(RandomAccessIterator first, RandomAccessIterator last)
            
        // custom(2)
        template
            void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
            
        */
        
        int myints[] = {10, 20, 30, 5, 15};
        std::vector v(myints, myints+5);
        
        std::make_heap(v.begin(), v.end());
        std::cout << "initial max heap: " << v.front() << endl;
        
        std::pop_heap(v.begin(), v.end());
        v.pop_back();
        std::cout << "max heap after pop: " << v.front() << endl;
        
        v.push_back(99);
        std::push_heap(v.begin(), v.end());
        std::cout << "max heap after push: " << v.front() << endl;
        
        std::sort_heap(v.begin(), v.end());
        std::cout << "final sorted range: ";
        for (int i = 0; i < v.size(); i++) {
            cout << " " << v[i];
        }
        cout << endl;
    }

4.4 输出结果

push_heap.png

5. pop_heap()函数

功能:将最大值移到位置last-1,[first, last-1)重新构建大根堆。
注意事项:在调用pop_heap时[first, last)已经是一个堆(使用相同的排序准则)

5.1 函数声明

// default(1)
        template
            void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
            
// custom(2)
        template
            void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

5.2 源码探究

通过查看源码,发现函数调用过程是:
pop_heap()->std::__pop_heap()->__adjust_heap()->__push_heap()
pop_heap()函数:

template
    inline void
    pop_heap(_RandomAccessIterator __first,
         _RandomAccessIterator __last, _Compare __comp)
    {
      // concept requirements
      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
        _RandomAccessIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      __glibcxx_requires_non_empty_range(__first, __last);
      __glibcxx_requires_heap_pred(__first, __last, __comp);

      if (__last - __first > 1)
    {
      --__last;
      std::__pop_heap(__first, __last, __last,
              __gnu_cxx::__ops::__iter_comp_iter(__comp));
    }
    }

std::__pop_heap()函数

template
    inline void
    __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
           _RandomAccessIterator __result, _Compare __comp)
    {
      typedef typename iterator_traits<_RandomAccessIterator>::value_type
    _ValueType;
      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    _DistanceType;

      _ValueType __value = _GLIBCXX_MOVE(*__result);
      *__result = _GLIBCXX_MOVE(*__first);
      std::__adjust_heap(__first, _DistanceType(0),
             _DistanceType(__last - __first),
             _GLIBCXX_MOVE(__value), __comp);
    }

__adjust_heap()函数

cpp
template
    void
    __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
          _Distance __len, _Tp __value, _Compare __comp)
    {
      const _Distance __topIndex = __holeIndex;
      _Distance __secondChild = __holeIndex;
      while (__secondChild < (__len - 1) / 2)
    {
      __secondChild = 2 * (__secondChild + 1);
      if (__comp(__first + __secondChild,
             __first + (__secondChild - 1)))
        __secondChild--;
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
      __holeIndex = __secondChild;
    }
      if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
    {
      __secondChild = 2 * (__secondChild + 1);
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
                             + (__secondChild - 1)));
      __holeIndex = __secondChild - 1;
    }
      std::__push_heap(__first, __holeIndex, __topIndex, 
               _GLIBCXX_MOVE(__value),
               __gnu_cxx::__ops::__iter_comp_val(__comp));

__push_heap()函数

template
    void
    __push_heap(_RandomAccessIterator __first,
        _Distance __holeIndex, _Distance __topIndex, _Tp __value,
        _Compare __comp)
    {
      _Distance __parent = (__holeIndex - 1) / 2;
      while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
    {
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
      __holeIndex = __parent;
      __parent = (__holeIndex - 1) / 2;
    }
      *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
    }

6. sort_heap()函数

功能:Sorts the elements in the heap range [first,last) into ascending order.
sort_heap即经典的堆排序算法,通过每次弹出堆顶直到堆为空,依次被弹出的元素就组成了有序的序列了。STL中的priority_queue即使用heap的这个特性来实现。使用sort_heap(f, l)处理过的区间因为已经有序,就不再是一个heap了。

6.1 函数声明

    // default(1)
        template
            void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
            
        // custom(2)
        template
            void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

6.2 源码探究

通过看源码,发现函数调用过程是:
sort_heap()->__sort_heap()->__pop_heap->__adjust_heap->__push_heap
sort_heap()函数:

template
    inline void
    sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Compare __comp)
    {
      // concept requirements
      __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
        _RandomAccessIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      __glibcxx_requires_heap_pred(__first, __last, __comp);

      std::__sort_heap(__first, __last,
               __gnu_cxx::__ops::__iter_comp_iter(__comp));
    }

__sort_heap()函数

template
    void
    __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
        _Compare __comp)
    {
      while (__last - __first > 1)
    {
      --__last;
      std::__pop_heap(__first, __last, __last, __comp);
    }
    }

__pop_heap()函数:

template
    inline void
    __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
           _RandomAccessIterator __result, _Compare __comp)
    {
      typedef typename iterator_traits<_RandomAccessIterator>::value_type
    _ValueType;
      typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    _DistanceType;

      _ValueType __value = _GLIBCXX_MOVE(*__result);
      *__result = _GLIBCXX_MOVE(*__first);
      std::__adjust_heap(__first, _DistanceType(0),
             _DistanceType(__last - __first),
             _GLIBCXX_MOVE(__value), __comp);
    }

adjust_heap()函数

template
    void
    __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
          _Distance __len, _Tp __value, _Compare __comp)
    {
      const _Distance __topIndex = __holeIndex;
      _Distance __secondChild = __holeIndex;
      while (__secondChild < (__len - 1) / 2)
    {
      __secondChild = 2 * (__secondChild + 1);
      if (__comp(__first + __secondChild,
             __first + (__secondChild - 1)))
        __secondChild--;
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
      __holeIndex = __secondChild;
    }
      if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
    {
      __secondChild = 2 * (__secondChild + 1);
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
                             + (__secondChild - 1)));
      __holeIndex = __secondChild - 1;
    }
      std::__push_heap(__first, __holeIndex, __topIndex, 
               _GLIBCXX_MOVE(__value),
               __gnu_cxx::__ops::__iter_comp_val(__comp));
    }

__push_heap()函数

template
    void
    __push_heap(_RandomAccessIterator __first,
        _Distance __holeIndex, _Distance __topIndex, _Tp __value,
        _Compare __comp)
    {
      _Distance __parent = (__holeIndex - 1) / 2;
      while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
    {
      *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
      __holeIndex = __parent;
      __parent = (__holeIndex - 1) / 2;
    }
      *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
    }

你可能感兴趣的:(标准库is_heap()、is_heap_until()、make_heap()、push_heap()、pop_heap()、sort_heap()函数)