当前位置:   article > 正文

数据结构系列-队列的基本操作

队列的基本操作

队列(Queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。允许插入的端是队尾,允许删除的端是队头。

所以说队列是一个先进先出的线性表,相应的也有顺序存储和链式存储两种方式。

顺序存储就是用数组实现,比如有一个n个元素的队列,数组下标0的一端是队头,入队操作就是通过数组下标一个个顺序追加,不需要移动元素,但是如果删除队头元素,后面的元素就要往前移动,对应的时间复杂度就是O(n),性能自然不高。

为了提高出队的性能,就有了循环队列,什么是循环队列呢?就是有两个指针,front指向队头,rear指向对尾元素的下一个位置,元素出队时front往后移动,如果到了对尾则转到头部,同理入队时rear后移,如果到了对尾则转到头部,这样通过下标front出队时,就不需要移动元素了。

同时规定,当队列为空时,front和rear相等,那么队列什么时候判断为满呢?按照循环操作rear依次后移,然后再从头开始,也是出现rear和front相等时,队列满。这样跟队列空的情况就相同了,为了区分这种情况,规定数组还有一个空闲单元时,就表示队列已满,因为rear 可能在front后面,也可能循环到front前面,所以队列满的条件就变成了(rear+1)%maxsize = front ,同时队列元素个数的计算就是(rear -front+maxsize)%maxsize。

如下是循环队列的数据结构及基本操作实现:

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "io.h"
  4. #include "math.h"
  5. #include "time.h"
  6. #define OK 1
  7. #define ERROR 0
  8. #define TRUE 1
  9. #define FALSE 0
  10. #define MAXSIZE 11 //初始容量
  11. typedef int Status;
  12. typedef int QElemType;//定义数据类型
  13. //循环队列的顺序存储结构
  14. typedef struct{
  15. QElemType data[MAXSIZE];
  16. int front; //头指针
  17. int rear;//尾指针,队列非空时,指向队尾元素的下一个位置
  18. }SqQueue;
  19. Status visit(QElemType item){
  20. printf("%d",item);
  21. return OK;
  22. }
  23. //初始化空队列
  24. Status InitQueue(SqQueue *sQ){
  25. sQ->front =0;
  26. sQ->rear =0;
  27. return OK;
  28. }
  29. //将队列清空
  30. Status ClearQueue(SqQueue *Q){
  31. Q->front = Q->rear =0;
  32. return OK;
  33. }
  34. //判断队列是否为null
  35. Status QueueEmpty(SqQueue Q){
  36. if(Q.front == Q.rear)
  37. return TRUE;
  38. else
  39. return FALSE;
  40. }
  41. //返回队列中的元素个数
  42. int QueueLength(SqQueue Q){
  43. return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
  44. }
  45. //返回队头元素
  46. Status GetHead(SqQueue Q, QElemType *e){
  47. if(Q.front == Q.rear)//是否为空队列
  48. return ERROR;
  49. *e = Q.data[Q.front];
  50. return OK;
  51. }
  52. //在队尾插入元素
  53. Status EnQueue(SqQueue *Q, QElemType e){
  54. if((Q->rear+1)%MAXSIZE == Q->front)//队列已满
  55. return ERROR;
  56. Q->data[Q->rear] =e;//插入队尾
  57. Q->rear = (Q->rear +1)%MAXSIZE;//尾部指针后移,如果到最后则转到头部
  58. return OK;
  59. }
  60. //元素出队
  61. Status DeQueue(SqQueue *Q, QElemType *e){
  62. if(Q->front == Q->rear)//队列空
  63. return ERROR;
  64. *e = Q->data[Q->front];//返回队头元素
  65. Q->front = (Q->front+1)%MAXSIZE;//队头指针后移,如到最后转到头部
  66. return OK;
  67. }
  68. //遍历队列元素
  69. Status QueueTraverse(SqQueue Q){
  70. int i = Q.front;
  71. while((i+Q.front) != Q.rear){
  72. visit(Q.data[i]);
  73. i=(i+1)%MAXSIZE;
  74. }
  75. printf("\n");
  76. return OK;
  77. }
  78. int main(){
  79. Status j;
  80. int i=0,l;
  81. QElemType d;
  82. SqQueue Q;
  83. InitQueue(&Q);
  84. //入队10个元素
  85. for(int i =0;i< MAXSIZE-1; i++){
  86. EnQueue(&Q,i);
  87. }
  88. QueueTraverse(Q);
  89. printf("依次出队:");
  90. for(l=1;l<=MAXSIZE;l++)
  91. {
  92. DeQueue(&Q,&d);
  93. printf("d= %d,",d);
  94. }
  95. return 0;
  96. }

循环队列要事先申请好空间,整个过程都不能释放,而且要有固定的长度,如果长度事先无法估计,这种方式显然不够灵活;所以就引入了链式存储队列,其实就是线性表的单链表,只是它只能对尾进,队头出。并且规定队头指针指向链队列的头结点,对尾指针指向终端节点,当队列为空时,front和rear都指向头结点。

入队操作,就是在链表尾部插入结点;出队操作就是头结点的后继结点出队,然后将头结点的后继后移。如果最后除了头结点外,只剩一个元素了,就把rear也指向头结点。

数据结构及基本操作:

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "io.h"
  4. #include "math.h"
  5. #include "time.h"
  6. #define OK 1
  7. #define ERROR 0
  8. #define TRUE 1
  9. #define FALSE 0
  10. #define MAXSIZE 20
  11. typedef int Status;
  12. typedef int QElemType;
  13. //结点结构
  14. typedef struct QNode{
  15. QElemType data;
  16. struct QNode *next;
  17. }QNode,*QueuePtr;
  18. //队列的链表结构
  19. typedef struct{
  20. QueuePtr front;//队头
  21. QueuePtr rear;//对尾
  22. }LinkQueue;
  23. Status visit(QElemType e)
  24. {
  25. printf("%d ",e);
  26. return OK;
  27. }
  28. //初始化空的队列
  29. Status InitQueue(LinkQueue *Q){
  30. Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
  31. if(!Q->front)
  32. exit(OVERFLOW);
  33. Q->front->next =NULL;
  34. return OK;
  35. }
  36. //销毁队列
  37. Status DestroyQueue(LinkQueue *Q){
  38. while(Q->front){
  39. Q->rear=Q->front->next;//从队头开始销毁
  40. free(Q->front);
  41. Q->front = Q->rear;
  42. }
  43. return OK;
  44. }
  45. //清空队列,队头指针还在
  46. Status ClearQueue(LinkQueue *Q){
  47. QueuePtr p,q;
  48. Q->rear =Q->front;//跟初始状态相同,Q->rear指向头结点
  49. p=Q->front->next;//开始销毁队头元素,队头,对尾依然保留
  50. Q->front->next =NULL;
  51. while(p){
  52. q=p;
  53. p=p->next;
  54. free(q);
  55. }
  56. return OK;
  57. }
  58. //队列是否空
  59. Status QueueEmpty(LinkQueue Q){
  60. if(Q.front == Q.rear)
  61. return TRUE;
  62. else
  63. return FALSE;
  64. }
  65. //取队列长度
  66. int QueueLength(LinkQueue Q){
  67. int i=0;
  68. QueuePtr p = Q.front;
  69. while(Q.rear != p){
  70. i++;
  71. p = p->next;
  72. }
  73. return i;
  74. }
  75. //获取队头元素
  76. Status GetHead(LinkQueue Q,QElemType *e){
  77. QueuePtr p;
  78. if(Q.front == Q.rear)//队空
  79. return ERROR;
  80. p=Q.front->next;
  81. *e = p->data;
  82. return OK;
  83. }
  84. //对尾插入元素
  85. Status EnQueue(LinkQueue *Q,QElemType e){
  86. QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
  87. if(!s)
  88. exit(OVERFLOW);
  89. s->data = e;
  90. s->next =NULL;
  91. Q->rear->next =s;//原来对尾的next指向新的元素
  92. Q->rear =s;//将新元素变为对尾
  93. return OK;
  94. }
  95. //队头元素出队
  96. Status DeQueue(LinkQueue *Q,QElemType *e){
  97. QueuePtr p;
  98. if(Q->front == Q->rear)
  99. return ERROR;
  100. p=Q->front->next;//p指向队头元素
  101. *e = p->data;
  102. Q->front->next = p->next;//头结点的后继指向队头的下一个元素
  103. if(Q->rear == p){//队头等于对尾了
  104. Q->rear = Q->front;//对尾指向头结点
  105. }
  106. free(p);
  107. return OK;
  108. }
  109. //遍历元素
  110. Status QueueTraverse(LinkQueue Q){
  111. QueuePtr p;
  112. p=Q.front->next;
  113. while(p){
  114. visit(p->data);
  115. p=p->next;
  116. }
  117. printf("\n");
  118. return OK;
  119. }
  120. int main(){
  121. int i;
  122. QElemType d;
  123. LinkQueue q;
  124. i=InitQueue(&q);
  125. //入队10个元素
  126. for(int index=0;index<MAXSIZE;index++){
  127. EnQueue(&q,index);
  128. }
  129. QueueTraverse(q);
  130. DestroyQueue(&q);
  131. printf("队列已经销毁,q.front=%p q.rear=%p\n",q.front, q.rear);
  132. return 0;
  133. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/884835
推荐阅读
相关标签
  

闽ICP备14008679号