在优先队列中,优先级高的元素先出队列。
标准库默认使用元素类型的<操作符来确定它们之间的优先级关系。
优先队列的第一种用法,也是最常用的用法:
priority_queue
<
int
>
qi;
通过<操作符可知在整数中元素大的优先级高。
故示例1中输出结果为:9 6 5 3 2
第二种方法:
在示例1中,如果我们要把元素从小到大输出怎么办呢?
这时我们可以传入一个比较函数,使用functional.h函数对象作为比较函数。
priority_queue
<
int
, vector
<
int
>
, greater
<
int
>
>
qi2;
其中
第二个参数为容器类型。
第二个参数为比较函数。
故示例2中输出结果为:2 3 5 6 9
第三种方法:
自定义优先级。
struct node
{
friend
bool operator
<
(node n1, node n2)
{
return
n1.priority
<
n2.priority;
}
int
priority;
int
value;
};
在该结构中,value为值,priority为优先级。
通过自定义operator<操作符来比较元素中的优先级。
在示例3中输出结果为:
优先级 值
9 5
8 2
6 1
2 3
1 4
但如果结构定义如下:
struct node
{
friend
bool operator
>
(node n1, node n2)
{
return
n1.priority
>
n2.priority;
}
int
priority;
int
value;
};
则会编译不过(G++编译器)
因为标准库默认使用元素类型的<操作符来确定它们之间的优先级关系。
而且自定义类型的<操作符与>操作符并无直接联系,故会编译不过。
//代码清单
#include
<
iostream
>
#include
<
functional
>
#include
<
queue
>

using
Namespace std
namespace std;
struct node
{
friend bool operator< (node n1, node n2)
{
return n1.priority < n2.priority;
}
int priority;
int value;
};
int main()
{
const int len = 5;
int i;
int a[len] = {3,5,9,6,2};
//示例1
priority_queue<int> qi;
for(i = 0; i < len; i++)
qi.push(a[i]);
for(i = 0; i < len; i++)
{
cout<<qi.top()<<" ";
qi.pop();
}
cout<<endl;
//示例2
priority_queue<int, vector<int>, greater<int> >qi2;
for(i = 0; i < len; i++)
qi2.push(a[i]);
for(i = 0; i < len; i++)
{
cout<<qi2.top()<<" ";
qi2.pop();
}
cout<<endl;
//示例3
priority_queue<node> qn;
node b[len];
b[0].priority = 6; b[0].value = 1;
b[1].priority = 9; b[1].value = 5;
b[2].priority = 2; b[2].value = 3;
b[3].priority = 8; b[3].value = 2;
b[4].priority = 1; b[4].value = 4; 
for(i = 0; i < len; i++)
qn.push(b[i]);
cout<<"优先级"<<'\t'<<"值"<<endl;
for(i = 0; i < len; i++)
{
cout<<qn.top().priority<<'\t'<<qn.top().value<<endl;
qn.pop();
}
return 0;
}优先队列:
虽然堆排序算法是一个非常漂亮的算法,但在实际中,快速排序的一个好的实现往往优于堆排序。尽管这样,堆这种数据结构还是有着很大的用处。一个很常见的应用就是作为优先级队列。和堆一样,队列也有最大优先队列和最小优先队列。
优先队列是用来维护一组元素集合S的数据结构,这一组元素中的每一个都有一个关键字key,一个最大优先队列支持如下的操作:
INSERT(S, x):把元素x插入到集合S中
MAXIMUM(S):返回集合中的最大元素
EXTRACT-MAX(S):去掉并且返回S中具有最大关键字的元素。
INCREASE-KEY(S, x, k):将元素x的关键字值增加到k,这里的k值不能小于x的原关键字值。
一个最小优先队列支持如下的操作:
INSERT(S, x):把元素x插入到集合S中
MINIMUN(S):返回集合S中的最小值
EXTRACT-MIN(S):去掉并且返回S中的最小关键字
DECREASE-KEY(S, x, k):将元素x的关键字值减小到k, 这里的k不能大于x.
对于用永真循环构造的消息循环,我们不能通过点击DOS窗口上的叉号来结束程序的运行,而要利用程序中的结束语句来执行,否则,虽然窗口关闭了,但是程序还在运行,我们只有重启计算机来终止程序的运行,如果程序中出现死循环的话,我们很可能无法在DOS界面下结束程序的运行,这时就会出现上述情况,目前我只知道关机来解决。
最大优先队列的源代码:
//最大优先队列的操作实现
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUM 100
//保持最大堆的属性
void max_heapify(int*, int, int);
//最大优先队列的建立
void build_max_queue(int*, int);
//返回优先队列中的最大值
int heap_maximum(int*);
//返回优先队列中的最大值,并且删除该最大值
int heap_extract_max(int*, int&);
//增加优先队列中某一个关键字的值
void heap_increase_key(int*, int, int);
//向优先队列中插入一个元素
void max_heap_insert(int*, int, int&);
int main()
{
int num[MAX_NUM + 10], n, i, max_num, elem, key;
char ch;
while(true)
{
do{
printf("\t\t***********max priority queue*************\n");
printf("\t\t*0.Build the maximum priority queue *\n");
printf("\t\t*1.Return the maximum of the queue *\n");
printf("\t\t*2.Return the maximum and delete it *\n");
printf("\t\t*3.Increase a certain key *\n");
printf("\t\t*4.Insert an element *\n");
printf("\t\t*5.Exit *\n");
printf("\t\t******************************************\n");
printf("\t\tPlease input your chioce(0-5): ");
scanf("%c", &ch);
fflush(stdin);
if(ch < '0' && ch > '5')
system("cls");
else
break;
}while(true);
switch(ch)
{
case '0':
printf("Please input the number if the elements in the queue: ");
scanf("%d", &n);
printf("Please input %d numbers with blank-space:\n", n);
for(i = 1; i <= n; ++i)
scanf("%d", num + i);
//优先队列的建立
build_max_queue(num, n);
printf("The elements of the priority are:\n", n);
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
fflush(stdin);
break;
case '1':
max_num = heap_maximum(num);
printf("The maximum of the queue is %d.\n", max_num);
break;
case '2':
max_num = heap_extract_max(num, n);
printf("The maximum of the queue is %d.\n", max_num);
printf("The elements of the queue are:\n");
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
break;
case '3':
printf("Please input the number of the key you want to increase: ");
scanf("%d", &i);
printf("Please input the key you want to incease: ");
scanf("%d", &key);
heap_increase_key(num, i, key);
printf("The elements of the queue are:\n");
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
fflush(stdin);
break;
case '4':
printf("Please input the element you want to insert: ");
scanf("%d", &elem);
max_heap_insert(num, elem, n);
printf("The elements of the queue are:\n");
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
fflush(stdin);
break;
case '5':
exit(0);
break;
}
}
return 0;
}
void max_heapify(int* num, int i, int n)
{
int l, r, largest;
l = 2 * i; //左孩子
r = 2 * i + 1; //右孩子
//左孩子中的关键字和父节点关键字比较取较大的关键字的编号
if(l <= n && num[l] > num[i])
largest = l;
else
largest = i;
//右孩子结点和上面较大的关键字的结点比较,取较大的关键结点的编号
if(r <= n && num[r] > num[largest])
largest = r;
if(largest != i)
{
int change_temp = num[i];
num[i] = num[largest];
num[largest] = change_temp;
max_heapify(num, largest, n);
}
}
void build_max_queue(int* num, int n)
{
int i;
for(i = n / 2; i >= 1; --i)
max_heapify(num, i, n);
}
int heap_maximum(int* num)
{
return num[1];
}
int heap_extract_max(int* num, int& n)
{
int max;
if(n < 1)
{
printf("heap underflow!\n");
exit(1);
}
max = num[1];
num[1] = num[n];
n = n - 1;
//堆的调整使其满足堆的属性
max_heapify(num, 1, n);
return max;
}
void heap_increase_key(int* num, int i, int key)
{
if(key < num[i])
{
printf("new key is smaller than current key!\n");
exit(1);
}
num[i] = key;
while(i > 1 && num[i] > num[i / 2])
{
int change_temp = num[i];
num[i] = num[i / 2];
num[i / 2] = change_temp;
i = i / 2;
}
}
void max_heap_insert(int* num, int elem, int& n)
{
n = n + 1;
//这里可能会存在bug,在实际中我们要给其赋值为负无穷大
num[n] = -9999999;
//利用关键字增加的函数来实现元素的插入
heap_increase_key(num, n, elem);
}
刚才花了大概两个小时的时间写了一份最小优先队列的代码,在这个过程中,我觉得一下几点需要自己以后注意:
1、 提示语太长,并且提示语中有输出参数时,我们一定要注意输出参数的变量的添加,特别是很长的输出提示语中就只有一个参数时。
2、 在循环语句中一定要注意语句的执行顺序问题,特别是清空缓冲区的语句,多加无害
3、 对于for循环,一定要弄明白循环变量是自增还是自减
4、 再次强调细节问题
最小优先队列的源代码如下:
//最小优先队列的相关操作
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUM 100
//保持最小堆的属性
void min_heapify(int*, int, int);
//最小优先队列的建立
void build_min_queue(int*, int);
//返回优先队列中的最小值
int heap_minimum(int*);
//返回队列中的最小值,并且将该最小值删除
int heap_extract_min(int*, int&);
//增加优先队列中的某一关键字的值
void heap_decrease_key(int*, int, int);
//向优先队列中插入一个元素
void min_heap_insert(int*, int, int&);
int main()
{
int num[MAX_NUM + 10], n, i, minimum, elem;
char ch;
while(true)
{
do{
printf("\t\t****************minimum priority queue*****************\n");
printf("\t\t*0.Build the minimum priority queue *\n");
printf("\t\t*1.Return the minimum element *\n");
printf("\t\t*2.Return the minimum element and delete it *\n");
printf("\t\t*3.Decrease a certain key *\n");
printf("\t\t*4.Insert an element *\n");
printf("\t\t*5.Exit *\n");
printf("\t\t*******************************************************\n");
printf("\t\tPlease input your choice(0-5): ");
scanf("%c", &ch);
fflush(stdin);
if(ch < '0' && ch > '5')
system("cls");
else
break;
}while(true);
switch(ch)
{
case '0':
printf("Please input the number of the elements: ");
scanf("%d", &n);
printf("Please input %d numbers with blank-space:\n", n);
for(i = 1; i <= n; ++i)
scanf("%d", num + i);
build_min_queue(num, n);
//一定要注意数组下标和元素编号之间的统一问题
printf("The elements of the queue are:\n");
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
printf("Press any key to continue......\n");
fflush(stdin);
ch = getchar();
fflush(stdin);
system("cls");
break;
case '1':
minimum = heap_minimum(num);
printf("The minimum element is %d.\n", minimum);
printf("Press any key to continue......\n");
ch = getchar();
fflush(stdin);
system("cls");
break;
case '2':
minimum = heap_extract_min(num, n);
printf("The minimum element is %d.\n", minimum);
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
printf("Press any key to continue......\n");
ch = getchar();
fflush(stdin);
system("cls");
break;
case '3':
printf("Please input the number of the element you want to increase: ");
scanf("%d", &i);
printf("Please input the element you want to decrease to: ");
scanf("%d", &elem);
heap_decrease_key(num, i, elem);
fflush(stdin);
printf("The elements of the queue are:\n");
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
printf("Press any key to continu......\n");
ch = getchar();
fflush(stdin);
system("cls");
break;
case '4':
printf("Please input the element you want to insert: ");
scanf("%d", &elem);
min_heap_insert(num, elem, n);
printf("The elements of the queue are:\n");
for(i = 1; i <= n; ++i)
printf("%d ", num[i]);
printf("\n");
fflush(stdin);
printf("Press any key to conitinue......\n");
ch = getchar();
system("cls");
fflush(stdin);
break;
case '5':
exit(0);
break;
default:
break;
}
}
return 0;
}
//保持最小堆的属性
void min_heapify(int* num, int i, int n)
{
int l, r, smallest;
l = 2 * i;
r = 2 * i + 1;
if(l <= n && num[i] > num[l])
smallest = l;
else
smallest = i;
if(r <= n && num[smallest] > num[r])
smallest = r;
if(smallest != i)
{
int change_temp = num[i];
num[i] = num[smallest];
num[smallest] = change_temp;
min_heapify(num, smallest, n);
}
}
//最小优先队列的建立
void build_min_queue(int* num, int n)
{
int i;
for(i = n / 2; i >= 1; --i)
min_heapify(num, i, n);
}
//返回优先队列中的最小值
int heap_minimum(int* num)
{
return num[1];
}
//返回队列中的最小值,并且将该最小值删除
int heap_extract_min(int* num, int& n)
{
int minimum;
if(n < 1)
{
printf("heap underflow.\n");
exit(1);
}
minimum = num[1];
num[1] = num[n];
n = n - 1;
min_heapify(num, 1, n);
return minimum;
}
//增加优先队列中的某一关键字的值
void heap_decrease_key(int* num, int i, int elem)
{
if(num[i] < elem)
{
printf("New key is larger than current key.\n");
return;
}
num[i] = elem;
while(i > 1 && num[i / 2] > num[i])
{
int change_temp = num[i];
num[i] = num[i / 2];
num[i / 2] = change_temp;
i = i / 2;
}
}
//向优先队列中插入一个元素
void min_heap_insert(int* num, int elem, int& n)
{
n = n + 1;
num[n] = 999999;
heap_decrease_key(num, n, elem);
本文介绍了优先队列的基本概念及其在C++中的实现方法。详细解释了如何使用标准库中的priority_queue,包括三种常见用法:默认按大小排序、自定义排序函数及自定义数据结构的优先级比较。同时提供了最大优先队列和最小优先队列的源代码示例。
1008

被折叠的 条评论
为什么被折叠?



