二叉堆例子
参考: https://blog.csdn.net/lyqzzy/article/details/59849252
https://baike.baidu.com/item/二叉堆
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。
二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
用处: 系统进程优先级, 游戏处理时间回调, A星寻路的openset弹值.
例子: 下面是个小堆, 定义一个线程结构体, 先加些数据, 然后pop时拿出优先级最高的, 优先值为0的.
例子中UpHeap与DownHeap应改为循环处理, 不要使用递归.
#include <iostream> #include <vector> #include <unordered_map> using namespace std; struct ProcessInfo { int processId; //进程ID int priority; //优先级越小, 越在在前面 void InfoOut() { cout << "pid:" << processId << ", priority:" << priority << endl; } }; class MyHeap { public: shared_ptr<ProcessInfo> Pop() { //第一个最小, 就是我们要的 auto retPtr = m_vects[0]; //移除最小的操作, 数组第一与最后一个交换, 然后移除最后一个 Swap(0, m_vects.size() - 1); m_vects.pop_back(); //最左边的节点要向下沉 DownHeap(0); return retPtr; } //数据放到最后 void Push(shared_ptr<ProcessInfo> process) { m_vects.push_back(process); UpHeap(m_vects.size() - 1); } void Remove(shared_ptr<ProcessInfo> process) { int index = m_vects.size(); for (int i = 0; i < m_vects.size(); ++i) { if (process->processId == m_vects[i]->processId) { index = i; //交换到最后 Swap(index, m_vects.size() - 1); m_vects.pop_back(); break; } } if (index >= m_vects.size()) { return; } //交换后数据要下沉 DownHeap(index); } //上浮 当前节点与父节点比较, 比父节点小时就上浮 void UpHeap(int index) { if (index == 0) { return; } //子节点的值小于父节点的值, 向上冒, 交换, 否则停止 int parentIndex = (index - 1) / 2; if (m_vects[index]->priority < m_vects[parentIndex]->priority) { Swap(index, parentIndex); //交换后, 节点到了父节点的位, 需要再检测, 是否继续向上冒了 UpHeap(parentIndex); } } //下沉 当前节点与两个子点比较, 与最小的子节点交换 void DownHeap(int index) { int childLeft = 2 * index + 1; if (childLeft >= m_vects.size()) { //左子节点已经超出范围了 return; } //找到最小的子节点 auto minChild = m_vects[childLeft]; int childRight = childLeft + 1; int minIdx = childLeft; if (childRight < m_vects.size() && minChild->priority > m_vects[childRight]->priority) { minIdx = childRight; minChild = m_vects[childRight]; } if (m_vects[index]->priority < minChild->priority) { // 已经比两个子节点更小了, 中断下潜 return; } // 当前节点与最小的子节点交换 Swap(index, minIdx); //当前节点到了minIdx的位置了, 再次检测 DownHeap(minIdx); } //交换两个节的值 void Swap(int indexA, int indexB) { auto tmp = m_vects[indexA]; m_vects[indexA] = m_vects[indexB]; m_vects[indexB] = tmp; } int GetSize() { return m_vects.size(); } void SetCapcity(int capcity) { m_vects.reserve(capcity); } void PrintHeap() { cout << "heap size:" << m_vects.size() << ", info begin:------>\n"; for (auto& ptr : m_vects) { ptr->InfoOut(); } cout << "<------info end\n" << endl; } shared_ptr<ProcessInfo> GetDataByProcessID(int processId) { for (auto& ptr : m_vects) { if (ptr->processId == processId) { return ptr; } } } private: //小堆, 最顶端最小 //对应数组就是最左边最小 第n个节点的子节点是第2n及2n+1位置 1的子节点为2与3节点, 2的子节点为2*2=4, 5, 3的子节点为6,7 vector<shared_ptr<ProcessInfo>> m_vects; }; int main() { int capcity = 25; MyHeap heap; heap.SetCapcity(capcity); cout << "start push:" << endl; for (int i = 0; i < capcity; i++) { auto process = make_shared<ProcessInfo>(); process->processId = i; process->priority = i % 5; process->InfoOut(); heap.Push(process); } cout << "end push" << endl; //测试remove函数 auto ptr = heap.GetDataByProcessID(15); heap.Remove(ptr); cout << "start pop heap:" << endl; while (heap.GetSize() > 0) { auto ptr = heap.Pop(); ptr->InfoOut(); } system("pause"); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2013-08-30 linux多线程