队列的基础知识和应用

1.概念

队列是一种特殊的线性表,只能在前端(front)进行删除操作,只能在后端(rear)进行删除操作;1

进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

–队尾(rear)——允许插入的一端
–队头(front)——允许删除的一端
队列特点:先进先出First in first out(FIFO)

2.分类

队列分为顺序队列和循环队列;

顺序队列:

每次插入,指针rear(队尾)加一,每次删除,指针front(队头)加一;

循环队列:

初始化时,rear = front=0,当队列不为空时,front指向队列中的第一个元素,rear指向队列中最后一个元素的下一个位置,当队列满时 rear=front,但不一定是位置0;

插入后rear+1,删除后front+1,但是,无论是删除还是插入,一旦rear或front加一超过了所分配的空间,则让指针指向这片空间的起始位置;设所分配的空间为Maxsize,一旦rear+1,或front+1 =Maxsize, 则rear或front指向起始位置。

因此,循环序列判空的方法是rear = front; 判满的方法是 (rear+1)%Maxsize ==front;

进队列步骤: 

1.判断队列是否满,即,rear+1是否等于front,若等于则队列已满,不允许进入;

2. 若不满,则将值保存至rear+1的位置 ; 从这里也可以看出,循环数列所能存储的值其实是最大值-1。

void EnQueue(Queue *Q, int key)
{

        if ( (Q->rear+1) % Q->maxsize == Q->front)                   //此时队列没有空间       取余保证,当quil=queuesize-1时,再转回0
        {
            printf("the queue has been filled full!");
        }
        else
        {
          Q->q[Q->rear] = key;

            Q-> rear =(Q->rear+1) % Q->maxsize;
        }
}

出队列步骤

1.判断数列是否为空; 

2, 将front现在的时间表保存至temp;

 3,将front指针后移一个;

4. 返回temp;

int DeQueue(Queue *Q)
{
        int tmp;
        if(Q->rear== Q->front)     //判断队列不为空
        {
            printf("the queue is NULL\n");
        }
        else
        {
            tmp = Q->q[q->front];
            Q->front= (Q->front+1) % Q->maxsize;
        }
        return tmp;

}

3.应用

栈和队列的应用

  在日常生活中,很多问题可以归结到栈和队列的应用问题。例如,排队购物的现象就可以看做是队列。在计算机学科的应用中,栈和队列的应用就更多了,例如,编译系统、消息队列等。

 栈的应用

  栈具有相当广泛的实际应用,例如,可以颠倒数据串的次序、为回溯算法提供支持、实现自动机等。
  1.编译应用
  栈可以应用于括号匹配、行编辑器、表达式求值、算法优先文法等编译程序中。例如,在表达式中,一般存在大、中、小三种括号,分别定义为“{}”、“[]”和“()”,要求其只能自我匹配,不能交互匹配,比如“{[()]}”、“[()()()]”等均为正确匹配,而“({]”、“(])[”、“)(]}”等均为错误匹配。

  2.转置应用
  一串数据全部进入栈后再全部出栈,将得到一个次序完全相反的数据串,这是栈的特性之一。因此,栈可以应用于转置操作,例如,数的进制转换等。
  例子:已知线性链表L,请按从表尾到表头的顺序输出元素。
  【解析】从头到尾遍历链表,同时将链表元素入栈,再依次出栈,并打印元素信息即可。

  3.迷宫问题
  迷宫问题是指在迷宫中从入口寻找出口的问题。此类问题的本质是将迷宫建模成图,将迷宫中的点建模为图中的点,将迷宫中相连并且相通的两点建模为图中的一条边,一般采用矩阵方式存储图,这样迷宫求解就转化为图的遍历,采用回溯法穷举所有从入口点到出口点之间的路径即可。
  迷宫问题求解算法中一般使用一个栈来存储访问过的顶点信息,栈中元素(即顶点信息)由顶点位置和搜索方向两部分组成,前者记载该顶点在迷宫中的位置,后者记载下一个顶点的访问方向,例如,右、下、左、上四个相连的方向,编程时可分别使用枚举类型enum表示。

队列的应用

  队列是一种相当实用的数据结构,可应用于生产、生活的各个方面,例如,共享打印机、消息队列和广度优先搜索等。
  1.共享打印机
  目前,打印机提供的网络共享打印功能采用了缓冲池技术,队列就是实现这个缓冲技术的数据结构支持。每台打印机具有一个队列(缓冲池),用户提交打印请求被写入到队列尾,当打印机空闲时,系统读取队列中第一个请求,打印并删除之。这样,利用队列的先进先出特性,就可完成打印机网络共享的先来先服务功能。
  2.消息队列
  操作系统中的消息队列也是队列的应用之一,消息队列遵循先进先出的原则,如图2-5所示,发送进程将消息写入队列尾,接收进程则从队列头读取消息。

舞伴问题

1、问题叙述
 假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。若两队初始人数不相同,则较长的那一队中未配对者,等待下一轮舞曲。现要求写一算法模拟上述舞伴配对问题。

2、问题分析
 先入队的男士或女士亦先出队配成舞伴。因此该问题具体有典型的先进先出特性,可用队列作为算法的数据结构。
 在算法中,假设男士和女士的记录存放在一个数组中作为输入,然后依次扫描该数组的各元素,并根据性别来决定是进入男队还是女队。当这两个队列构造完成之后,依次将两队当前的队头元素出队来配成舞伴,直至某队列变空为止。此时,若某队仍有等待配对者,算法输出此队列中等待者的人数及排在队头的等待者的名字,他(或她)将是下一轮舞曲开始时第一个可获得舞伴的人。

3、具体算法及相关的类型定义  
  view plain  co
#include 
using namespace std;
typedef struct
{
  char name[20];
  char sex; //性别,'F'表示女性,'M'表示男性
} Person;

void DancePartner(Person dancer[],int num)
{
  //结构数组dancer中存放跳舞的男女,num是跳舞的人数。

  Person p;
  queue Mdancers,Fdancers;

  for(int i = 0; i < num; i++)
    {
      //依次将跳舞者依其性别入队
      p=dancer[i];
      if(p.sex=='F')
        Fdancers.push(p); //排入女队
      else
        Mdancers.push(p); //排入男队
    }
  printf("跳舞的伙伴是: \n \n");
  while(!(Fdancers.empty()||Mdancers.empty()))
    {
      //依次输入男女舞伴名
      p=Fdancers.front();     //获取女队第一人
      Fdancers.pop();         //出队
      printf("%s ",p.name);   //打印出队女士名

      p=Mdancers.front();     //获取男队第一人
      Mdancers.pop();         //出队
      printf("%s\n",p.name);  //打印出队男士名
    }
  if(!Fdancers.empty())
    {
      //输出女士剩余人数及队头女士的名字
      printf("\n 有 %d 个女人等下一轮\n",Fdancers.size());
      p=Fdancers.front(); //取队头
      printf("%s 将是第一个得到伙伴的\n",p.name);
    }
  else if(!Mdancers.empty())
    {
      //输出男队剩余人数及队头者名字
      printf("\n有%d个男人等下一轮\n",Mdancers.size());
      p=Mdancers.front();
      printf("%s将是第一个得到伙伴的\n",p.name);
    }
  else
    {
      printf("没有人在队列里了!");
    }
}//DancerPartners

int main()
{
  Person p[] = {{"A",'F'},{"B",'F'},{"C",'M'},{"D",'M'},{"E",'M'}};
  DancePartner(p,5);
}

你可能感兴趣的:(C++基础学习)