数据结构与算法(6)- 队列

369 阅读4分钟

一.队列的类型定义

队列的操作与栈的操作类似,不同的是,删除在表的头部(即队头)进行。特点是“先进先出”。

二.队列的顺序表示和实现

  • 顺序分配的队列中头指针(Q.front)、尾指针(Q.rear)和元素之间的关系如下图:

假设当前队列分配的最大空间为MAXQSIZE(图中为6),在d所示的状态不可再继续插入新元素,否则会出现溢出现象,实际上此时队列的可用空间并未占满,这种现象称为“假溢出”。这种现象的出现,主要是由“队尾出队,队头出队”的操作造成。

1.循环队列

为了解决“假溢出”问题,将顺序队列变为一个环状空间,即“循环队列”。 头、尾指针以及队列元素之间的关系不变,在循环队列中,头、尾指针“依环状增1”的操作可用“模”运算来实现,通过取模,头指针和尾指针就可以在顺序表空间内以头尾衔接的方式“循环”移动。

循环队列中头指针(Q.front)、尾指针(Q.rear)和元素之间的关系如下图:

  • a. 队头元素是J5,在元素J6入队之前,Q.rear的值为5,当元素J6入队之后,通过“模”运算,Q.rear = (Q.rear+1) % MAXQSIZE; 即Q.rear = 0;此时不会出现“假溢出”
  • b. J7,J8,J9,J10相继入队,队满,此时头尾指针相同
  • c. 空队列,头、尾指针相同

由此可见,循环队列不能以头、尾指针的值是否相同来区分队列空间是“满”还是“空”。

解决办法: 少用一个元素空间,即队列空间大小为m时,有m-1个元素就认为是队满。

  • d. 当J7,J8,J9入队后,(Q.rear +1)%MAXQSIZE 的值等于Q.front,此时认为队满。

2.结构定义

#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int QElemType; 
typedef struct
{
    QElemType data[MAXSIZE];
    int front;        /* 头指针 */
    int rear;        /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;

3.基本实现

Status InitQueue(SqQueue *Q){
    Q->front = 0;
    Q->rear = 0;
    return OK;
}
Status ClearQueue(SqQueue *Q){
    Q->front = Q->rear = 0;
    return OK;
}
Status QueueEmpty(SqQueue Q){
    if (Q.front == Q.rear)
        return TRUE;
    else
        return FALSE;
}
int QueueLength(SqQueue Q){
    return (Q.rear - Q.front + MAXSIZE)%MAXSIZE;
}
Status GetHead(SqQueue Q,QElemType *e){
    if (Q.front == Q.rear)
        return ERROR;
    *e = Q.data[Q.front];
    return OK;
}
Status EnQueue(SqQueue *Q,QElemType e){
    if((Q->rear+1)%MAXSIZE == Q->front)
        return ERROR;
    Q->data[Q->rear] = e;
    Q->rear = (Q->rear+1)%MAXSIZE;
    return OK;
}
Status DeQueue(SqQueue *Q,QElemType *e){
    if (Q->front == Q->rear) {
        return ERROR;
    }
    *e = Q->data[Q->front];
    Q->front = (Q->front+1)%MAXSIZE;
    return OK;
}
Status QueueTraverse(SqQueue Q){
    int i;
    i = Q.front;
    while (i != Q.rear) {
        printf("%d   ",Q.data[i]);
        i = (i+1)%MAXSIZE;
    }
    printf("\n");
    return OK;
}
int main(int argc, const char * argv[]) {
    Status j;
    int i=0;
    QElemType d;
    SqQueue Q;
    InitQueue(&Q);
    printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
    printf("入队:\n");
    while (i < 10) {
        EnQueue(&Q, i);
        i++;
    }
    QueueTraverse(Q);
    printf("队列长度为: %d\n",QueueLength(Q));
    printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
    printf("出队:\n");
    DeQueue(&Q, &d);
    printf("出队的元素:%d\n",d);
    EnQueue(&Q, 10);
    QueueTraverse(Q);
    j=GetHead(Q,&d);
    if(j)
        printf("现在队头元素为: %d\n",d);
    ClearQueue(&Q);
    printf("清空队列后, 队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
    return 0;
}

三.队列的链式表示和实现

1.结构定义

#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
typedef struct QNode
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
    QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;

2.基本操作

Status InitQueue(LinkQueue *Q){
    Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
    if (!Q->front) {
        return ERROR;
    }
    Q->front->next = NULL;
    return OK;
}
Status DestoryQueue(LinkQueue *Q){
    while (Q->front) {
        Q->rear = Q->front->next;
        free(Q->front);
        Q->front = Q->rear;
    }
    return OK;
}
Status ClearQueue(LinkQueue *Q){
    QueuePtr p,q;
    Q->rear = Q->front;
    p = Q->front->next;
    Q->front->next = NULL;
    while (p) {
        q = p;
        p = p->next;
        free(q);
    }
    return OK;
}
Status QueueEmpty(LinkQueue Q){
    if (Q.front == Q.rear)
        return TRUE;
    else
        return FALSE;
}
int QueueLength(LinkQueue Q){
    int i= 0;
    QueuePtr p;
    p = Q.front;
    while (Q.rear != p) {
        i++;
        p = p->next;
    }
    return i;
}
Status EnQueue(LinkQueue *Q,QElemType e){
    QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
    if (!s) {
         return ERROR;
    }
    s->data = e;
    s->next = NULL;
    Q->rear->next = s;
    Q->rear = s;
    return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e){
    QueuePtr p;
    if (Q->front == Q->rear) {
        return ERROR;
    }
    p = Q->front->next;
    *e = p->data;
    Q->front->next = p ->next;
    if(Q->rear == p) Q->rear = Q->front;
    free(p);
    return OK;
}
Status GetHead(LinkQueue Q,QElemType *e){
    if (Q.front != Q.rear) {
        *e =  Q.front->next->data;
        return TRUE;
    }
    return  FALSE;
}
Status QueueTraverse(LinkQueue Q){
    QueuePtr p;
    p = Q.front->next;
    while (p) {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
    return OK;
}
int main(int argc, const char * argv[]) {
    Status iStatus;
    QElemType d;
    LinkQueue q;
    iStatus = InitQueue(&q);
    if (iStatus) {
        printf("成功地构造了一个空队列\n");
    }
    printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));
    printf("队列的长度为%d\n",QueueLength(q));
    EnQueue(&q, -3);
    EnQueue(&q, 6);
    EnQueue(&q, 12);
    printf("队列的长度为%d\n",QueueLength(q));
    printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));
    printf("队列中的元素如下:\n");
    QueueTraverse(q);
    iStatus = GetHead(q, &d);
    if (iStatus == OK) {
        printf("队头元素是:%d\n",d);
    }
    iStatus =DeQueue(&q, &d);
    if (iStatus == OK) {
        printf("删除了的队头元素为:%d\n",d);
    }
    iStatus = GetHead(q, &d);
    if (iStatus == OK) {
        printf("新的队头元素为:%d\n",d);
    }
    ClearQueue(&q);
    DestoryQueue(&q);
    return 0;
}