自定义小根堆使用

来源:互联网 发布:mac取得最高权限 编辑:程序博客网 时间:2024/05/12 18:48

小根堆原理是完全二叉树的结构上父节点的值比两个子节点的值要小。

应用游戏场景如:在游戏服务器的ai的a*寻路中会使用到计算f值最小的节点。


1、二叉堆定义

模板的T是地图节点的类型。数组结构实现的二叉树。

插入操作(putNodeIn)和 弹出堆顶操作( popRootNodeOut )保证在比较相同的情况下,新进入的节点在堆的更上层。

//----------------------------// 二叉堆 ,T 需要支持 operator < 操作//---------------------------//vector存储结构的二叉堆封装。template < typename T >class BinaryHeap{public: BinaryHeap(){};压入节点到二叉树。// putNodeIn & popRootNodeOut 保证在比较相同的情况下,新进入的节点在堆的更上层 inline bool putNodeIn( T *node ); inline T* popRootNodeOut ();inline void clear();private:inline const uint32 getFatherIndex( const uint32 nodeIndex ) const;//获取父节点inline const uint32 get1stChildIndex( const uint32 nodeIndex ) const;//获取第一个子节点inline const uint32 get2ndChildIndex( const uint32 nodeIndex ) const;//获取第二个子节点protected:std::vector<T*> m_vec;};

清除小根堆

template < typename T >void BinaryHeap<T>::clear() {m_vec.clear();//清除数组}


2、插入新节点

放入节点到数组末尾,并调整小根堆(跟父节点比较,比父节点小则交换)

template < typename T >bool BinaryHeap<T>::putNodeIn(T *node){m_vec.push_back(node);//把子节点放入列表最后if (m_vec.size() <= 1) {return true;}uint32 nowIndex = m_vec.size()-1;//当前节点下标while (nowIndex != 0) {uint32 fatherIndex = getFatherIndex(nowIndex);//获取父节点的下标if (!(*m_vec[nowIndex] < *m_vec[fatherIndex])) {//如果父节点下标与当前节点下标相比较大则交换对象并指向父节点T* tmp = m_vec[nowIndex];m_vec[nowIndex] = m_vec[fatherIndex];m_vec[fatherIndex] = tmp;nowIndex = fatherIndex;}else {break;}}return true;}

3、弹出根节点

从小根堆头部弹出根节点,并调整小根堆。

把最后的节点放入头节点,调整小根堆(父节点跟较小的子节点交换)

template < typename T >T* BinaryHeap<T>::popRootNodeOut(){if (m_vec.empty()) {return NULL;}T* ret = m_vec[0];m_vec[0] = m_vec.back();//把最后的节点放到头节点m_vec.pop_back();//弹出最后的节点if (m_vec.size() <= 1) {return ret;}uint32 nowIndex = 0;//当前下标指向头结点uint32 maxIndex = m_vec.size() - 1;while (true) {uint32 firstChildIndex = get1stChildIndex(nowIndex);//获取该索引的第一个子节点uint32 secondChildIndex = get2ndChildIndex(nowIndex); //获取该索引的第二个子节点uint32 minChildIndex = nowIndex;if (secondChildIndex > maxIndex) {if (firstChildIndex > maxIndex) {//两子节点都没有break;}else {minChildIndex = firstChildIndex;//把下标指向第一个子节点(第二个节点不存在)}}else {minChildIndex = *m_vec[firstChildIndex] < *m_vec[secondChildIndex] ?firstChildIndex : secondChildIndex;//两子节点都有就指向较小的子节点}if (*m_vec[minChildIndex] < *m_vec[nowIndex])//当前节点和子节点相比较大则交换对象并把下标指向子节点{T* tmp = m_vec[nowIndex];m_vec[nowIndex] = m_vec[minChildIndex];m_vec[minChildIndex] = tmp;nowIndex = minChildIndex;}else {break;}}return ret;}


4、获取节点

(1)获取父节点

template < typename T >const uint32 BinaryHeap<T>::getFatherIndex(const uint32 nodeIndex) const {if (0 == nodeIndex)return 0;return (nodeIndex - 1) / 2;}


(2)获取第一个子节点

获取一个子节点的
template < typename T >const uint32 BinaryHeap<T>::get1stChildIndex(const uint32 nodeIndex) const {return nodeIndex * 2 + 1;}


(3)获取第二个子节点


template < typename T >const uint32 BinaryHeap<T>::get2ndChildIndex(const uint32 nodeIndex) const {return nodeIndex * 2 + 2;}

5、清除小根堆

template < typename T >void BinaryHeap<T>::clear() {m_vec.clear();//清除数组}

 

0 0