优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。
优先队列的完全二叉树表示
note:0号位置是为了之后的插入操作方便,而加入的哨兵,如果在堆排序中,未给出这样的结点,则可不设置。
堆的两个特性
结构性:用数组表示的完全二叉树;
局部有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)
note:①此处易和二叉搜索树进行混淆,只是局部有界
②判断是否是最小堆(1)完全二叉树
(2)从根结点到任意结点路径上结点序列的有序性!
“最大堆(MaxHeap)”,也称“大顶堆”:最大值
“最小堆(MinHeap)”,也称“小顶堆” :最小值
template
class MinHeap { //最小堆类定义
private:
T* heapArray; //存放堆数据的数组
int CurrentSize; //当前堆中元素数目
int MaxSize; //堆所能容纳的最大元素数目
void swap(int pos_x, int pos_y); //交换位置x和y的元素
void BuildHeap(); //建堆
public:
MinHeap(const int n); //构造函数,n表示初始化堆的最大元素数目
virtual ~MinHeap(){delete []heapArray;}; //析构函数
bool isEmpty( ); // 如果堆空,则返回真
bool isLeaf(int pos) const; //如果是叶结点,返回TRUE
int leftchild(int pos) const; //返回左孩子位置
int rightchild(int pos) const; //返回右孩子位置
int parent(int pos) const; //返回父结点位置
bool Remove(int pos, T& node); //删除给定下标的元素
bool Insert(const T& newNode); //向堆中插入新元素newNode
T& RemoveMin(); //从堆顶删除最小值
void SiftUp(int position); //从position向上开始调整,使序列成为堆
void SiftDown(int left); //筛选法函数,参数left表示开始处理的数组下标
};
一、插入新元素——向上筛选
template
int MinHeap
::leftchild(int pos) const {
return 2*pos + 1; //返回左孩子位置
}
template
int MinHeap
::rightchild(int pos) const {
return 2*pos + 2; //返回右孩子位置
}
template
int MinHeap
::parent(int pos) const { return (pos-1)/2; //返回父结点位置 } template
void MinHeap
::swap(int pos_x, int pos_y) //交换位置x和y的元素 { T temp = heapArray[pos_x]; heapArray[pos_x] = heapArray[pos_y]; heapArray[pos_y] = temp; } template
bool MinHeap
::Insert(const T& newNode) { //向堆中插入新元素newNode if(CurrentSize == MaxSize) //堆空间已经满 return FALSE; heapArray[CurrentSize] = newNode; //从最后结点开始插入 SiftUp(CurrentSize); //向上调整 CurrentSize++; return TRUE; } template
void MinHeap
::SiftUp(int position) { //从position向上开始调整,使序列成为堆 未使用哨兵 int temppos = position; T temp = heapArray[temppos]; while ((temppos>0) && (heapArray[parent(temppos)]>temp)) { heapArray[temppos] = heapArray[parent(temppos)]; temppos = parent(temppos); } heapArray[temppos] = temp; }
二、删除堆顶(取最大值或者最小值)——向下筛选
第一步:取最后的那个结点代替栈顶结点
第二步:向下筛选
template
T& MinHeap
::RemoveMin() { //从堆顶删除最小值
if (CurrentSize == 0) {
cout<< "Can't Delete" <
1)
SiftDown(0); //从堆顶开始筛选
return heapArray[CurrentSize];
}
}
template
void MinHeap
::SiftDown(int left) { int i = left; // 标识父结点 int j = leftchild (i); // 标识关键值较小的子结点 T temp = heapArray[i]; // 保存父结点 while (j < CurrentSize) { // 过筛 if ((j < CurrentSize-1) && (heapArray[j]>heapArray[j + 1]))//左子节点存在右子节点未必存在 j++; // j指向右子结点 if (temp>heapArray[j]) { heapArray[i] = heapArray[j]; i = j; j = leftchild(j); // 向下继续 } else break; } heapArray[i] = temp; }
三、堆的建立
建立最大(小)堆:将已经存在的N个元素按最大(小)堆的要求存放在一个一维数组中
方法1:通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去,其时间代价最大为O(N logN)。
建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中
方法2:在线性时间复杂度下建立最大堆。
(1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性
(2)调整各结点位置,以满足最大堆的有序特性。
调整从栈顶到最后一个没有子女的结点进行向下筛选
template
void MinHeap
::BuildHeap() {
for (int i = CurrentSize/2-1; i >= 0; i--) //反复调用筛选函数
SiftDown(i);
}