数据结构——队列

1.定义

队列(queue)是只允许在一端进行插入操作、另一端进行删除操作的线性表。先进先出,插入端为队尾;删除端为队头。
队列作为一种特殊的线性表,也具有顺序结构和链式结构

2.循环队列

循环队列:队列的头尾相接的顺序存储结构称为循环队列。使用循环队列是为了避免队列空间浪费、插入删除之后队头队尾指针操作不便等情况。
循环队列的顺秀结构如下:

//循环队列的顺序存储结构
typedef struct  
{
    QElemType data[MAXSIZE];
    int front;      //头指针,指向下标为0
    int rear;       //尾指针,若队列不为空,指向队尾元素的下一个位置

}SqQueue;

循环队列的头指针rear指向下标为0的位置,尾指针,指向最后一个元素的下一个位置。
注意:由于是循环队列,元素下标会因为循环而不断增加,但数组长度固定,因此计算队列中的元素个数、队列长度、判断是否队满等都需要对MAXSIZE取余。
①循环队列判断队满的条件:(rear+1)%MAXSIZE==front
②循环队列求队列长度:(rear-front +MAXSIZE)%MAXSIZE.

/************************************************************************/
/*          顺序队列                                                                     */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <math.h>
#include <time.h>

#define OK 1
#define  ERROR 0
#define  TRUE 1
#define  FALSE 0
#define MAXSIZE 20      //存储空间初始分配量

typedef int Status;
typedef int QElemType;  //队列元素的类型,此处定义为int

//循环队列的顺序存储结构
typedef struct  
{
    QElemType data[MAXSIZE];
    int front;      //头指针,指向下标为0
    int rear;       //尾指针,若队列不为空,指向队尾元素的下一个位置

}SqQueue;

Status visitSqQueue(QElemType c)
{
    printf("%d",c);
    return OK;
}

//初始化一个空的循环队列
Status InitQueue(SqQueue *Q)
{
    Q->front =0;
    Q->rear =0;
    return OK;
}

//将队列Q清为空队列
Status ClearQueue(SqQueue *Q)
{
    Q->front =Q->rear =0;
    return OK;
}

//判断队列是否为空队列,若为空,返回TRUE;否则返回FALSE
Status isEmptyQueue(SqQueue Q)
{
    if (Q.front==Q.rear)
        return TRUE;
    else 
        return FALSE;

}

//返回Q中元素的个数,即队列长度
int QueueLength(SqQueue Q)
{
    return (Q.rear - Q.front + MAXSIZE)%MAXSIZE;
}


//若队列不为空,用e返回Q的队头元素,并返回OK;否则返回ERROR
Status GetHead(SqQueue Q, QElemType *e)
{
    if (isEmptyQueue(Q))
        return ERROR;

    *e = Q.data[Q.front];
    return OK;
}

//若队列未满,则插入元素e为Q的新的队尾元素
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;       //先给rear位置赋值,然后将rear指针后移一位,要考虑是循环队列,所以要对MAXSIZE取余
    return OK;

}

//若队列不为空,删除队头元素用e表示
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;

}

//从队头到队尾,一次对Q中的每个元素输出
Status QueueTraverse(SqQueue Q)
{
    int i=Q.front;
    while(i!=Q.rear)
    {
        printf("%d ",Q.data[i]);
        i=(i+1)%MAXSIZE;
    }
    printf("\n");
    return OK;
}


int main()
{
    Status j;
    int i=0;
    int l;
    QElemType d;
    SqQueue Q;

    InitQueue(&Q);
    printf("初始化队列后,队列是否为空?%u(1:空;0:否)\n",isEmptyQueue(Q));

    printf("请输入整型队列元素(不超过%d个),-1为提前结束符\n",MAXSIZE-1);
    do 
    {
        d=i+100;
        if (d==-1)
            break;
        i++;
        EnQueue(&Q,d);

    } while (i<MAXSIZE-1);

    printf("队列长度为:%d\n",QueueLength(Q));
    printf("初始化队列后,队列是否为空?%u(1:空;0:否)\n",isEmptyQueue(Q));
    QueueTraverse(Q);


    printf("连续%d次由队头删除元素,队尾插入元素:\n",MAXSIZE);
    for (l=1;l<=MAXSIZE;l++)
    {
        DeQueue(&Q,&d);
        printf("删除的元素是%d,插入的元素是%d\n",d, l+1000);
        d=l+1000;
        EnQueue(&Q, d);
    }

    printf("连续插入和删除之后,现在队列长度为%d\n",QueueLength(Q));
    QueueTraverse(Q);
    printf("共向队尾插入了%d个元素\n",i+MAXSIZE);
    if (l-2>0)
    {
        printf("现在由队头插入了%d个元素\n",l-2);
    }


    j=GetHead(Q,&d);
    if (j)
    {
        printf("现在的队头元素为:%d\n",d);
    }

    ClearQueue(&Q);
    printf("初始化队列后,队列是否为空?%u(1:空;0:否)\n",isEmptyQueue(Q));

    getchar();

}

3、队列的链式存储——链队列

链队列是一种特殊的链式存储的线性表。只能尾进头出。
①有头结点,②front指针指向头结点;③rear指针指向最后一个结点。④若是空的链队列,则只有头结点,且front和rear指针同时指向头结点。
链队列结构中,除了链表的基本结构定义,链队列结构中,仅包含链表结构的front和rear指针。

//定义链队列结构
struct QNode
{
    QElemType data;
    struct QNode *next;
};

typedef struct QNode QNode;
typedef struct QNode* QueuePtr;

typedef struct
{
    QueuePtr front;     //只需定义链队列的头指针和尾指针
    QueuePtr rear;

}LinkQueue;

/************************************************************************/
/*    链队列:队列的链式存储结构                                                                     */
/************************************************************************/

//定义链队列结构
struct QNode
{
    QElemType data;
    struct QNode *next;
};

typedef struct QNode QNode;
typedef struct QNode* QueuePtr;

typedef struct
{
    QueuePtr front;     //只需定义链队列的头指针和尾指针
    QueuePtr rear;

}LinkQueue;

Status visitLinkQueue(QElemType c)
{
    printf("%d ",c);
    return OK;
}

//构造一个空的链队列
Status InitLinkQueue(LinkQueue *Q)
{
    QueuePtr head=(QueuePtr)malloc(sizeof(QNode));
    Q->front=Q->rear = head;
    if (!Q->front)
    {
        exit(OVERFLOW); //如果front指针为空,退出
    }
    Q->front->next=NULL;
    return OK;
}

//销毁链队列Q ,链表指针之间有相互关系(注意链队列是尾进头出,因此消除的时候从头部开始)
Status DestroyLinkQueue(LinkQueue *Q)
{
    while(Q->front)
    {
        Q->rear=Q->front->next;
        free(Q->front);
        Q->front=Q->rear;
    }
    return OK;
}

//将Q清空为空链队
Status ClearLinkQueue(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;
}

//若链队列为空,返回TRUE;否则返回FALSE
Status isLinkQueueEmpty(LinkQueue Q)
{
    if (Q.front==Q.rear)
        return TRUE;
    else 
        return FALSE;
}

//求链队列的长度
int LinkQueueLength(LinkQueue Q)
{
    QueuePtr p;
    p=Q.front;
    int count=0;
    while(p!=Q.rear)
    {
        count++;
        p=p->next;

    }
    return count;
}

//若链队列不为空,用e返回Q的队头元素,并返回OK;否则返回ERROR
Status GetHead(LinkQueue Q, QElemType *e)
{
    if (Q.front==Q.rear)
        return ERROR;
    *e=Q.front->next->data;
    return OK;

}

//插入元素e为Q的新的队尾元素
Status EnLinkQueue(LinkQueue *Q,QElemType e)
{
    QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
    if (!p)
        exit(OVERFLOW);     //若存储分配失败,则退出
    p->data=e;
    p->next=NULL;
    Q->rear->next=p;
    Q->rear=p;
    return OK;

}

//若队列不为空,删除Q的队头元素e返回其值,并返回OK;否则,返回ERROR
Status DeQueue(LinkQueue *Q, QElemType *e)
{
    if (Q->front ==Q->rear)
        return ERROR;

    QueuePtr p;             //需要新建一个指针,后面还有free释放掉
    p=Q->front->next;       
    *e=p->data;
    Q->front->next=p->next;

    //判断尾指针是否为p,若相等,尾指针特殊处理;否则直接释放就可以
    if (Q->rear==p)
        Q->rear=Q->front;

    free(p);

    return OK;
}

//从队头到队尾依次对每个元素输出
Status LinkQueueTraverse(LinkQueue Q)
{
    QueuePtr p;
    p=Q.front->next;    //p初始化,指向第一个结点
    while(p)
    {
        visitLinkQueue(p->data);
        p=p->next;
    }
    printf("\n");
    return OK;
}


int main()
{
    int i;
    QElemType d;
    LinkQueue q;
    i=InitLinkQueue(&q);
    if (i)
        printf("成功构建一个空的链队列。\n");

    printf("是否为空的链队列?%d(1:空;0:否)\n",isLinkQueueEmpty(q));
    printf("链队列长度为:%d\n",LinkQueueLength(q));
    LinkQueueTraverse(q);
    EnLinkQueue(&q,-5);
    EnLinkQueue(&q,5);
    EnLinkQueue(&q,10);

    printf("插入3个元素之后,链队列长度为:%d\n",LinkQueueLength(q));
    LinkQueueTraverse(q);

    DeQueue(&q,&d);
    printf("%d\n",d);
    LinkQueueTraverse(q);


    getchar();


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章