1.为何要实现优先级队列这种数据结构
考虑实际中的问题,某个夜间门诊只有一个接诊医生,在接诊病人时的次序自然是按照队列的FIFO(先进先出)的原则进行实行。但是这是有一个伤口出血的病人自然是要比平常感冒的病人要先被接诊,而相对于一个心脏病突发的病人更是需要把他放置在更高的优先级。
在计算机系统中,运行程序也是遵循某个优先级关系。在一批待处理的进程中,系统总是将优先级更高的进程优先传递给CPU进行处理。
这些问题都需要运用到优先级队列这种数据结构。
2.优先级队列所要实现的基本接口
根据以上接口,可知要实现的三种方法要控制在一个良好的复杂度。
1.若采用向量vector来实现优先级队列
其插入可以采用在尾部插入的vector::put_back(const T& e) - 复杂度为O(1)
其get_max需要遍历整个向量才能得出最高优先级词条 - 其复杂度为O(n)
而del_max则更是需要get_max后再进行删除 - 其复杂也可达O(n)
2.若采用有序的向量sorted_vector来实现优先级队列
固然其查找和删除都可以在向量的尾部进行 - 其复杂度仅仅只有O(1)
但是其插入操作为了保证有序插入 - 需要进行二分查找(O(logn)) - 而插入操作涉及元素的移动也可达O(n)复杂度
3.若采用链表list进行实现优先级队列
其插入操作固然可以达到O(1)
但是其get_max和del_max接口都需要对最高优先级的元素进行查找,其复杂度都可达O(n)
----------------即使采用有序化的链表
其get_max接口和del_max接口都可在把首节点设为最高优先级的情况下,复杂度为O(1)
但是其插入操作则不得在有序的查找下进行O(n) + O(1) - O(n)复杂度
4.继而考虑采用平衡二叉搜索树(BBST) - AVL树、splay树、red_black树
可以相信其三种操作都是可以在O(logn)复杂度下实现
但是优先级队列只需维护队列中优先级最高的元素即可 - BBST则需要维护这种全序,未免显得有些杀鸡用牛刀
3.以上实现方法都不能在效率和成本上比较好的实现,考虑采用—以向量为形,完全二叉树为神—来实现优先级队列
3.1 完全二叉树
从根节点到倒数第二层构成的是一个满二叉树(2^h-1 - 1个节点),最后一层可能不满
也可看作平衡因子非负的AVL树,平衡因子为0,左子树为满二叉树时 // 平衡因子为1,右子树为满二叉树时
3.2 向量之形
其存储的形式是以一个动态分配的可扩充数组来实现的,将有20个节点的完全二叉树存储为向量其对应形式可视为:
3.3 完全二叉树之神
根据宏定义可将向量中秩所对应的元素确定子父关系
#define Parent(i) ( ( ( i ) - 1 ) >> 1 ); //某个节点的父亲的秩必为其( rank - 1 )/ 2
#define Lchild(i) ( 1 + ( ( i ) << 1 ) ); //某个节点存在左孩子其左孩子的秩为其 ( rank * 2 ) + 1 - 为奇数
#define Rchild(i) ( ( 1 + ( i ) ) << 1 ); //某个节点存在右孩子其右孩子的秩为其 ( rank + 1 ) * 2 - 为偶数
为了对优先级队列中优先级高的词条进行快速处理,规定完全二叉树还要满足堆序性
即其H( i ) <= H( Parent( i ) ) - 从而保证最大元始终在根节点处 - 即向量中秩为0所对应的词条
原文地址:https://www.cnblogs.com/exhina/p/12368988.html