數據結構之隊列

轉載:http://blog.chinaunix.net/uid-26548237-id-3473528.html


與棧相反,隊列是一種先進先出的線性表,它只允許在表的一端進行,而在另一端刪除元


素。

   在隊列中,允許插入的一端叫做隊尾,允許刪除的一端則稱爲隊頭。


1、鏈隊列——隊列的鏈式表示和實現

   用鏈表表示的隊列簡稱爲鏈隊列,一個鏈隊列顯然需要兩個分別指示對頭和隊尾的指針

(分別稱爲頭指針和尾指針)才能唯一確定。這裏,和線性表的單鏈表一樣,爲了操作方便起

見,我們也給隊列添加一個頭結點。

   鏈隊列的操作即爲單鏈表的插入和刪除操作的特殊情況,只是尚需修改尾指針或頭指針。

   單鏈隊列——隊列的鏈式存儲結構,如下所示。

  1. //單鏈隊列,隊列的鏈式存儲結構
  2. typedef struct QNode
  3. {
  4.     ElemType data;
  5.     struct QNode *next;
  6. }QNode, *QueuePtr;

  7. typedef struct
  8. {
  9.     QueuePtr front;            //隊頭指針
  10.     QueuePtr rear;            //隊尾指針
  11. }LinkQueue;

2、單鏈隊列的C語言操作

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. #define ElemType int

  4. #define OK 1
  5. #define ERROR 0


  6. //單鏈隊列,隊列的鏈式存儲結構
  7. typedef struct QNode
  8. {
  9.     ElemType data;
  10.     struct QNode *next;
  11. }QNode, *QueuePtr;

  12. typedef struct
  13. {
  14.     QueuePtr front;            //隊頭指針
  15.     QueuePtr rear;            //隊尾指針
  16. }LinkQueue;

  17. //構造一個空隊列
  18. int InitQueue(LinkQueue *q)
  19. {
  20.     //
  21.     q->front = q->rear = (QueuePtr)malloc(sizeof(QNode));
  22.     if(q->front == NULL)
  23.     {
  24.         fprintf(stderr, "malloc() error.\n");
  25.         return ERROR;
  26.     }

  27.     q->front->next = NULL;
  28.     q->rear->next = NULL;

  29.     return OK;
  30. }

  31. //銷燬隊列,Q不在存在
  32. int DestroyQueue(LinkQueue *q)
  33. {
  34.     //
  35.     while(q->front)
  36.     {
  37.         q->rear = q->front->next;
  38.         free(q->front);
  39.         q->front = q->rear;
  40.     }
  41.     return OK;
  42. }

  43. //判斷隊列是否爲空
  44. int IsEmptyQueue(LinkQueue *q)
  45. {
  46.     return (q->front->next == NULL && q->rear->next == NULL);
  47. }

  48. //插入元素e爲新的隊尾元素
  49. int InsertQueue(LinkQueue *q, ElemType e)
  50. {
  51.     //
  52.     QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
  53.     if(p == NULL)
  54.     {
  55.         fprintf(stderr, "malloc() error.\n");
  56.         return ERROR;
  57.     }
  58.     
  59.     p->data = e;
  60.     p->next = NULL;
  61.     
  62.     //如果隊列爲空
  63.     if(IsEmptyQueue(q))
  64.     {
  65.         q->front->next = p;
  66.         q->rear = p;
  67.     }
  68.     else
  69.     {
  70.         q->rear->next = p;
  71.         q->rear = p;            //不要忘記這句啊
  72.     }
  73.     return OK;
  74. }

  75. //若隊列不空,則刪除隊頭元素,用e返回其值,並返回OK
  76. int DeQueue(LinkQueue *q, ElemType *e)
  77. {
  78.     //
  79.     if(IsEmptyQueue(q))
  80.     {
  81.         fprintf(stdout, "the queue is null.\n");
  82.         return ERROR;
  83.     }

  84.     //注意有隊頭結點
  85.     QueuePtr temp;
  86.     temp = q->front->next;
  87.     *e = temp->data;

  88.     q->front->next = temp->next;

  89.     //一個元素
  90.     if(q->rear == temp)
  91.     {
  92.         q->rear = q->front;
  93.     }

  94.     free(temp);

  95.     return OK;
  96. }

  97. //打印隊列
  98. void printQueue(LinkQueue *q)
  99. {
  100.     QueuePtr temp;
  101.     temp = q->front->next;

  102.     while(temp != NULL)
  103.     {
  104.         printf("%d ", temp->data);
  105.         temp = temp->next;
  106.     }

  107. }

  108. int main(int argc, char **argv)
  109. {
  110.     LinkQueue *q;
  111.     InitQueue(q);

  112.     srand(time(NULL));

  113.     int i = 0;
  114.     for(i = 0; i < 10; i++)
  115.     {
  116.         InsertQueue(q, i);
  117.     }

  118.     printf("插入隊列的元素爲:\n");
  119.     printQueue(q);

  120.     int e;
  121.     DeQueue(q, &e);
  122.     printf("隊頭元素爲: %d\n", e);

  123.     return 0;
  124. }

3、循環隊列定義

   單鏈隊列時,當隊列爲空時,front等於rear,現在循環隊列當隊列滿時,也是front等

rear,那麼如何判斷此時的隊列究竟是空還是滿呢?

   辦法一是設置一個標誌變量flag,當front == rear,且flag = 0時爲隊列空,當front 

==rear,且flag = 1時爲隊列滿;

   辦法二是當隊列空時,條件就是front == rear,當隊列爲滿時,我們修改其條件,保留一

個元素空間。也就是說,隊列滿時,數組中還有一個空閒單元。例如下圖所示,我們就認爲此

隊列已經滿了,也就是說,我們不允許下圖中的右圖情況出現。

   我們重點來討論第二種方法,由於rear可能比front大,也可能比front小,所以,儘管它

們只相差一個位置時就說滿的情況,但也有可能是相差整整一圈。所以,若隊列的最大尺寸爲

QueueSize,那麼隊列滿的條件是(rear + 1) % QueueSize == front(取模"%"的目的就說爲

了整合rear與front大小爲一個問題)。比如上面這個例子,QueueSzie = 5,上圖中的左圖中

front = 0,而rear = 4,(4 + 1) % 5 = 0,所以,此時隊列滿。再看右圖,front = 2, 

而rear = 1,(1 + 1) %5 = 2,所以,此時隊列也是滿的。但是也有例外的情況。

   另外,通用的計算隊列長度的公式爲:(rear - front + QueueSize) % QueueSize

   循環隊列的順序存儲結構,如下所示。

  1. #define ElemType int 

  2. typedef struct
  3. {
  4.     ElemType data[MAXSIZE];
  5.     int front; //頭指針
  6.     int rear; //尾指針,若隊列不爲空時,rear指向隊列尾元素的下一個位置
  7. }SqQueue;



4、循環隊列的C操作

  1. #define ElemType int

  2. #define MAXSIZE 100

  3. typedef struct
  4. {
  5.     ElemType data[MAXSIZE];
  6.     int front;                //頭指針
  7.     int rear;                //尾指針,若隊列不爲空時,rear指向隊列尾元素的下一個位置
  8. }SqQueue;


  9. #define OK     1
  10. #define ERROR 0
  11. //初始化一個空隊列
  12. int InitQueue(SqQueue *q)
  13. {
  14.     q->front = 0;
  15.     q->rear = 0;

  16.     return OK;
  17. }

  18. //循環隊列求隊列長度
  19. //返回隊列的元素的個數,也就是隊列的當前長度
  20. int QueueLength(SqQueue *q)
  21. {
  22.     return (q->rear - q->front + MAXSIZE) % MAXSIZE;
  23. }

  24. //循環隊列的入隊操作
  25. //若隊列未滿,則插入元素e爲隊列新的隊尾元素
  26. int EnQueue(SqQueue *q, ElemType e)
  27. {
  28.     if((q->rear + 1) % MAXSIZE == q->front)    //隊列滿的判斷
  29.     {
  30.         return ERROR;
  31.     }

  32.     q->data[q->rear] = e;                    //將元素e賦值給隊尾
  33.     q->rear = (q->rear + 1) MAXSIZE;        //rear指向後移一位置,若到最後則轉爲數組頭部
  34.                                             //注意
  35.     return OK;
  36. }

  37. //循環隊列的出對操作
  38. //若隊列不空,則刪除q中隊頭元素,用e返回值
  39. int DeQueue(SqQueue *q, ElemType *e)
  40. {
  41.     if(q->rear == q->front)                //隊列空的判斷
  42.     {
  43.         return ERROR;
  44.     }
  45.     
  46.     *e = q->data[q->front];                //將隊頭元素賦值給e
  47.     q->front = (q->front + 1) % MAXSIZE;//front指針向後一位置,若到最後,則轉到數組頭部

  48.     return OK;
  49. }





          參數:嚴蔚敏老師之《數據結構》、《大話數據結構》

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