关于队列的学习

原创博文,转载请注明出处。

队列也是一种线性表,但是只允许在表的一端进行插入,而在表的另一端进行删除。其操作特性是先进先出。队列常应用在在层次遍历中(如对二叉树的遍历),计算机系统中,也常用来解决如主机与外部设备之间速度不匹配的问题,和由多用户引起的资源竞争问题。

队头(front):允许删除的一端,又称队首。

队尾(rear): 允许插入的一端。

空队列:不含任何元素的空表。

队列的顺序存储 比较简单,下面我们学习一下队列的链式存储结构。

队列的链式存储类型可描述为

1 typedef struct{                       //链式队列节点
2           ElemType data:
3           struct LinkNode *next;
4     }LinkNode;
5 typedef struct{                    //链式队列
6           LinkNode *front, *rear;
7 }LinkQueue

当Q.front,Q.rear==NULL时,链式队列为空。为了方便插入和删除操作,通常将链式队列设计成一个带头结点的单链表。

链式队列的基本操作:

(1)初始化

void InitQueue(LinkQueue &Q){
        Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));
        Q.front->next = NULL;
}

(2)判队空

bool IsEmpty(LinkQueue Q){
        if(Q.front = = Q.rear) return true;
        else return false;  
}

(3)入队

void EnQueue(LinkQueue &Q,ElemType x){
         s=(LinkNode *)malloc(sizeof(LinkNode));
         s->data=x;s->next=NULL;
         Q.rear->next=s;
         Q.rear=s;
}

(4)出队

bool DeQueue(LinkQueue &Q,ElemType &x){
        if(Q.front==Q.rear) return false;//空队
        p=Q.front; //让头元素指向p
        x=p->data;
        Q.front->next=p->next;
        if(Q.rear==p)
            Q.rear==Q.front; //若原队列中只有一个结点,删除后变空
        free(p);
        return true;
}

1、如果希望循环队列中的元素都能得到利用,则需要设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的队列状态是“空”还是“满”。使编写此结构相应的入队和出队算法。

在循环队列的类型结构中,增设一个tag的整型变量,进队时设置为1,出队时设置为0。初始时,设置为tag=0,front=0,rear=0.

队空条件:Q.front ==Q.rear 且tag==0。

队满条件: Q.front == Q.rear且tag==1。

入队操作:Q.data[Q.rear]=x;Q.rear=(Q.rear+1)/MaxSize;Q.tag=1。

出队操作: x=Q.data[Q.front];Q.front=(Q.front+1)/MaxSize;Q.tag=0。

2、Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。

只是对队列的一系列操作是不可能将其中的元素逆置的,所以我们可以借助栈来存储队列中的元素。

void Inverser(Stack S, Queue Q){
        while(Q.front!=Q.rear){     //将队列中的元素逐个地出队列,入栈
                x=DeQueue(Q);
               Push(S,x);
    }
        while(S.top!=-1){      //逐个出栈,然后入队列
              Pop(S,x);
              EnQueue(Q,x);
    }  
}

 3、利用两个栈 S1 、S2 来模拟一个队列,已知栈的4个运算定义如下:

Push(S,x);      //元素x入栈S
Pop(S,x);       //S出栈并将出栈的值赋给x
StackEmpty(S);  //判断栈是否为空
StackOverflow(S); //判断栈是否满

那么如何利用栈的运算来实现该队列的3个运算:

Enqueue;   //将元素x入队
Dequeue;   //出队,并将出队元素存储在x中
QueueEmpty;  //判断队列是否为空 

利用两个栈S1和S2 来模拟一个队列,当需要想队列中插入一个元素时,用S1存放已输入的元素,即S1 执行入栈操作。当需要出队时,则对S2执行出栈操作。由于从栈中取出元素的顺序是原顺序的逆序,所以,必须将S1 中所有元素全部出栈并入栈到S2中,再在S2 中执行出栈操作,即可实现出队操作。因此,在执行操作前必须判断S2 是否为空,否则会导致顺序混乱。当栈S1和S2都为空时,队列为空。

总结如下:

(1)对S2的出栈操作用出队,若S2 为空,则先将S1 中的所有元素送入S2 。

(2)对S1的入栈操作用入队,若S1满,必须先保证S2 为空,才能将S1中的元素全部插入到S2中去。

入队算法:

int EnQueue(Stack S1,Stack S2,ElemType e){
      if(!StackOverflow(S1)){
                Push(S1,x);
                return 1;
          } 
      if(StackOverflow(S1)&&!StackEmpty(S2)){
               return 0;
          }
     if(StackOverflow(S1)&&StackEmpty(S2)){    //S1满 S2空
                while(!StackEmpty(S1)){
                        Pop(S1,x);
                        Push(S2,x);
               }
          }     
     Push(S1,x);
     return 1;
}

出队算法:

void DeQueue(Stack S1,Stack S2,ElemType &x){
          if(!StackEmpty(S2)){
               Pop(S2,x);
       }
          else if(StackEmpty(S1){
               printf("队列为空");
      }
         else{
               while(!StackEmpty(S1)){
                     Pop(S1,x);
                     Push(S2,x);
           }
             Pop(S2,x);
       }
}

判断列队为空的算法:

int QueueEmpty(Stack S1,Stack S2){
        if(StackEmpty(S1)&&StackEmpty(S2))
               return 1;
        else
              return 0;
}

4、某汽车轮渡口,过江渡船每次能载10辆车过江。过江车辆分为客车类和货车类,上渡船有如下规定:同类车先到先上船;客车先于货车上渡船,且每上4辆客车,才允许放上一辆货车;若等待客车不足4辆,则以货车代替;若无货车等待,才允许客车都上船。设设计一个算法模拟渡口管理。

算法思想:我们可以设定三个队列,Q 是每次载渡的队列,长度为10。Q1 和Q2 分别是客车和货车的等待队列。若Q1>4,则每取4个Q1元素后再取一个Q2元素,直到Q长度为10。若Q1<4,则直接用Q2补齐。算法实现如下:

void manager(Queue q,Queue q1,Queue q2){
          int i=0,j=0;  //i代表渡船上客车的数量 j代表渡船上总车辆数
          while(j<10){
               if(!QueueEmpty(q1)&&i<4){ //客车队列非空,且未上满4辆
                  DeQueue(q1,x);
                  EnQueue(q,x);
                  j++;
                  i++;
          }
              else if(i==4&&!QueueEmpty(q2)){ //客车已上满4辆
                  DeQueue(q2,x);
                  EnQueue(q,x);
                  j++;
                  i=0;
          }
             else{
                 while(i<4&&!QueueEmpty(q2)){ //客车队列空,且未上满4辆
                   DeQueue(q2,x);
                   EnQueue(q,x);
                   j++;
                   i++;
               }
              i=0;
          }
          if (QueueEmpty(q1)&&QueueEmpty(q1))
              j=11;
    }
}

 

 

 

posted @ 2013-12-05 15:48  枫桦宁  阅读(1847)  评论(0编辑  收藏  举报