pairing heap在nebula studio中的使用场景主要用于HLS流和UDP流的限速发送,pairing heap用于timed queue的底层实现,在我们的pairing heap的中,实现了两种pairing heap,一个分配节点内存,一个不分配节点内存,据测试,比STL中的优先队列性能高出近1倍,下面是具体实现:
//
// pairingheap.h
// nebula
//
// Created by yi.cheng on 16/4/28.
// Copyright © 2016 kanshansoft. All rights reserved.
//
#ifndef pairingheap_h
#define pairingheap_h
#include
#include
namespace anysee {
//! Pairing heap node.
template
struct PairingHeapNode {
T value; //!< Value contained in the node.
PairingHeapNode
*prev; //!< Previous sibling of the node or parent.
PairingHeapNode
*next; //!< Next sibling of the node. PairingHeapNode
*child; //!< First child of the node. //! Creates heap node with a given \a value. inline PairingHeapNode(const T &val) : value(val), prev(nullptr), next(nullptr), child(nullptr) { } inline PairingHeapNode(T&& val) : value(std::move(val)), prev(nullptr), next(nullptr), child(nullptr) { } }; //! Pairing heap implementation. /** * @ingroup containers * * Code is mainly based on orginal paper "The Pairing Heap: A New Form of * Self-Adjusting Heap" by Fredman, Sedgewick, Sleator and Tarjan. * * @tparam T Denotes value type of inserted elements. * @tparam C Denotes comparison functor determining value ordering. */ template
> class PairingHeap { public: /** * Creates empty pairing heap. * * @param cmp Comparison functor determining value ordering. * @param initialSize ignored by this implementation. */ PairingHeap(const C &cmp = C(), int initialSize = -1); /** * Destructs pairing heap. * * If the heap is not empty, destructors of contained elements are called * and used storage is deallocated. */ virtual ~PairingHeap(); //! Returns reference to the top element in the heap. const T &top() const; /** * Inserts a new node with given \a value into a heap. * * @param value A value to be inserted. * @return Handle to the inserted node. */ PairingHeapNode
*push(const T &value); PairingHeapNode
*push(const T &value, bool& isHeadChanged); PairingHeapNode
*push(T &&value); PairingHeapNode
*push(T &&value, bool& isHeadChanged); /** * Removes the top element from the heap. * * Behaviour of this function is undefined if the heap is empty. */ T pop(); /** * Decreases value of the given \a node to \a value. * * Behaviour of this function is undefined if node does not belong to a the * heap or new value is greater than old one. * * @param node A node for which the value is to be decreased. * @param value A new value for the node. */ void decrease(PairingHeapNode
*node, const T &value); /** * Merges in values of \a other heap. * * After merge \a other heap becomes empty and is valid for further usage. * * @param other A heap to be merged in. */ void merge(PairingHeap
&other); /* * Retuns the value of the node * * @param node The nodes handle * @return the value of the node */ const T &value(PairingHeapNode
*node) const { return node->value; } inline bool isEmpty() const { return (m_root == NULL); } private: C m_comp; ObjPool
> m_pool; PairingHeapNode
*m_root; //!< Root node of the heap. //! Pairs list of heaps given as \a node. Returns resulting list. PairingHeapNode
*pair(PairingHeapNode
**node); //! Merges lists of heaps \a a and \a b. Returns resulting list. PairingHeapNode
*merge(PairingHeapNode
*a, PairingHeapNode
*b); //! Makes \a child node a child of \a parent node. void link(PairingHeapNode
*parent, PairingHeapNode
*child); //! Removes \a node from its parent children list. void unlink(PairingHeapNode
*node); //! Releases memory occupied by list of heaps given as \a node. void release(PairingHeapNode
*node); }; template
PairingHeap
::PairingHeap(const C &cmp, int initialSize) : m_root(nullptr), m_pool(1024) { this->m_comp = cmp; } template
PairingHeap
::~PairingHeap() { release(m_root); m_root = nullptr; } template
inline const T &PairingHeap
::top() const { return m_root->value; } template
inline PairingHeapNode
*PairingHeap
::push(const T &value, bool& isHeadChanged) { PairingHeapNode
*node = m_pool.alloc(value); PairingHeapNode
*root = m_root; m_root = m_root == nullptr ? node : merge(m_root, node); isHeadChanged = (root == m_root) ? false : true; return node; } template
inline PairingHeapNode
*PairingHeap
::push(const T &value) { PairingHeapNode
*node = m_pool.alloc(value); m_root = m_root == nullptr ? node : merge(m_root, node); return node; } template
inline PairingHeapNode
*PairingHeap
::push(T && value, bool& isHeadChanged) { PairingHeapNode
*node = m_pool.alloc(std::move(value)); PairingHeapNode
*root = m_root; m_root = m_root == nullptr ? node : merge(m_root, node); isHeadChanged = (root == m_root) ? false : true; return node; } template
inline PairingHeapNode
*PairingHeap
::push(T && value) { PairingHeapNode
*node = m_pool.alloc(std::move(value)); m_root = m_root == nullptr ? node : merge(m_root, node); return node; } template
inline T PairingHeap
::pop() { PairingHeapNode
*children = m_root->child; T val = m_root->value; m_pool.free(m_root); m_root = pair(&children); return val; } template
void PairingHeap
::decrease(PairingHeapNode
*node, const T &value) { node->value = value; unlink(node); if (node->child) node = merge(node, pair(&node->child)); if (node != m_root) { if (m_root != NULL) m_root = merge(m_root, node); else m_root = node; } } template
void PairingHeap
::merge(PairingHeap
&other) { m_root = merge(m_root, other.m_root); other.m_root = nullptr; } template
inline PairingHeapNode
*PairingHeap
::pair( PairingHeapNode
**node) { if(*node == nullptr) { return nullptr; } PairingHeapNode
* first_child = *node; PairingHeapNode
* second_child = (*node)->next; PairingHeapNode
* merge_node = NULL; first_child->prev = first_child->next = NULL; if(second_child == NULL) { merge_node = first_child; return merge_node; } else { *node = second_child->next; second_child->prev = second_child->next = NULL; merge_node = merge(first_child, second_child); } PairingHeapNode
* node_list = merge_node; PairingHeapNode
* cur_node_list = node_list; while (*node) { first_child = *node; second_child = (*node)->next; first_child->prev = first_child->next = NULL; if(second_child == NULL) { merge_node = first_child; *node = (*node)->next; } else { *node = second_child->next; second_child->prev = second_child->next = NULL; merge_node = merge(first_child, second_child); } cur_node_list->next = merge_node; merge_node->prev = cur_node_list; cur_node_list = merge_node; } merge_node = pair(&node_list); return merge_node; } template
inline PairingHeapNode
*PairingHeap
::merge( PairingHeapNode
*a, PairingHeapNode
*b) { if(nba_likely(this->m_comp(a->value, b->value))) { link(a, b); return a; } else { link(b, a); return b; } } template
inline void PairingHeap
::link( PairingHeapNode
*root, PairingHeapNode
*child) { if(root->child != nullptr) { child->next = root->child; root->child->prev = child; } child->prev = root; root->child = child; } template
inline void PairingHeap
::unlink( PairingHeapNode
*node) { if(node->prev) { if(node->prev->child == node) { node->prev->child = node->next; } else { node->prev->next = node->next; } } if(node->next != nullptr) { node->next->prev = node->prev; } node->prev = nullptr; node->next = nullptr; } template
inline void PairingHeap
::release(PairingHeapNode
*node) { /* * Recursive version of this function is infinitely prettier than that * abomination. Please, make it prettier if you can. */ PairingHeapNode
*it = node; if(it == nullptr) { return; } for(;;) { // Slide down as long as possible. if(it->child != nullptr) { it = it->child; continue; } if(it->next != nullptr) { it = it->next; continue; } // Climb up until you find first non-visited node. for(;;) { PairingHeapNode
*curr = it, *prev = it->prev; m_pool.free(it); if(prev == nullptr) { return; } if(curr == prev->child && prev->next != nullptr) { it = prev->next; break; } else { it = prev; } } } } template
> class PairingNeutralHeap { public: struct PairTreeNode { inline PairTreeNode() : prev(nullptr), next(nullptr), child(nullptr) { } PairTreeNode *prev; //!< Previous sibling of the node or parent. PairTreeNode *next; //!< Next sibling of the node. PairTreeNode *child; //!< First child of the node. K key; //key }; /** * Creates empty pairing heap. * * @param cmp Comparison functor determining value ordering. * @param initialSize ignored by this implementation. */ PairingNeutralHeap(const C &cmp = C(), int initialSize = -1); /** * Destructs pairing heap. * * If the heap is not empty, destructors of contained elements are called * and used storage is deallocated. */ virtual ~PairingNeutralHeap(); //! Returns reference to the top element in the heap. const PairTreeNode* top() const; /** * Inserts a new node with given \a value into a heap. * * @param value A value to be inserted. * @return Handle to the inserted node. */ void push(PairTreeNode* node, bool& isHeadChanged); /** * Removes the top element from the heap. * * Behaviour of this function is undefined if the heap is empty. */ PairTreeNode* pop(); /** * Decreases value of the given \a node to \a value. * * Behaviour of this function is undefined if node does not belong to a the * heap or new value is greater than old one. * * @param node A node for which the value is to be decreased. * @param value A new value for the node. */ void decrease(PairTreeNode *node); /** * Merges in values of \a other heap. * * After merge \a other heap becomes empty and is valid for further usage. * * @param other A heap to be merged in. */ void merge(PairingNeutralHeap
&other); inline bool isEmpty() const { return (m_root == NULL); } private: C m_comp; PairTreeNode *m_root; //!< Root node of the heap. //! Pairs list of heaps given as \a node. Returns resulting list. PairTreeNode *pair(PairTreeNode **node); //! Merges lists of heaps \a a and \a b. Returns resulting list. PairTreeNode *merge(PairTreeNode *a, PairTreeNode *b); //! Makes \a child node a child of \a parent node. void link(PairTreeNode *parent, PairTreeNode *child); //! Removes \a node from its parent children list. void unlink(PairTreeNode *node); void swap(PairTreeNode *a, PairTreeNode* b); //! Releases memory occupied by list of heaps given as \a node. void release(PairTreeNode *node); }; template
PairingNeutralHeap
::PairingNeutralHeap(const C &cmp, int initialSize) : m_root(nullptr) { this->m_comp = cmp; } template
PairingNeutralHeap
::~PairingNeutralHeap() { release(m_root); m_root = nullptr; } template
inline const typename PairingNeutralHeap
::PairTreeNode* PairingNeutralHeap
::top() const { return m_root; } template
inline void PairingNeutralHeap
::push(PairTreeNode* node, bool& isHeadChanged) { PairTreeNode* root = m_root; m_root = m_root == nullptr ? node : merge(m_root, node); isHeadChanged = (m_root == root) ? false : true; } /** * \b Effects: Removes top element from the priority_queue. * * \cond * \b Complexity: \f$2^2log(log(N))\f$ (amortized). * \endcond * * \b Complexity: 2**2*log(log(N)) (amortized). * */ template
typename PairingNeutralHeap
::PairTreeNode* PairingNeutralHeap
::pop() { PairTreeNode* node = m_root; PairTreeNode *children = m_root->child; m_root = pair(&children); return node; } /** * \b Effects: decrease the heap after the element has been changed. * * \cond * \b Complexity: \f$2^2log(log(N))\f$ (amortized). * \endcond * * \b Complexity: 2**2*log(log(N)) (amortized). * * \b Note: If this is not called, after a handle has been updated, the behavior of the data structure is undefined! * */ template
void PairingNeutralHeap
::decrease(PairTreeNode *node) { unlink(node); if (node->child) node = merge(node, pair(&node->child)); if (node != m_root) { if (m_root != NULL) m_root = merge(m_root, node); else m_root = node; } } template
void PairingNeutralHeap
::merge(PairingNeutralHeap
&other) { m_root = merge(m_root, other.m_root); other.m_root = nullptr; } template
inline typename PairingNeutralHeap
::PairTreeNode *PairingNeutralHeap
::pair( PairTreeNode **node) { if(*node == nullptr) { return nullptr; } PairTreeNode* first_child = *node; PairTreeNode* second_child = (*node)->next; PairTreeNode* merge_node = NULL; first_child->prev = first_child->next = NULL; if(second_child == NULL) { merge_node = first_child; return merge_node; } else { *node = second_child->next; second_child->prev = second_child->next = NULL; merge_node = merge(first_child, second_child); } PairTreeNode* node_list = merge_node; PairTreeNode* cur_node_list = node_list; while (*node) { first_child = *node; second_child = (*node)->next; first_child->next = first_child->prev = NULL; if(second_child == NULL) { merge_node = first_child; *node = (*node)->next; } else { *node = second_child->next; second_child->prev = second_child->next = NULL; merge_node = merge(first_child, second_child); } cur_node_list->next = merge_node; merge_node->prev = cur_node_list; cur_node_list = merge_node; } merge_node = pair(&node_list); return merge_node; } template
inline typename PairingNeutralHeap
::PairTreeNode *PairingNeutralHeap
::merge( PairTreeNode *a, PairTreeNode *b) { if(this->m_comp(a->key, b->key)) { link(a, b); return a; } else { link(b, a); return b; } } template
inline void PairingNeutralHeap
::swap(PairTreeNode *a, PairTreeNode* b) { PairTreeNode* c = a; a = b; b = c; } template
inline void PairingNeutralHeap
::link( PairTreeNode *root, PairTreeNode *child) { if(root->child != nullptr) { child->next = root->child; root->child->prev = child; } child->prev = root; root->child = child; } template
inline void PairingNeutralHeap
::unlink( PairTreeNode *node) { if(node->prev != NULL) { if(node->prev->child == node) { node->prev->child = node->next; } else { node->prev->next = node->next; } } if(node->next != nullptr) { node->next->prev = node->prev; } node->prev = nullptr; node->next = nullptr; } template
inline void PairingNeutralHeap
::release(PairTreeNode *node) { /* * Recursive version of this function is infinitely prettier than that * abomination. Please, make it prettier if you can. */ PairTreeNode *it = node; if(it == nullptr) { return; } for(;;) { // Slide down as long as possible. if(it->child != nullptr) { it = it->child; continue; } if(it->next != nullptr) { it = it->next; continue; } // Climb up until you find first non-visited node. for(;;) { PairTreeNode *curr = it, *prev = it->prev; if(prev == nullptr) { return; } if(curr == prev->child && prev->next != nullptr) { it = prev->next; break; } else { it = prev; } } } } } #endif /* pairingheap_h */