什么是队列

Queue : 具有一定操作约束的线性表 (只能在一端插入 , 而在另一端删除)

堆栈的插入和删除只能在同一端进行

  • 数据插入 : 入队 (AddQ)
  • 数据删除 : 出队 (DeleteQ)
  • 先进先出 : FIFO

**

队列的抽象数据类型描述

操作集

  1. Queue CreateQueue( int MaxSize ) : 生成长度为MaxSize的空队列
  2. int IsFullQ( Queue Q, int MaxSize ) : 判断队列Q是否已满
  3. void AddQ( Queue Q, ElementType item) : 将数据元素item插入队列Q中
  4. int IsEmptyQ( Queue Q ) : 判断队列Q是否为空
  5. ElementType DeleteQ( Queue Q ) : 将队头数据元素从队列中删除并返回

队列的顺序存储实现

通常由一个一维数组和一个记录队列头元素位置的变量 front 以及一个记录队列尾元素位置的变量 rear 组成

堆栈是一个数组和一个Top

定义 :

  1. #define MaxSize<储存数据元素的最大个数>
  2. struct QNode{
  3. ElementType Data[MaxSize];
  4. int rear;
  5. int front;
  6. };
  7. typedef struct QNode *Queue;
  • 开始时 , 队列为空 , 队头变量front 和队尾变量 rear 都指向 -1
  • 向里面添加 Job 1 (AddQ Job 1) , 此时 rear 指向 Job 1 , 在往后添加Job时指向当前添加的Job

image.png

  • 删除元素 Job 1 , 此时 front 指向 0 的位置 (原来 Job 1 的位置)

image.png

  • 总的来说 添加一个元素时 rear ++ ; 删除一个元素时 front ++ ;

image.png
上图情况发生时 , 队尾已经满了没法再添加 , 但队头还有空位置 , 可以将 rear 指向 0 的位置构成循环队列

image.png
队列空 : **front == rear

image.png
此时出现矛盾 : 0,1,2,3,4,5 一共6个相对距离没办法表示出 (0到6) 一共7个相对状态
有两种解决方案 :
(1) 使用额外标记 : Size 或者 Tag域 (1或0 , 对应 front==rear 时的空或满)
(2) 仅使用 n-1 个数组空间

操作

(1) 入队列

  1. void AddQ(Queue PtrQ, ElementType item){
  2. if((PtrQ->rear +1)% MaxSize == PtrQ ->front){ /*判断队列是否满,rear+1=最大元素个数,用求余*/
  3. printf("队列满");return;}
  4. PtrQ->rear = (PtrQ->rear+1)% MaxSize; /*最大rear数用求余*/
  5. PtrQ->Data[PtrQ->rear]=item;
  6. }

(2) 出队列

  1. ElementType DeleteQ(Queue PtrQ){
  2. if(PtrQ->front == PtrQ->rear){ /*front和rear是否相等 判断出队列是否为空*/
  3. printf("队列空");return ERROR;
  4. }else{
  5. PtrQ->front = (PtrQ->front+1)% MaxSize;
  6. return PtrQ->Data[PtrQ->front];
  7. }
  8. }

队列的链式存储实现

front

定义 :

  1. struct Node{
  2. ElementType Data;
  3. struct Node *Next;
  4. };
  5. struct QNode{ /*链队列结构*/
  6. struct Node *rear; /*指向队尾结点*/
  7. struct Node *front;/*指向队头结点*/
  8. };
  9. typedef struct QNode *Queue;
  10. Queue PtrQ;

image.png

不带头结点的链式队列出队操作的一个示例 :

  1. ElementType DeleteQ(Queue PtrQ){
  2. struct Node *FrontCell;
  3. ElementType FrontElem;
  4. if(PtrQ->front == NULL){ /*根据上图,front是NULL的时候就是队列空*/
  5. printf("队列空");return ERROR;
  6. }
  7. FrontCell = PtrQ->front;
  8. if(PtrQ->front == PtrQ->rear) /*若队列中只有一个元素1`2*/
  9. PtrQ->front = PtrQ->rear = NULL; /*删除后队列置为空*/
  10. else
  11. PtrQ->front = PtrQ->front->Next;
  12. FrontElem = FrontCell->Data;
  13. free(FrontCell); /*释放被删除的结点空间*/
  14. return FrontElem;
  15. }

同样可以实现入队操作

小测验

image.png

讨论

如何用两个堆栈模拟实现一个队列?
如果这两个堆栈的容量分别是m和n(m>n),你的方法能保证的队列容量是多少?

堆栈是先进后出,队列是先进先出,用两个堆栈倒腾两次正好把顺序反过来就能实现队列的操作。
一个堆栈用来出队(可以叫stackPop),一个堆栈用来入队(可以叫stackPush)。
要实现先进先出,要把数据从stachPush中倒腾到stackPop中,倒腾的时候,必须保证两点:
(1). stackPush往stackPop倒腾的时候,必须一次把stackPush的时候全部弹出去。
(2).stackPop中有数据的时候,不能倒腾。
入队很简单,直接push到stackPop中。 出队时stackPop里没有元素的话,就把stackPush里面的元素都倒腾过来,然后出去一个就好了。出队时如果stackPop里有元素,就直接出去一个就ok。

课件

2.3队列.pdf

C语言实现 - 队列的定义和操作(顺序_数组)

  1. typedef int Position;
  2. struct QNode {
  3. ElementType *Data; /* 存储元素的数组 */
  4. Position Front, Rear; /* 队列的头、尾指针 */
  5. int MaxSize; /* 队列最大容量 */
  6. };
  7. typedef struct QNode *Queue;
  8. Queue CreateQueue( int MaxSize )
  9. {
  10. Queue Q = (Queue)malloc(sizeof(struct QNode));
  11. Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
  12. Q->Front = Q->Rear = 0;
  13. Q->MaxSize = MaxSize;
  14. return Q;
  15. }
  16. bool IsFull( Queue Q )
  17. {
  18. return ((Q->Rear+1)%Q->MaxSize == Q->Front);
  19. }
  20. bool AddQ( Queue Q, ElementType X )
  21. {
  22. if ( IsFull(Q) ) {
  23. printf("队列满");
  24. return false;
  25. }
  26. else {
  27. Q->Rear = (Q->Rear+1)%Q->MaxSize;
  28. Q->Data[Q->Rear] = X;
  29. return true;
  30. }
  31. }
  32. bool IsEmpty( Queue Q )
  33. {
  34. return (Q->Front == Q->Rear);
  35. }
  36. ElementType DeleteQ( Queue Q )
  37. {
  38. if ( IsEmpty(Q) ) {
  39. printf("队列空");
  40. return ERROR;
  41. }
  42. else {
  43. Q->Front =(Q->Front+1)%Q->MaxSize;
  44. return Q->Data[Q->Front];
  45. }
  46. }

C语言实现 - 队列的定义和操作(链式_链表)

  1. typedef struct Node *PtrToNode;
  2. struct Node { /* 队列中的结点 */
  3. ElementType Data;
  4. PtrToNode Next;
  5. };
  6. typedef PtrToNode Position;
  7. struct QNode {
  8. Position Front, Rear; /* 队列的头、尾指针 */
  9. int MaxSize; /* 队列最大容量 */
  10. };
  11. typedef struct QNode *Queue;
  12. bool IsEmpty( Queue Q )
  13. {
  14. return ( Q->Front == NULL);
  15. }
  16. ElementType DeleteQ( Queue Q )
  17. {
  18. Position FrontCell;
  19. ElementType FrontElem;
  20. if ( IsEmpty(Q) ) {
  21. printf("队列空");
  22. return ERROR;
  23. }
  24. else {
  25. FrontCell = Q->Front;
  26. if ( Q->Front == Q->Rear ) /* 若队列只有一个元素 */
  27. Q->Front = Q->Rear = NULL; /* 删除后队列置为空 */
  28. else
  29. Q->Front = Q->Front->Next;
  30. FrontElem = FrontCell->Data;
  31. free( FrontCell ); /* 释放被删除结点空间 */
  32. return FrontElem;
  33. }
  34. }