數據結構(十三)隊列的順序存儲結構(循環隊列)


  一、隊列:隊列是只允許在一端進行插入操作,而在另一端進行刪除操作的線性表。隊列是一種先進先出(First In First Out)的線性表,簡稱FIFO。允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。

  二、隊列在程序設計中的應用:鍵盤輸入、操作系統多個程序因需要通過一個管道輸出而按先后次序排隊等待等。

  三、隊列順序存儲的不足:把隊列的所有元素存儲在數組的前n個單元,數組下標為0的一端即是隊頭。入隊列操作就是在隊尾追加一個元素,不需要移動任何元素,因此時間復雜度為O(1)。但是,與棧不同的是,隊列元素的出列是在隊頭,即下標為0的位置,那也就意味着,隊列中的所有元素都得向前移動,以保證隊列的隊頭,也就是下標為0的位置不為空,此時時間復雜度為O(n)。

  四、如果不去限制隊列的元素必須存儲在數組的前n個單元這一條件,出隊的性能就會大大增加,也就是,隊頭不需要一定在下標為0的位置。

  五、為了避免當只有一個元素時,隊頭和隊尾重合使處理變得麻煩,所以引入兩個指針,front指針指向隊頭元素,rear指針指向隊尾元素的下一個位置,這樣當front等於rear時,次隊列不是還剩一個元素,而是空隊列。

  六、“假溢出”現象就是:數組前面的位置是空閑的,而數組后面的位置已經不夠了。解決假溢出的辦法就是后面滿了,就再重頭開始,也就是頭尾相接的循環。把隊列的這種頭尾相接的順序存儲結構稱為循環隊列。

  七、不循環時,當front等於rear時,隊列是空隊列。但是,使用循環后,front等於rear時,隊列是可能是滿的。為了解決這個問題,采用這個方法:當隊列空時,front=rear;當隊列滿是,修改條件,保留一個元素空間,也就是說,隊列滿時,數組中還有一個空閑單元。盡管它們只相差一個位置時就是滿的情況,但也可能是相差整整一圈。

  八、假設隊列的最大尺寸為QueueSize,那么隊列滿的條件是(rear+1) % QueueSize == front

  九、由於rear > front時,隊列長度等於rear - front;當rear < front時,隊列長度等於(0+rear) + (QueueSize-front)。因此,通用的隊列長度計算公式為:(rear-front+QueueSize)% QueueSize

  十、循環隊列的C語言代碼實現:

#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; /* QElemType類型根據實際情況而定,這里假設為int */

/* 循環隊列的順序存儲結構 */
typedef struct
{
    QElemType data[MAXSIZE];
    int front;        /* 頭指針 */
    int rear;        /* 尾指針,若隊列不空,指向隊列尾元素的下一個位置 */
}SqQueue;

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

/* 初始化一個空隊列Q */
Status InitQueue(SqQueue *Q)
{
    Q->front=0;
    Q->rear=0;
    return  OK;
}

/* 將Q清為空隊列 */
Status ClearQueue(SqQueue *Q)
{
    Q->front=Q->rear=0;
    return OK;
}

/* 若隊列Q為空隊列,則返回TRUE,否則返回FALSE */
Status QueueEmpty(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(Q.front==Q.rear) /* 隊列空 */
        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;            /* 將元素e賦值給隊尾 */
    Q->rear=(Q->rear+1)%MAXSIZE;/* rear指針向后移一位置, */
                                /* 若到最后則轉到數組頭部 */
    return  OK;
}

/* 若隊列不空,則刪除Q中隊頭元素,用e返回其值 */
Status DeQueue(SqQueue *Q,QElemType *e)
{
    if (Q->front == Q->rear)            /* 隊列空的判斷 */
        return ERROR;
    *e=Q->data[Q->front];                /* 將隊頭元素賦值給e */
    Q->front=(Q->front+1)%MAXSIZE;    /* front指針向后移一位置, */
                                    /* 若到最后則轉到數組頭部 */
    return  OK;
}

/* 從隊頭到隊尾依次對隊列Q中每個元素輸出 */
Status QueueTraverse(SqQueue Q)
{ 
    int i;
    i=Q.front;
    for(i = Q.front; i != Q.rear; i = (i + 1) % MAXSIZE){
        visit(Q.data[i]);
    }

    /*
    while((i+Q.front)!=Q.rear)
    {
        visit(Q.data[i]);
        i=(i+1)%MAXSIZE;
    }
    */

    printf("\n");
    return OK;
}

int main()
{
    Status j;
    int i=0,l;
    QElemType d;
    SqQueue Q;
    InitQueue(&Q);
    printf("初始化隊列后,隊列空否?%u(1:空 0:否)\n",QueueEmpty(Q));

    printf("請輸入整型隊列元素(不超過%d個),-1為提前結束符: ",MAXSIZE-1);
    do
    {
        /* scanf("%d",&d); */
        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",QueueEmpty(Q));
    printf("連續%d次由隊頭刪除元素,隊尾插入元素:\n",MAXSIZE);
    for(l=1;l<=MAXSIZE;l++)
    {
        DeQueue(&Q,&d);
        printf("刪除的元素是%d,插入的元素:%d \n",d,l+1000);
        /* scanf("%d",&d); */
        d=l+1000;
        EnQueue(&Q,d);
    }
    l=QueueLength(Q);

    printf("現在隊列中的元素為: \n");
    QueueTraverse(Q);
    printf("共向隊尾插入了%d個元素\n",i+MAXSIZE);
    if(l-2>0)
        printf("現在由隊頭刪除%d個元素:\n",l-2);
    while(QueueLength(Q)>2)
    {
        DeQueue(&Q,&d);
        printf("刪除的元素值為%d\n",d);
    }

    printf("現在隊列中的元素為: \n");
        QueueTraverse(Q);

    j=GetHead(Q,&d);
    if(j)
        printf("現在隊頭元素為: %d\n",d);
    ClearQueue(&Q);
    printf("清空隊列后, 隊列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
    return 0;
}


輸出為:
初始化隊列后,隊列空否?1(1:空 0:否)
請輸入整型隊列元素(不超過19個),-1為提前結束符: 隊列長度為: 19
現在隊列空否?0(1:空 0:否)
連續20次由隊頭刪除元素,隊尾插入元素:
刪除的元素是100,插入的元素:1001 
刪除的元素是101,插入的元素:1002 
刪除的元素是102,插入的元素:1003 
刪除的元素是103,插入的元素:1004 
刪除的元素是104,插入的元素:1005 
刪除的元素是105,插入的元素:1006 
刪除的元素是106,插入的元素:1007 
刪除的元素是107,插入的元素:1008 
刪除的元素是108,插入的元素:1009 
刪除的元素是109,插入的元素:1010 
刪除的元素是110,插入的元素:1011 
刪除的元素是111,插入的元素:1012 
刪除的元素是112,插入的元素:1013 
刪除的元素是113,插入的元素:1014 
刪除的元素是114,插入的元素:1015 
刪除的元素是115,插入的元素:1016 
刪除的元素是116,插入的元素:1017 
刪除的元素是117,插入的元素:1018 
刪除的元素是118,插入的元素:1019 
刪除的元素是1001,插入的元素:1020 
現在隊列中的元素為: 
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 
共向隊尾插入了39個元素
現在由隊頭刪除17個元素:
刪除的元素值為1002
刪除的元素值為1003
刪除的元素值為1004
刪除的元素值為1005
刪除的元素值為1006
刪除的元素值為1007
刪除的元素值為1008
刪除的元素值為1009
刪除的元素值為1010
刪除的元素值為1011
刪除的元素值為1012
刪除的元素值為1013
刪除的元素值為1014
刪除的元素值為1015
刪除的元素值為1016
刪除的元素值為1017
刪除的元素值為1018
現在隊列中的元素為: 
1019 1020 
現在隊頭元素為: 1019
清空隊列后, 隊列空否?1(1:空 0:否)

  十一、循環隊列的Java語言代碼實現:

  • 接口類:
package bigjun.iplab.sequenceQueue;

public interface QueueINF {
    // 判斷順序隊列是否為空
    public boolean isqueueEmpty();
    // 將一個已經存在的順序隊列置成空表
    public void queueClear();
    // 求順序隊列的長度
    public int queueLength();
    // 讀取順序隊列的隊列隊頭元素
    public int getHeadElem() throws Exception;
    // 在順序隊列的隊尾插入元素e
    public void queueEnter(int e) throws Exception;
    // 刪除順序隊列隊頭元素
    public void queueDel() throws Exception ;
    // 輸出順序隊列中的所有元素
    public void queueTraverse() throws Exception;
}
  • 實現類:
package bigjun.iplab.sequenceQueue;

public class SequenceQueue implements QueueINF {
    
    private final static int MAXSIZE = 20;
    private int[] queueElem;
    private int front;
    private int rear;
    
    public SequenceQueue() {
        queueElem = new int[MAXSIZE];
        front = rear = 0;
    }

    @Override
    public boolean isqueueEmpty() {
        return front == rear;
    }

    public void queueClear() {
        front=rear=0;
    }

    public int queueLength() {
        return (rear - front + MAXSIZE) % MAXSIZE;
    }

    public int getHeadElem() throws Exception {
        if (front == rear) 
            throw new Exception("順序隊列為空,無法獲取隊頭元素");
        return queueElem[front];
    }

    public void queueEnter(int e) throws Exception {
        if ((rear + 1) % MAXSIZE == front) 
            throw new Exception("隊列為滿的,無法實現入隊列操作");
        queueElem[rear] = e;
        rear = (rear + 1) % MAXSIZE;
    }

    public void queueDel() throws Exception {
        if (front == rear) 
            throw new Exception("順序隊列為空,無法刪除隊頭元素");
        front = (front + 1 ) % MAXSIZE;
    }

    public void queueTraverse() throws Exception {
        if (front == rear) 
            throw new Exception("順序隊列為空,無法獲取隊頭元素");
        System.out.print("此時順序隊列的元素為: ");
        for (int i = front; i != rear; i = (i + 1 ) % MAXSIZE) {
            System.out.print(queueElem[i] + " ");
        }
        System.out.println();
    }
    
    public static void main(String[] args) throws Exception {
        int i = 0;
        SequenceQueue sQueue = new SequenceQueue();
        System.out.println("隊列是否為空: " + sQueue.isqueueEmpty());
        do {
            int d = i + 100;
            i++;
            sQueue.queueEnter(d);
        } while (i  < MAXSIZE - 1);      // 這里留一個位置為空,注意一下。
        System.out.println("隊列是否為空: " + sQueue.isqueueEmpty());
        System.out.println("隊列長度為: " + sQueue.queueLength());
        sQueue.queueTraverse();
        
        for (int j = 1; j <= MAXSIZE; j++) {
            sQueue.queueDel();
            int f = j + 1000;
            sQueue.queueEnter(f);
        }
        sQueue.queueTraverse();
        
        for (int l = 1; l <= 17 ; l++) {
            sQueue.queueDel();
        }
        System.out.println("隊列長度為: " + sQueue.queueLength());
        sQueue.queueTraverse();
        System.out.println("隊列的隊頭為: " + sQueue.getHeadElem());
        sQueue.queueDel();
        System.out.println("隊列的隊頭為: " + sQueue.getHeadElem());
    }
    

}
  • 輸出:
隊列是否為空: true
隊列是否為空: false
隊列長度為: 19
此時順序隊列的元素為: 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 
此時順序隊列的元素為: 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 
隊列長度為: 2
此時順序隊列的元素為: 1019 1020 
隊列的隊頭為: 1019
隊列的隊頭為: 1020


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM