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
#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