优先队列

本文介绍了优先队列的基本概念及其在C++中的实现方法。详细解释了如何使用标准库中的priority_queue,包括三种常见用法:默认按大小排序、自定义排序函数及自定义数据结构的优先级比较。同时提供了最大优先队列和最小优先队列的源代码示例。

在优先队列中,优先级高的元素先出队列。
标准库默认使用元素类型的<操作符来确定它们之间的优先级关系。
优先队列的第一种用法,也是最常用的用法:

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);

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值