33.队列的实现
开发步骤:
1. 建立抽象 自然语言描述
2. 建立接口 queue.h 编写类型的定义、结构体的定义、宏的定义、函数声明、include等内容
3. 实现接口 queue.c 编写函数的实现
4. 使用接口 main.c list的使用
5. 编译过程
编译环境 : unix 、linux
方法 1 :gcc main.c queue.c 生成的可执行文件为a.out
方法 2 : gcc -o main main.c queue.c ;./main 生成指定名称的可执行文件main
注意事项 : 三个文件要放在同一文件夹内编译
1.queue.h
/* queue.h -- Queue的接口*/ #ifndef _QUEUE_H_ #define _QUEUE_H_ #include <stdbool.h> /* 提供bool的定义*/ // Item类型的定义 typedef int Item; // typedef struct item {int gumption; int charisma;} Item; #define MAXQUEUE 10 typedef struct node { Item item; struct node * next; } Node; typedef struct queue { Node * front; /* 指向队列首项的指针*/ Node * rear; /* 指向队列尾项的指针*/ int items; /* 队列中的项数*/ } Queue; /* 操作: 初始化队列 */ /* 前提条件: pq指向一个队列 */ /* 后置条件: 队列被初始化为空 */ void InitializeQueue(Queue * pq); /* 操作: 检查队列是否已满*/ /* 前提条件: pq指向之前被初始化的队列 */ /* 后置条件: 如果队列已满则返回true,否则返回false*/ bool QueueIsFull(const Queue * pq); /* 操作:检查队列是否为空 */ /* 前提条件: pq指向之前被初始化的队列 */ /* 后置条件: 如果队列为空则返回true,否则返回false*/ bool QueueIsEmpty(const Queue * pq); /* 操作:确定队列中的项数*/ /* 前提条件: pq指向之前被初始化的队列 */ /* 后置条件: 返回队列中的项数*/ int QueueItemCount(const Queue * pq); /* 操作:在队列末尾添加项*/ /* 前提条件: pq指向之前被初始化的队列 item是要被添加在队列末尾的项 */ /* 后置条件: 如果队列不为空,item将被添加在队列末尾, 该函数返回true;否则,队列不改变,该函数返回false*/ bool Enqueue(Item item, Queue * pq); /* 操作: 从队列的开头删除项*/ /* 前提条件: pq指向之前被初始化的队列*/ /* 后置条件: 如果队列不为空,队列首端的item将被拷贝到*pitem中 并被删除,且函数返回true; 如果该操作时的队列为空,则重置队列为空 如果队列在操作前为空,则函数返回false */ bool DeQueue(Item *pitem, Queue * pq); /* 操作: 清空队列 */ /* 前提条件: pq指向之前被初始化的队列*/ /* 后置条件: 队列被清空*/ void EmptyTheQueue(Queue * pq); /* 操作: 打印队列*/ /* 前提条件: pq指向之前被初始化的队列*/ void Echo(Queue * pq); #endif
2.queue.c
/* queue.c -- Queue类型的实现 */ #include <stdio.h> #include <stdlib.h> #include "queue.h" /* 局部函数 */ static void CopyToNode(Item item, Node * pn); static void CopyToItem(Node * pn, Item * pi); /* 接口方法实现 */ /* 操作: 初始化队列 */ /* 前提条件: pq指向一个队列 */ /* 后置条件: 队列被初始化为空 */ void InitializeQueue(Queue * pq) { pq->front = pq->rear = NULL; pq->items = 0; } /* 操作: 检查队列是否已满*/ /* 前提条件: pq指向之前被初始化的队列 */ /* 后置条件: 如果队列已满则返回true,否则返回false*/ bool QueueIsFull(const Queue * pq) { return pq->items == MAXQUEUE; } /* 操作:检查队列是否为空 */ /* 前提条件: pq指向之前被初始化的队列 */ /* 后置条件: 如果队列为空则返回true,否则返回false*/ bool QueueIsEmpty(const Queue * pq) { return pq->items == 0; } /* 操作:确定队列中的项数*/ /* 前提条件: pq指向之前被初始化的队列 */ /* 后置条件: 返回队列中的项数*/ int QueueItemCount(const Queue * pq) { return pq->items; } /* 操作:在队列末尾添加项*/ /* 前提条件: pq指向之前被初始化的队列 item是要被添加在队列末尾的项 */ /* 后置条件: 如果队列不为空,item将被添加在队列末尾, 该函数返回true;否则,队列不改变,该函数返回false*/ bool Enqueue(Item item, Queue * pq) { Node * pnew; if (QueueIsFull(pq)) return false; pnew = (Node *) malloc(sizeof(Node)); if (pnew == NULL) { fprintf(stderr, "Unable to allocate memory!\n" ); exit(1); } CopyToNode(item, pnew); pnew->next =NULL; if (QueueIsEmpty(pq)) pq->front = pnew; /* 项位于队列的首端*/ else pq->rear->next = pnew; /* 链接到队列的尾端*/ pq->rear = pnew; /* 记录队列尾端的位置*/ pq->items++; /* 队列的项数加1*/ return true; } /* 操作: 从队列的开头删除项*/ /* 前提条件: pq指向之前被初始化的队列*/ /* 后置条件: 如果队列不为空,队列首端的item将被拷贝到*pitem中 并被删除,且函数返回true; 如果该操作时的队列为空,则重置队列为空 如果队列在操作前为空,则函数返回false */ bool DeQueue(Item *pitem, Queue * pq) { Node * pt; if (QueueIsEmpty(pq)) return false; CopyToItem(pq->front,pitem); pt = pq->front; pq->front = pq->front->next; free(pt); pq->items--; if (pq->items == 0) pq->rear = NULL; return true; } /* 操作: 清空队列 */ /* 前提条件: pq指向之前被初始化的队列*/ /* 后置条件: 队列被清空*/ void EmptyTheQueue(Queue * pq) { Item dummy; while (!QueueIsEmpty(pq)) DeQueue(&dummy, pq); } /* 操作: 打印队列*/ /* 前提条件: pq指向之前被初始化的队列*/ void Echo(Queue * pq) { if (QueueIsEmpty(pq)) puts("当前队列为空."); else { puts("打印当前队列元素(front->rear):"); Node * newpt = pq->front; while (newpt != NULL) { printf("\t当前队列元素:%d\n", newpt->item ); newpt = newpt->next; } } } /* 局部函数*/ static void CopyToNode(Item item, Node * pn) { pn->item = item; } static void CopyToItem(Node * pn, Item * pi) { *pi = pn->item; }
3.main.c
/* use_q.c -- 驱动程序测试 Queue 接口 */ /* 与 queue.c 一起编译 */ #include <stdio.h> #include "queue.h" /* 定义 Queue、Item*/ void Test1(); int main(void) { //Test1(); Queue line; //初始化 InitializeQueue(&line); //添加元素 Enqueue(10,&line); Enqueue(9,&line); Enqueue(8,&line); Enqueue(7,&line); //查看当前元素 Echo(&line); //删除一个元素 int d; DeQueue(&d,&line); printf("被删除的元素是:%d\n", d ); //查看当前元素 Echo(&line); //判断队列是否为空 bool isEmpty = QueueIsEmpty(&line); printf("当前队列是否为空:%d\n", isEmpty ); //判断队列是否已满 bool isFull = QueueIsFull(&line); printf("当前队列是否已满:%d\n", isFull ); //添加元素 Enqueue(6,&line); Enqueue(5,&line); Enqueue(4,&line); Enqueue(3,&line); Enqueue(2,&line); Enqueue(1,&line); Enqueue(0,&line); Enqueue(100,&line); //查看当前元素 Echo(&line); //判断队列是否已满 isFull = QueueIsFull(&line); printf("当前队列是否已满:%d\n", isFull ); //查看当前节点数量 int size = QueueItemCount(&line); printf("当前队列的节点数量:%d\n", size ); //清空队列 EmptyTheQueue(&line); return 0; } /* 测试1*/ void Test1() { Queue line; Item temp; char ch; InitializeQueue(&line); puts("Testing the Queue interface. Type a to add a value,"); puts("type d to delete a value, and type q to quit."); while ((ch = getchar()) != 'q') { if(ch != 'a' && ch != 'd') /* 忽略其他输出*/ continue; if (ch == 'a') { printf("Integer to add:" ); scanf("%d", &temp); if (!QueueIsFull(&line)) { printf("Putting %d into queue\n", temp ); Enqueue(temp, &line); } else puts("Queue is full"); } else { if (QueueIsEmpty(&line)) puts("Nothing to delete!"); else { DeQueue(&temp, &line); printf("Removing %d from queue\n", temp ); } } printf("%d items in queue\n", QueueItemCount(&line) ); puts("Type a to add, d to delete, q to quit:"); } Echo(&line); EmptyTheQueue(&line); puts("Bye!"); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界