优先级队列概念
优先级队列是一种按元素优先级大小顺序出队的队列,与普通队列先进先出不同。每一个元素都有优先权,分为元素值越大优先级越高、元素值越小,优先级越高两种;虽然它是一种队列,但是用堆的思想完成的(队列里面堆排序)。
小根堆的两种调整方法
从上到下
还记得堆排序中小根堆交换根和最后一个元素位置后的调整吗,那相当于在根的位置(队头)放入了一个值大的元素,然后从上往下调整,从使上面的大元素移到后面去:
void FilterDown(int* nums, int start,int end)
{
int i = start, j = 2 * i + 1;
int tmp = nums[i];
while (j <= end)
{
if (j<end && nums[j]>nums[j + 1])j++;
if (tmp <= nums[j])break;
nums[i] = nums[j];
i = j;
j = i * 2 + 1;
}
nums[i] = tmp;
}
从下往上
这种方法相当于在队尾部放入了一个值小的元素,然后想办法把它移动上去
void FilterUP(int* nums, int start)
{
int j = start, i = (j - 1) / 2;
int tmp = nums[j];
while (j > 0)
{
if (tmp >= nums[i])break;
nums[j] = nums[i];//大的数往下层移
j = i;
i = (j - 1) / 2;
}
nums[j] = tmp;
}
这两个方法在实现优先级队列中需要用到,是关键代码。
构造一个优先级队列类
私有部分:队列里面包含三个变量分别指向元素,保存队尾下标,元素个数
int* data;//元素
int cursize;//当前元素个数
int maxsize;//队尾下标
公共部分:
成员构造、析构函数,因为有指针,所以必须写;上面说到的两个调整函数;数据出队入队;判断队列空或满;取队列内元素个数;清除队列;
MinHeap(int sz = 100);
~MinHeap();
//向下调整
static void FilterDown(int* nums, int start, int end);
//向上调整
static void FilterUP(int* nums, int start);
int getSize()const { return cursize; }
bool isEmpty() const { return getSize() == 0; }
bool isFull()const { return getSize() == maxsize; }
void clear() { cursize = 0; }
//入队
bool push(const int& val);
//出队
bool remove(int& val);
入队时,先判断队列是否满,如果可以入队,调整cursize和maxsize的大小,将元素放入队尾,之后使用向上调整函数完成优先级队列内部顺序的调整。
出队时,先判断队列是否为空,如果可以出队,则将队头元素出,队头即为优先级最大的元素,然后将队尾元素放到队头,,调整cursize和maxsize的大小,使用向下调整函数调整顺序。
完整代码
class MinHeap
{
private:
int* data;//元素
int cursize;//当前元素个数
int maxsize;//队尾下标
public:
MinHeap(int sz = 100)
{
cursize = 0;
maxsize = sz;
data = new int[maxsize];
}
~MinHeap()
{
delete[]data;
data = NULL;
cursize = 0;
maxsize = 0;
}
//向下调整
static void FilterDown(int* nums, int start, int end)
{
int i = start, j = 2 * i + 1;
int tmp = nums[i];
while (j <= end)
{
if (j<end && nums[j]>nums[j + 1])j++;
if (tmp <= nums[j])break;
nums[i] = nums[j];
i = j;
j = i * 2 + 1;
}
nums[i] = tmp;
}
//向上调整
static void FilterUP(int* nums, int start)
{
int j = start, i = (j - 1) / 2;
int tmp = nums[j];
while (j > 0)
{
if (tmp >= nums[i])break;
nums[j] = nums[i];//大的数往下层移
j = i;
i = (j - 1) / 2;
}
nums[j] = tmp;
}
int getSize()const { return cursize; }
bool isEmpty() const { return getSize() == 0; }
bool isFull()const { return getSize() == maxsize; }
void clear() { cursize = 0; }
//入队
bool push(const int& val)
{
if (isFull())return false;
data[cursize++] = val;
FilterUP(data, cursize - 1);//从后往前调
return true;
}
//出队
bool remove(int& val)
{
if (isEmpty())return false;
val = data[0];
data[0] = data[cursize - 1];//把最后一个元素放第一个,覆盖取出的
cursize--;
FilterDown(data, 0, cursize - 1);
return true;
}
};
使用测试
int main()
{
MinHeap mh(100);
mh.push(12);
mh.push(23);
mh.push(100);
mh.push(89);
mh.push(45);
while (!mh.isEmpty())
{
int x = 0;
mh.remove(x);
printf("%-5d\n", x);
}
mh.clear();
mh.clear();
}
如果需要改成值越大优先级越大,只需修改调整函数中if里面的大于小于号: