隊列(常用數據結構之一)


隊列

隊列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。

一個隊列為z=(a1,a2,...,an), 如圖

那么a1為對頭元素,an為隊尾元素。最早進入隊列的元素也會最早出來,只有當最先進入隊列的元素都出來以后,后進入的元素才能退出。

在日常生活中,人們去銀行辦理業務需要排隊,這就類似我們提到的隊列。每一個新來辦理業務的需要按照機器自動生成的編號等待辦理,只有前面的人辦理完畢,才能輪到排在后面的人辦理業務。新來的人進入排隊狀態就相當於入隊,前面辦理完業務離開的就相當於出隊。
隊列有兩種存儲表示:順序存儲和鏈式存儲。采用順序存儲結構的隊列被稱為順序隊列,采用鏈式存儲結構的隊列稱為鏈式隊列。

基本運算

InitQueue()     ——初始化隊列
EnQueue()        ——進隊列
DeQueue()        ——出隊列
IsQueueEmpty()   ——判斷隊列是否為空
IsQueueFull()    ——判斷隊列是否已滿

順序隊列

由於順序隊列的底層使用的是數組,因此需預先申請一塊足夠大的內存空間初始化順序隊列。除此之外,為了滿足順序隊列中數據從隊尾進,隊頭出且先進先出的要求,我們還需要定義兩個指針(top 和 rear)分別用於指向順序隊列中的隊頭元素和隊尾元素。

隊列為空時,隊頭指針front和隊尾指針rear都指向下標為0的存儲單元,當元素a,b,c,d,e,f,g依次進入隊列后,元素ag分別存放在數組下標為06的存儲單元中,隊頭指針front指向元素a,隊尾指針指rear向元素g的下一位置。如圖所示。

假溢出

在順序隊中,當尾指針已經到了數組的上界,不能再有入隊操作,但其實數組中還有空位置,這就叫“假溢出”。解決假溢出的途徑———采用循環隊列。

例如在圖中隊列刪除a和b,然后依次插入h、i和j,當插入j后,就會出現隊尾指針rear越出數組的下界造成“假溢出”,如圖

順序循環隊列

為充分利用向量空間,克服"假溢出"現象的方法是:將向量空間想象為一個首尾相接的圓環,並稱這種向量為循環向量。存儲在其中的隊列稱為循環隊列(Circular Queue)。即:循環隊列中進行出隊、入隊操作時,頭尾指針仍要加1,朝前移動。只不過當頭尾指針指向向量上界(QueueSize-1)時,其加1操作的結果是指向向量的下界0。

隊空和隊滿

在循環隊列中,隊空和隊滿時隊頭front和隊尾指針rear同時都會指向同一存儲單元,即front==rear,如圖所示。

隊空

隊滿

如何區分隊空和隊滿呢?有以下兩種方法:

(1)增加一個標志位。設標志位為tag,初始時,tag=0;當入隊成功,則tag=1;出隊成功,tag=0。則判斷隊空的條件為:frontrear&&tag0;隊滿的條件為:frontrear&&tag1;

(2)少用一個存儲單元。隊空的判斷條件為frontrear;隊滿的判斷條件為front(rear+1)%QueueSize。
隊滿的狀態如圖。

存儲結構

#define  MAXQSIZE  5 // 存儲空間的初始分配量
typedef struct {
  ElemType *base;
  int front;
  int rear;
  int maxSize;
} SqQueue;

基本運算

初始化

Status InitQueue(SqQueue &Q) {
  //分配存儲空間
  Q.base = (ElemType*)malloc(MAXQSIZE * sizeof(ElemType));
  if(!Q.base)	exit(OVERFLOW);
  //置Q為空隊列
  Q.front = Q.rear = 0;
  Q.maxSize = MAXQSIZE;
  return OK;
}

判隊列是否為空

Status QueueEmpty(SqQueue Q) {
  if(Q.rear == Q.front) return TRUE;
  else return FALSE;
}

入隊函數

Status EnQueue(SqQueue &Q, ElemType e) {
  if((Q.rear + 1) % MAXQSIZE == Q.front)//隊列已滿
    return ERROR;

  Q.base[Q.rear] = e;//插入隊尾
  Q.rear = (Q.rear + 1) % MAXQSIZE;//尾部指針后移,如果到最后則轉到頭部
  return OK;
}

出隊函數

Status DeQueue(SqQueue &Q, ElemType &e) {
  if(Q.front == Q.rear)   //隊列空
      return ERROR;
  //返回隊頭元素
  e = Q.base[Q.front];    
  //隊頭指針后移,如到最后轉到頭部
  Q.front = (Q.front + 1) % MAXQSIZE; 
  return OK;
}

輸出循環隊列函數

void OutQueue(SqQueue Q) { 	
  ElemType e;
  if(QueueEmpty(Q)){
    printf("這是一個空隊列!");
  } else {
      while(!QueueEmpty(Q)){
        DeQueue(Q, e);
        printf("%6d", e);
        }
      printf("\n");
  }
}

輸出循環隊列長度

Status QueueLength(SqQueue Q) {
    return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

銷毀隊列

Status ClearQueue(SqQueue Q) {
    ///銷毀隊列Q,Q不再存在
    if(Q.base)
        free(Q.base);
    Q.base = NULL;
    Q.front = Q.rear = 0;
    return OK;
}

主函數

int main() { 	
    SqQueue q;
    int cord; 
    ElemType a;
    printf("第一次使用必須初始化!\n");
    //調用初始化算法
    InitQueue(q); 
    do{
        printf("\n 主菜單 \n");
        printf(" 1 初始化循環隊列 ");
        printf(" 2 進隊一個元素 ");
        printf(" 3 出隊一個元素 ");
        printf(" 4 隊列長度 ");
        printf(" 5 銷毀隊列 ");
        printf(" 6 結束程序運行 ");
        printf("\n------------------------------------------------------------------\n");
        printf("請輸入您的選擇( 1, 2, 3, 4, 5, 6)");
        scanf("%d", &cord);
        printf("\n");

        switch(cord) {
            case 1:
                InitQueue(q); //調用初始化算法;
                OutQueue(q);
                break;
            case 2:
                printf("請輸入要插入的數據元素:a=");
                scanf("%d", &a);
                EnQueue (q, a); //調用進隊算法;
                printf("%d 進隊之后的隊列:",a);
                OutQueue(q);
                break;
            case 3:
                DeQueue (q, a); //調用出隊算法;
                printf("隊頭元素 %d 出隊之后的隊列:", a);
                OutQueue(q);
                break;
            case 4:
                printf("該隊列長度為: %d", QueueLength(q));
                break;
            case 5:
                ClearQueue(q);
                break;
            case 6:
                exit(0);
                }
    } while(cord <= 4);
    return 0;
}


免責聲明!

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



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