數據結構——隊列

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();


}

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