文字描述
队列是和栈相反,队列是一种先进先出(first in first out,缩写FIFO)的线性表,它只允许在表的一端进行插入,而在另一端进行删除。和生活中的排队相似,最早进入队列的元素最早离开。在队列中,允许插入的一端加队尾,允许删除的一端叫队头。
另外除了栈和队列,还有一种限定性数据结构是双端队列,它是一种插入和删除操作在表的两端进行的线性表。可以用一个铁道铁轨网络来比喻双端队列。
示意图
表示和实现
A 链队列(链式表示)
用链表表示的队列简称链队列。一个链队列需要分别指向队头和队为的指针才能唯一确定。一般,为了操作方便,会给链队列添加一个不存数据的头结点,并令头结点的next指针指向头结点。由此,空的链队列的判决条件为头指针和尾指针均指向头结点。
扫描二维码关注公众号,回复:
5912359 查看本文章
代码实现
1 // 2 // Created by lady on 19-4-4. 3 // 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 typedef struct QElemType{ 9 char data[10]; 10 }QElemType; 11 12 typedef struct QNode{ 13 QElemType data; 14 struct QNode *next; 15 }QNode, *QueuePtr; 16 typedef struct LinkQueue{ 17 QueuePtr front; 18 QueuePtr rear; 19 }LinkQueue; 20 21 static int InitQueue(LinkQueue *Q); 22 static int CreateQueue(LinkQueue *Q, int n); 23 static int DestoryQueue(LinkQueue *Q); 24 static int EnQueue(LinkQueue *Q, QElemType e); 25 static int DeQueue(LinkQueue *Q, QElemType *e); 26 static int QueueTraverse(LinkQueue Q); 27 28 int main(int argc, char *argv[]) 29 { 30 LinkQueue Q; 31 int i = 0; 32 if(CreateQueue(&Q, 5)<0){ 33 return -1; 34 } 35 printf("依次出队列!\n"); 36 QElemType e; 37 while(!DeQueue(&Q, &e)){ 38 printf("%s\n", e.data); 39 } 40 printf("销毁队列!\n"); 41 DestoryQueue(&Q); 42 return 0; 43 } 44 45 46 47 static int InitQueue(LinkQueue *Q) 48 { 49 if(Q == NULL){ 50 return -1; 51 } 52 Q->front = (QueuePtr)malloc(sizeof(QNode)); 53 Q->front->next = NULL; 54 Q->rear = Q->front; 55 if(Q->front == NULL){ 56 return -1; 57 }else{ 58 return 0; 59 } 60 } 61 62 static int CreateQueue(LinkQueue *Q, int n) 63 { 64 printf("创建一个长度为%d,以链式存储的链队列!\n", n); 65 if(InitQueue(Q)<0){ 66 return -1; 67 } 68 int i = 0; 69 QElemType e; 70 for(i=0; i<n; i++){ 71 printf("输入第%d个元素:", i+1); 72 scanf("%s[^\\n]", e.data); 73 if(EnQueue(Q, e)<0){ 74 return -1; 75 } 76 } 77 return 0; 78 } 79 80 static int DestoryQueue(LinkQueue *Q) 81 { 82 QueuePtr p = Q->front->next; 83 QueuePtr q = NULL; 84 while(p){ 85 q = p; 86 p = p->next; 87 free(q); 88 } 89 if(Q->front){ 90 free(Q->front); 91 Q->front = NULL; 92 } 93 return 0; 94 } 95 static int EnQueue(LinkQueue *Q, QElemType e) 96 { 97 QueuePtr p = (QueuePtr)malloc(sizeof(QNode)); 98 if(p == NULL){ 99 return -1; 100 } 101 p->data = e; 102 p->next = NULL; 103 Q->rear->next = p; 104 Q->rear = p; 105 return 0; 106 } 107 108 static int DeQueue(LinkQueue *Q, QElemType *e) 109 { 110 if(Q->front == Q->rear){ 111 return -1; 112 } 113 QueuePtr p = Q->front->next; 114 (*e) = p->data; 115 Q->front->next = p->next; 116 if(p == Q->rear){ 117 Q->rear = Q->front; 118 } 119 free(p); 120 return 0; 121 } 122 123 static int QueueTraverse(LinkQueue Q) 124 { 125 QueuePtr p = Q.front->next; 126 while(p){ 127 printf("%s\n", p->data.data); 128 p = p->next; 129 } 130 return 0; 131 }
代码运行
1 /home/lady/CLionProjects/untitled/cmake-build-debug/untitled 2 创建一个长度为5,以链式存储的链队列! 3 输入第1个元素:a1 4 输入第2个元素:a2 5 输入第3个元素:a3 6 输入第4个元素:a4 7 输入第5个元素:a5 8 依次出队列! 9 a1 10 a2 11 a3 12 a4 13 a5 14 销毁队列! 15 16 Process finished with exit code 0
B 循环队列(顺序表示)
和顺序栈类似,除了用一组地址连续的存储单元依次存放从队头到队尾的元素外,需设两个指针front和rear分别指向队头元素和队尾元素的位置。一般,为了充分利用空间,会将顺序队列设置为循环模式。在循环队列中,判断队列空间是否为”空“还是”满”。可有两种处理方法:1)单独设置一个标志位以区分队列是否为满 2)少用一个元素空间,约定以”队列头指针在队列指针的下一位置(指环状的下一个位置)上”作为队列满状态的标志。
代码实现
1 // 2 // Created by lady on 19-4-4. 3 // 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 9 //----循环队列----队列的顺序存储结构 10 #define MAXQSIZE 6 //循环队列的最大长度 11 typedef struct QElemType{ 12 char s[10]; 13 }QElemType; 14 typedef struct SqQueue{ 15 QElemType *base;//初始化的动态分配存储空间 16 int front; //头指针,队列不为空的话指向队列头元素 17 int rear; //尾指针,队列不为空的话指向队列尾元素的下一个位置 18 }SqQueue; 19 20 //初始化队列 21 static int InitQueue(SqQueue *Q); 22 //求队列长度 23 static int QueueLength(SqQueue Q); 24 //入队列 25 static int EnQueue(SqQueue *Q, QElemType e); 26 //出队列 27 static int DeQueue(SqQueue *Q, QElemType *e); 28 //遍历队列 29 static int TraverseQueue(SqQueue Q); 30 31 static int CreateQueue(SqQueue *Q, int l){ 32 if(InitQueue(Q) < 0){ 33 return 0; 34 } 35 printf("创建一个长度为%d的顺序存储的循环队列\n", l); 36 37 QElemType e; 38 int i = 0; 39 for(i=0; i<l; i++){ 40 printf("输入第(%d)个数据元素:", i+1); 41 memset(e.s, 0, sizeof(e.s)); 42 scanf("%s[^\\n]", e.s); 43 EnQueue(Q, e); 44 } 45 return 0; 46 } 47 48 int main(int argc, char *argv[]) 49 { 50 QElemType e; 51 SqQueue Q; 52 if(CreateQueue(&Q, 5) < 0){ 53 return -1; 54 } 55 printf("队列长度为%d\n", QueueLength(Q)); 56 TraverseQueue(Q); 57 58 snprintf(e.s, sizeof(e.s), "%s", "A6"); 59 EnQueue(&Q, e); 60 61 DeQueue(&Q, &e); 62 DeQueue(&Q, &e); 63 64 snprintf(e.s, sizeof(e.s), "%s", "A6"); 65 EnQueue(&Q, e); 66 67 TraverseQueue(Q); 68 return 0; 69 } 70 71 static int InitQueue(SqQueue *Q) 72 { 73 Q->base = (QElemType *)malloc(MAXQSIZE*sizeof(QElemType)); 74 if(!Q->base){ 75 return -1; 76 }else{ 77 printf("队列初始化成功,队列可保存的最大元素个数为%d\n", MAXQSIZE); 78 Q->front = Q->rear = 0; 79 return 0; 80 } 81 } 82 83 static int QueueLength(SqQueue Q) 84 { 85 return ((Q.rear-Q.front+MAXQSIZE) % MAXQSIZE); 86 } 87 88 static int EnQueue(SqQueue *Q, QElemType e) 89 { 90 if((Q->rear+1) % MAXQSIZE == Q->front){ 91 printf("队列已满,元素%s不能入队列!\n", e.s); 92 return -1; 93 } 94 printf("元素%s入队列!\n", e.s); 95 Q->base[Q->rear] = e; 96 Q->rear = (Q->rear+1) % MAXQSIZE; 97 return 0; 98 } 99 100 static int DeQueue(SqQueue *Q, QElemType *e) 101 { 102 if(Q->front == Q->rear){ 103 return -1; 104 } 105 (*e) = Q->base[Q->front]; 106 printf("元素%d:%s出队列!\n", Q->front, (*e).s); 107 Q->front = (Q->front+1) % MAXQSIZE; 108 return 0; 109 } 110 111 static int TraverseQueue(SqQueue Q) 112 { 113 printf("遍历:"); 114 if(Q.rear == Q.front){ 115 printf("队列是空的\n"); 116 } 117 int i = Q.front; 118 do{ 119 printf("%d:%s ", i, Q.base[i].s); 120 i = (i+1)%MAXQSIZE; 121 if(i == Q.rear){ 122 break; 123 } 124 }while(1); 125 printf("\n"); 126 }
代码运行
/home/lady/CLionProjects/untitled/cmake-build-debug/untitled 队列初始化成功,队列可保存的最大元素个数为6 创建一个长度为5的顺序存储的循环队列 输入第(1)个数据元素:a1 元素a1入队列! 输入第(2)个数据元素:a2 元素a2入队列! 输入第(3)个数据元素:a3 元素a3入队列! 输入第(4)个数据元素:a4 元素a4入队列! 输入第(5)个数据元素:a5 元素a5入队列! 队列长度为5 遍历:0:a1 1:a2 2:a3 3:a4 4:a5 队列已满,元素A6不能入队列! 元素0:a1出队列! 元素1:a2出队列! 元素A6入队列! 遍历:2:a3 3:a4 4:a5 5:A6 Process finished with exit code 0