heap只能算是算法,而priority_queue只是封装了vector,所以又称为配接器。
由于在下面的实现中需要获得iterator所指向的类型,所以又用到了stl中的类型萃取技术
cconstruct.h
#ifndef C_CONSTRUCT_H
#define C_CONSTRUCT_H
#include <iostream>
#include <new.h>
inline void destroy(char *, char *){}
inline void destroy(int *, int *){}
inline void destroy(long *, long *){}
inline void destroy(float *, float *){}
inline void destroy(double *, double *){}
//对于int* p,也可以调用这个函数,比较怪异
template <class T>
inline void destroy(T* pointer) {
pointer->~T();
}
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
for (; first < last ; ++first)
destroy(first);
}
template <class T1, class T2>
inline void construct(T1* p, const T2& value) {
new (p) T1(value);
}
template <class _Iter>
inline typename std::iterator_traits<_Iter>::value_type*
__value_type(const _Iter&)
{
return static_cast<typename std::iterator_traits<_Iter>::value_type*>(0);
}
#endif
cheap.h
#ifndef C_HEAP_H
#define C_HEAP_H
#include "cconstruct.h"
#include <iostream>
//上溯。假设要上溯的值放在堆尾
template <class RandomAccessIterator, class Compare>
void cpush_heap(RandomAccessIterator first, RandomAccessIterator last, Compare cmp ) {
__cpush_heap(first, last, __value_type(first), cmp);
}
template <class RandomAccessIterator, class T, class Compare>
void __cpush_heap(RandomAccessIterator first, RandomAccessIterator last, T*, Compare cmp) {
size_t holeIndex = last - first - 1;
size_t parent = (holeIndex - 1)/2;
T value = *(last - 1);
while (holeIndex > 0 && cmp(*(first + parent), value)) {
*(first + holeIndex) = *(first + parent);
holeIndex = parent;
parent = (holeIndex - 1)/2;
}
*(first + holeIndex) = value;
}
//上溯操作只适用于在尾部添加元素,维持堆特性的操作
template <class RandomAccessIterator, class Compare>
void cpop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare cmp) {
__cpop_heap(first, last, __value_type(first), cmp);
}
template <class RandomAccessIterator, class T, class Compare>
void __cpop_heap(RandomAccessIterator first, RandomAccessIterator last, T*, Compare cmp) {
T value = *(last - 1);
*(last - 1) = *first;
__cadjust_heap(first, 0, last - first - 1, value, cmp);//注意,此时的长度就不应该算上堆尾
}
//向下走。value本来放在holeIndex
template <class RandomAccessIterator, class T, class Compare>
void __cadjust_heap(RandomAccessIterator first, size_t holeIndex, size_t len, T value, Compare cmp) {
size_t firstChild = 2* holeIndex + 1;
for ( ; firstChild < len; firstChild = 2* firstChild + 1) {
if (firstChild + 1 < len && cmp(*(first + firstChild ), *(first + firstChild + 1)))
++firstChild;
if (!cmp(value, *(first + firstChild) ))//value >= child
break;
*(first + holeIndex) = *(first + firstChild);
holeIndex = firstChild;
}
*(first + holeIndex) = value;
}
//输入必须是已经成堆的
template <class RandomAccessIterator, class Compare>
void csort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare cmp) {
while (last - first > 1) cpop_heap(first, last--, cmp);
}
template <class RandomAccessIterator, class Compare>
void cmake_heap(RandomAccessIterator first, RandomAccessIterator last, Compare cmp) {
__cmake_heap(first, last, __value_type(first), cmp);
}
template <class RandomAccessIterator, class T,class Compare>
void __cmake_heap(RandomAccessIterator first, RandomAccessIterator last, T*, Compare cmp) {
if (last - first < 2) return;
size_t len = last - first;
size_t holeIndex = (len - 2)/2;//从底向上,第一棵子树的头
while (true) {
__cadjust_heap(first, holeIndex, len, *(first + holeIndex), cmp);
if (holeIndex == 0) return;
--holeIndex;
}
}
#endif
cqueue.h
#ifndef C_QUEUE_H
#define C_QUEUE_H
#include "cvector.h"
#include "cheap.h"
#include <iostream>
template <class T, class Seq = cvector<T>, class Compare = less<typename Seq::value_type> >
class cpriority_queue {
public:
typedef typename Seq::value_type value_type;
typedef typename Seq::reference reference;
typedef typename Seq::const_reference const_reference;
protected:
Seq c;//底层容器
Compare comp;
public:
cpriority_queue() : c() {}
template <class InputIterator>
cpriority_queue(InputIterator first, InputIterator last, const Compare& x)
: c(first, last), comp(x) { cmake_heap(c.begin(), c.end(), comp); }
template <class InputIterator>
cpriority_queue(InputIterator first, InputIterator last)
: c(first, last){ cmake_heap(c.begin(), c.end(), comp); }
/*void show() {
Seq::iterator first = c.begin();
for (;first != c.end(); ++first)
std::cout<<*first<<" ";
std::cout<<endl;
}*/
bool empty() const { return c.empty(); }
size_t size() const { return c.size(); }
const_reference top() const { return c.front(); }
void push(const value_type& x) {
c.push_back(x);
cpush_heap(c.begin(), c.end(), comp);
}
void pop() {
cpop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
};
#endif