zoukankan      html  css  js  c++  java
  • 浅谈数据结构之顺序队列(五)

      队列:是指只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种先进先出的线性表,这与栈的后进先出正好相反;其中允许插入的一端我们称为队尾,允许删除的一端我们称为队头(或队首)。假设队列Q=(a1,a2,......an),那么a1就是队头元素,an就是队尾元素;我们删除数据时,总是从队头元素a1开始,而插入数据时,则是从队尾元素an后面开始插入,这也比较符合我们生活中的习惯,排在第一的当然优先出列,后来的当然排在队伍的后面。

      线性表有顺序存储和链式存储,栈是线性表,所以也有这两种存储方式。同样的,队列作为一种特殊的线性表,也有这两种存储方式。下面,我们先来看看队列的顺序存储结构。

      我们假设一个队列有n个元素,则顺序存储的队列需要建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元中,数组下标为0的一端即为队首。所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此它的时间复杂度为0(1)。与栈不同的是,队列元素的出队列在队头,这也就意味着,队列中所有元素都得向前移动,以保证队列队头元素不为空,即数组下标为0的位置不为空,此时的时间复杂度为0(n)。在现实中也是如此,比如说一群人在排队买票,前面的人买好了票就离开,后面的人则向前一步,补上前面的空位。

      通常我们为了避免当只有一个元素时,队头与队尾重合使操作变得麻烦,所以引入了两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front=rear时,此队列不是只剩下一个元素,而是一个空队列。若设队列的长度为QueueSize,则通用的计算队列的长度公式为:(rear-front+QueueSize)%QueueSize。接下来我们重点看一下队列的插入、删除等操作是怎样实现的,具体操作源程序代码如下所示:

      1 #include <stdio.h>
      2 #include <stdlib.h> 
      3 
      4 #define OK 1
      5 #define ERROR 0
      6 #define TRUE 1
      7 #define FALSE 0
      8 
      9 #define MAXSIZE 10                /* 存储空间初始分配量 */
     10 
     11 typedef int Status; 
     12 typedef int QElemType;             /* QElemType类型根据实际情况而定,这里假设为int */
     13 
     14 /* 循环队列的顺序存储结构 */
     15 typedef struct
     16 {
     17     QElemType data[MAXSIZE];
     18     int front;                   /* 头指针 */
     19     int rear;                    /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
     20 }SqQueue;
     21 
     22 Status visit(QElemType c)
     23 {
     24     printf("%d ",c);
     25     return OK;
     26 }
     27 
     28 /* 初始化一个空队列Q */
     29 Status InitQueue(SqQueue *Q)
     30 {
     31     Q->front=0;
     32     Q->rear=0;
     33     return  OK;
     34 }
     35 
     36 /* 将Q清为空队列 */
     37 Status ClearQueue(SqQueue *Q)
     38 {
     39     Q->front=Q->rear=0;
     40     return OK;
     41 }
     42 
     43 /* 返回Q的元素个数,也就是队列的当前长度 */
     44 int QueueLength(SqQueue Q)
     45 {
     46     return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
     47 }
     48 
     49 /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
     50 Status GetHead(SqQueue Q,QElemType *e)
     51 {
     52     if(Q.front==Q.rear)     /* 队列空 */
     53         return ERROR;
     54     *e=Q.data[Q.front];
     55     return OK;
     56 }
     57 
     58 /* 若队列未满,则插入元素e为Q新的队尾元素 */
     59 Status EnQueue(SqQueue *Q,QElemType e)
     60 {
     61     if ((Q->rear+1)%MAXSIZE == Q->front)    /* 队列满的判断 */
     62         return ERROR;
     63     Q->data[Q->rear]=e;                     /* 将元素e赋值给队尾 */
     64     Q->rear=(Q->rear+1)%MAXSIZE;            /* rear指针向后移一位置, */
     65                                             /* 若到最后则转到数组头部 */
     66     return  OK;
     67 }
     68 
     69 /* 若队列不空,则删除Q中队头元素,用e返回其值 */
     70 Status DeQueue(SqQueue *Q,QElemType *e)
     71 {
     72     if (Q->front == Q->rear)                /* 队列空的判断 */
     73         return ERROR;
     74     *e=Q->data[Q->front];                   /* 将队头元素赋值给e */
     75     Q->front=(Q->front+1)%MAXSIZE;          /* front指针向后移一位置, */
     76                                             /* 若到最后则转到数组头部 */
     77     return  OK;
     78 }
     79 
     80 /* 从队头到队尾依次对队列Q中每个元素输出 */
     81 Status QueueTraverse(SqQueue Q)
     82 { 
     83     int i;
     84     i=Q.front;
     85     while((i+Q.front)!=Q.rear)
     86     {
     87         visit(Q.data[i]);
     88         i=(i+1)%MAXSIZE;
     89     }
     90     printf("
    ");
     91     return OK;
     92 }
     93 
     94 int main()
     95 {    
     96     SqQueue Q;
     97     QElemType e;
     98     Status i;
     99     int j,k=0;
    100 
    101     i=InitQueue(&Q);
    102     printf("1.初始化队列Q后,队列Q的长度为:Q.length=%d
    ",QueueLength(Q));
    103     
    104     printf("2.请输入整型队列元素(不超过%d个),-1为提前结束符: 
    ",MAXSIZE-1);
    105     do
    106     {
    107         e=k+10;
    108         if(e==-1)
    109             break;
    110         k++;
    111         EnQueue(&Q,e);
    112     }while(k<MAXSIZE-1);
    113     
    114     printf("3.连续%d次由队头删除元素,队尾插入元素:
    ",MAXSIZE);
    115     for(j=1;j<=MAXSIZE;j++)
    116     {
    117         DeQueue(&Q,&e);
    118         printf("删除的元素是%d,插入的元素:%d 
    ",e,j+100);
    119         e=j+100;
    120         EnQueue(&Q,e);
    121     }
    122 
    123     printf("4.现在队列中的元素为: 
    ");
    124     QueueTraverse(Q);
    125     
    126     printf("5.现在队列Q的长度为:Q.length=%d
    ",QueueLength(Q));
    127  
    128     DeQueue(&Q,&e);
    129     printf("6.在队列Q的队头处删除元素后:Q.data=");
    130     QueueTraverse(Q); 
    131     
    132     GetHead(Q,&e);
    133     printf("7.现在队列Q的队头元素是:%d
    ",e); 
    134      
    135     i=ClearQueue(&Q);
    136     printf("8.将队列Q清空后,队列Q的长度为:Q.length=%d
    ",QueueLength(Q));
    137      
    138     return 0;
    139 }
  • 相关阅读:
    MySQL与SQLServer的语法区别
    Linux系统ELK环境搭建
    springboot_yml配置, 以及 properties 和yml转换示例
    mybatis-plus的 mapper.xml 路径配置问题
    Windows下 启动redis
    Mysql 创建库,删除库 命令,脚本
    mybatis中传入多个参数时,接口调用报错Parameter '*****' not found ...
    构建启动Vue项目
    HyperLedger/Fabric区块连网络-编译启动单节点
    HyperLedger/Fabric区块连网络 死磕fabric
  • 原文地址:https://www.cnblogs.com/mix88/p/6171799.html
Copyright © 2011-2022 走看看