该算法内容放在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);
}
}
}