根据前面几篇关于C语言的抽象类型及模块化开发的知识,一方面总结知识,另一方面通过实例来增加理解,使其真正转化为自己的能力和思想,使强大而又古老的C语言不再枯燥,挖掘它的高级语言特性。我们简单回顾一下相关知识:
重点有:
1)接口定义,只重行为,不重底层实现,给予实现层充分的自由。
2)模块化划分再加上接口层,实现层和客户层,多种形式,使程序易于开发和维护
这里我们主要应用前面几篇博文中提到的关于模块块开发及抽象数据类型的相关知识,结合一个常见的数据结构题目,练习体会一下。题目如下:
显然,此题目中的问题涉及堆栈和队列相关数据类型,为了实现最大程度的代码重用,我们让堆栈和队列抽象类型的底层均基于链表,那我们就可以实现一个链表抽象类型,并以此为基础,来实现堆栈和队列的抽象类型。
此程序共有9个文件,按类型和功能划分为:
1)主模块:parking.c 和它的头文件parking.h
2)链表抽象类型:接口定义list.h,接口实现list_impl.h和list.c
3)堆栈抽象类型: 接口定义 stack.h ,接口实现 stack.c
4)队列抽象类型:接口定义 queue.h 接口实现 queue.c
下面看代码:
链表抽象类型的接口:
1 /* list.h --- 2 * 3 * Filename: list.h 4 * Description: 链表抽象接口定义 5 * Author: magc 6 * Maintainer: 7 * Created: 五 8月 17 10:02:41 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 00:41:41 2012 (+0800) 10 * By: magc 11 * Update #: 82 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 20 * 21 * 22 */ 23 24 /* Change Log: 25 * 26 * 27 */ 28 29 /* Code: */ 30 31 #ifndef _list_h 32 #define _list_h 33 34 35 36 #include "../commonlib/genlib.h" 37 38 /* 39 * struct :链表抽象类型, 40 * listCDT:不完全类型,有待实现层去定义 41 */ 42 typedef struct listCDT *listADT; 43 44 45 46 /* 47 * struct :链表单元结构定义 48 * data:为了提高此属性的适用范围,特将它设为void *类型,在获取具体数据时,需要显式转换该指针类型为目标类型 49 */ 50 typedef struct listCellT{ 51 void *data; //此处用通用指针类型,便于存放各种指针类型的数据,只是在取指针类型时,需要强制转换一下指针类型。 52 struct listCellT *next; //指向下一个元素 53 } *listCellP; 54 55 /************************************************************************* 56 *功能描述:创建新链表 57 *参数列表: 58 *返回类型: 59 **************************************************************************/ 60 listADT NewList(void); 61 62 /************************************************************************* 63 *功能描述:释放链表 64 *参数列表: 65 *返回类型: 66 **************************************************************************/ 67 void FreeList(listADT list); 68 69 /************************************************************************* 70 *功能描述:在链表前端添加元素 71 *参数列表: 72 *返回类型: 73 **************************************************************************/ 74 void AddCellAheadList(listADT list,listCellP cell); 75 76 /************************************************************************* 77 *功能描述:在链表后端添加元素 78 *参数列表: 79 *返回类型: 80 **************************************************************************/ 81 void AddCellRearList(listADT list , listCellP cell); 82 83 /************************************************************************* 84 *功能描述:在链表前端删除元素 85 *参数列表: 86 *返回类型: 87 **************************************************************************/ 88 listCellP RemoveCellAheadList(listADT list); 89 90 /************************************************************************* 91 *功能描述:在链表后端删除元素 92 *参数列表: 93 *返回类型: 94 **************************************************************************/ 95 listCellP RemoveCellRearList(listADT list); 96 97 /************************************************************************* 98 *功能描述:链表长度 99 *参数列表: 100 *返回类型: 101 **************************************************************************/ 102 int LenthList(listADT list); 103 104 /************************************************************************* 105 *功能描述:链表是否为空 106 *参数列表: 107 *返回类型: 108 **************************************************************************/ 109 bool IsEmptyList(listADT list); 110 111 /************************************************************************* 112 *功能描述:回调函数(映射函数),用来在打印内容时,让客户端个性化信息 113 *参数列表: 114 *返回类型: 115 **************************************************************************/ 116 typedef void (*printCell)(void *data); 117 118 /************************************************************************* 119 *功能描述:打印输出链表元素内容 120 *参数列表: 121 *返回类型: 122 **************************************************************************/ 123 void PrintList(printCell printc,listADT list); 124 125 126 #endif 127 128 /* list.h ends here */
链表单元结构定义
1 /* list_impl.h --- 2 * 3 * Filename: list_impl.h 4 * Description: 链表元素类型底层实现 5 * Author: magc 6 * Maintainer: 7 * Created: 五 8月 17 16:16:42 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 00:39:43 2012 (+0800) 10 * By: magc 11 * Update #: 6 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 20 * 21 * 22 */ 23 24 /* Change Log: 25 * 26 * 27 */ 28 29 /* Code: */ 30 31 #ifndef _list_impl_h 32 #define _list_impl_h 33 34 /* 35 * struct :链表单元类型结构定义 36 * 为了使这一种底层实现被多个抽象类型重用,特单独放到这个文件中, 37 */ 38 struct listCDT{ 39 int count; //元素个数 40 listCellP head; //头部指针,指向链表的第一个元素 41 listCellP rear; ///尾部指针,指向链表最后个元素 42 }; 43 44 #endif 45 46 /* list_impl.h ends here */
注:将此类型定义单独出来,是为了让后面链表、堆栈和队列三个抽象类型都能引用到,都能重用这同一个类型定义。
链表抽象类型的实现:
/* list.c --- * * Filename: list.c * Description:链表的实现 * Author: magc * Maintainer: * Created: 五 8月 17 10:56:58 2012 (+0800) * Version: * Last-Updated: 五 8月 17 23:50:32 2012 (+0800) * By: magc * Update #: 164 * URL: * Keywords: * Compatibility: * */ /* Commentary: * 链表抽象类型的实现 * * */ /* Change Log: * * */ /* Code: */ #include <assert.h> #include <ctype.h> #include <errno.h> #include <limits.h> #include <string.h> #include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include "../commonlib/genlib.h" #include "../commonlib/strlib.h" #include "list.h" #include "list_impl.h" /************************************************************************* *功能描述:创建新链表 *参数列表: *返回类型: **************************************************************************/ listADT NewList(void){ listADT list = New(listADT); list->count = 0; list->head = NULL; list->rear = NULL; return list; } /************************************************************************* *功能描述:释放链表 *参数列表: *返回类型: **************************************************************************/ void FreeList(listADT list){ //遍历各元素,将元素释放 listCellP cell = list->head; //每个指针类型的属性都是看作地雷,一定要处理好。否则后患无穷。 while(cell != NULL){ list->head = list->head->next; FreeBlock(cell); cell = list->head; } FreeBlock(list); } /************************************************************************* *功能描述:在链表前端添加元素 *参数列表: *返回类型: **************************************************************************/ void AddCellAheadList(listADT list,listCellP cell){ //链接上头部元素 cell->next = list->head; list->head = cell; //若空链表,即尾部指针为空时,要处理一下 if(list->rear == NULL){ list->rear = cell; } list->count++; // printf("add--%x\n",list->head); } /************************************************************************* *功能描述:在链表后端添加元素 *参数列表: *返回类型: **************************************************************************/ void AddCellRearList(listADT list , listCellP cell){ //若为空链表时即头指针为NULL ,要处理头部指针 if(list->head == NULL){ list->head = cell; } //链接尾部元素 if(list->rear != NULL){ list->rear->next = cell; } list->rear = cell; list->count++; } /************************************************************************* *功能描述:在链表前端删除元素 *参数列表: *返回类型: **************************************************************************/ listCellP RemoveCellAheadList(listADT list){ if(list->head == NULL) return NULL; listCellP cell = list->head; list->head = list->head->next; cell->next = NULL; //注意置NULL的次序,再向上一行,就会影响到list->head了。 //若当前头指针已经为空,说明当前链表已空,需要将rear指针也置NULL if(list->head == NULL){ list->rear = NULL; } list->count--; return cell; } /************************************************************************* *功能描述:在链表后端删除元素 *参数列表: *返回类型: **************************************************************************/ listCellP RemoveCellRearList(listADT list){ if(list->rear == NULL) Error("链表已为空\n"); //若从尾部删除元素,则需要找到倒数第二个元素 listCellP cell = list->head; while(cell->next != list->rear){ cell = cell->next; } list->rear = cell; cell = cell->next; list->count--; return cell; } /************************************************************************* *功能描述:链表长度 *参数列表: *返回类型: **************************************************************************/ int LenthList(listADT list){ return (list->count); } /************************************************************************* *功能描述:链表是否为空 *参数列表: *返回类型: **************************************************************************/ bool IsEmptyList(listADT list){ return (list->count == 0); } /************************************************************************* *功能描述:打印输出链表元素内容 *参数列表:printc:回调函数名称 *返回类型: **************************************************************************/ void PrintList(printCell printc,listADT list){ listCellP cell = list->head; if(cell == NULL){ printf("链表为空。\n"); } while(cell!=NULL){ printc(cell->data); //具体打印格式交给回调函数处理,给予客户端个性化机会。 cell = cell->next; } } /* list.c ends here */
堆栈接口定义:
1 /* stack.h --- 2 * 3 * Filename: stack.h 4 * Description:抽象数据类型ADT--堆栈 5 * Author: magc 6 * Maintainer: 7 * Created: 四 8月 9 08:59:34 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 00:44:24 2012 (+0800) 10 * By: magc 11 * Update #: 88 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * ADT 接口 20 * 只定义行为,而不限制底层表示和实现 21 * 22 */ 23 24 /* Change Log: 25 * 2012-8-16 修改cellT结构,将其int属性改为carP类型,以适应栈内存放汽车信息 26 * 2012-8-17 修改堆栈抽象类型基于链表抽象类型 27 */ 28 29 /* Code: */ 30 #ifndef _stack_h 31 #define _stack_h 32 #include "../commonlib/genlib.h" 33 #include "parking.h" 34 #include "list.h" 35 #include "list_impl.h" 36 37 #define MaxStackSize 10 38 39 40 41 typedef struct stackCDT *stackADT; 42 43 // 堆栈单元类型重用链表抽象类型的单元类型,为了便于使用和理解,给它起了个本土名字。 44 45 typedef listCellP stackElement; 46 47 /** 2012-8-17 改为基于list单元结构的 48 typedef struct cellT{ 49 carP car; 50 struct cellT *next; 51 } * stackElement; 52 53 54 **/ 55 /************************************************************************* 56 *功能描述:创建新堆栈 57 *参数列表: 58 *返回类型:堆栈指针 59 **************************************************************************/ 60 stackADT NewStack(void); 61 62 /************************************************************************* 63 *功能描述:释放堆栈内存空间 64 *参数列表: 65 *返回类型: 66 **************************************************************************/ 67 void FreeStack(stackADT stack); 68 69 /************************************************************************* 70 *功能描述:压栈 71 *参数列表: 72 *返回类型: 73 **************************************************************************/ 74 void Push(stackADT stack ,stackElement element ); 75 76 /************************************************************************* 77 *功能描述:出栈 78 *参数列表: 79 *返回类型:弹出的元素 80 **************************************************************************/ 81 stackElement Pop(stackADT stack); 82 83 /************************************************************************* 84 *功能描述:判断当前栈是否为空 85 *参数列表: 86 *返回类型:TRUE or FALSE 87 **************************************************************************/ 88 bool StackIsEmpty(stackADT stack ); 89 90 /************************************************************************* 91 *功能描述:判断当前栈是否已满 92 *参数列表: 93 *返回类型: 94 **************************************************************************/ 95 bool StackIsFull(stackADT stack); 96 97 /************************************************************************* 98 *功能描述:获取当前栈的深度 99 *参数列表: 100 *返回类型: 101 **************************************************************************/ 102 int StackDepth(stackADT stack); 103 104 /************************************************************************* 105 *功能描述:读取堆栈顶端元素值 106 *参数列表: 107 *返回类型: 108 **************************************************************************/ 109 int StackTop(stackADT stack); 110 111 /************************************************************************* 112 *功能描述:打印堆栈元素的内容 113 *参数列表: 114 *返回类型: 115 **************************************************************************/ 116 void StackPrint(stackADT stack); 117 118 #endif 119 /* stack.h ends here */
堆栈抽象类型的实现:
1 /* stack1.c --- 2 * 3 * Filename: stack.c 4 * Description: 堆栈ADT的实现(链表实现方式) 5 * Author: magc 6 * Maintainer: 7 * Created: 三 8月 15 08:49:21 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 00:47:35 2012 (+0800) 10 * By: magc 11 * Update #: 297 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 底层采用链表的形式实现堆栈 20 * 同样实现stack.h接口中的行为 21 * 堆栈的行为,基于链表抽象类型的行为来实现。即重用链表类型 22 */ 23 24 /* Change Log: 25 * 2012-8-16 修改Push和PoP,压栈和出栈参数为栈单元类型, 26 * 2012-8-17 修改Pop方法,将弹出的元素next属性适时置NULL 27 */ 28 29 /* Code: */ 30 #include <assert.h> 31 #include <ctype.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <string.h> 35 #include <stdarg.h> 36 #include <stdlib.h> 37 #include <stdio.h> 38 #include "../commonlib/genlib.h" 39 #include "stack.h" 40 41 // 为了重用链表的类型和行为,使链表作为堆栈类型的一个属性,将它包装起来,所以它的行为都是可以重用链表的。 42 struct stackCDT { 43 listADT list; 44 }; 45 46 /************************************************************************* 47 *功能描述:创建新堆栈实例 48 *参数列表: 49 *返回类型:空堆栈 50 **************************************************************************/ 51 stackADT NewStack(void){ 52 stackADT stack = New(stackADT); 53 listADT list = NewList(); 54 stack->list = list; 55 return stack; 56 } 57 58 /************************************************************************* 59 *功能描述:释放堆栈内存空间(每个元素的空间都需要释放) 60 *参数列表: 61 *返回类型: 62 **************************************************************************/ 63 void FreeStack(stackADT stack){ 64 FreeList(stack->list); 65 FreeBlock(stack); 66 } 67 68 69 /************************************************************************* 70 *功能描述:压栈 head始终指向栈顶,压栈是从head端添加元素 71 *参数列表: 72 *返回类型: 73 **************************************************************************/ 74 void Push(stackADT stack ,stackElement element){ 75 AddCellAheadList(stack->list,element); 76 } 77 78 /************************************************************************* 79 *功能描述:出栈(将栈顶元素弹出) 80 *参数列表: 81 *返回类型:弹出的元素 82 **************************************************************************/ 83 stackElement Pop(stackADT stack){ 84 if(stack == NULL){ 85 Error("堆栈为NULL"); 86 } 87 //printf("test---%d\n",stack->list->count); 88 89 stackElement temp = RemoveCellAheadList(stack->list); 90 return temp; 91 } 92 93 /************************************************************************* 94 *功能描述:判断当前栈是否为空 95 *参数列表: 96 *返回类型:TRUE or FALSE 97 **************************************************************************/ 98 bool StackIsEmpty(stackADT stack ){ 99 return (stack->list->count == 0); 100 101 } 102 /************************************************************************* 103 *功能描述:判断当前栈是否已满 104 *参数列表: 105 *返回类型: 106 **************************************************************************/ 107 bool StackIsFull(stackADT stack){ 108 return (stack->list->count == MaxStackSize); 109 } 110 111 112 /************************************************************************* 113 *功能描述:获取当前栈的深度 114 *参数列表: 115 *返回类型: 116 **************************************************************************/ 117 int StackDepth(stackADT stack){ 118 return stack->list->count; 119 } 120 121 /************************************************************************* 122 *功能描述:读取堆栈顶端元素值 123 *参数列表: 124 *返回类型: 125 **************************************************************************/ 126 int StackTop(stackADT stack){ 127 if(stack->list->count == 0)return NULL; 128 return stack->list->head; 129 } 130 /************************************************************************* 131 *功能描述:打印单元信息(作为回调函数) 132 *参数列表: 133 *返回类型: 134 **************************************************************************/ 135 136 137 static void printCar(void *data){ 138 printf("%s,",((carP)data)->number_id); 139 140 } 141 142 143 /************************************************************************* 144 *功能描述:打印堆栈元素的内容 145 *参数列表: 146 *返回类型: 147 **************************************************************************/ 148 void StackPrint(stackADT stack){ 149 if(stack->list->count == 0) return ; 150 printf("共%d个元素:",StackDepth(stack)); 151 PrintList( printCar,stack->list); 152 153 /*** 154 stackElement element = NULL; 155 for(element = stack->list->head;element!=NULL;element = element->next){ 156 printf("%s,",((carP)element->data)->number_id); 157 } 158 *****/ 159 160 printf("\n"); 161 162 } 163 164 165 /************************************************************************* 166 *功能描述:主函数 167 *参数列表: 168 *返回类型: 169 170 int main(int argc, char * argv[]) 171 { 172 stackADT stack = NewStack(); 173 Push(stack,45); 174 Push(stack,55); 175 Push(stack,66); 176 Pop(stack); 177 178 StackPrint(stack); 179 printf("\n"); 180 181 182 } 183 **************************************************************************/ 184 185 186 187 188 189 190 /* stack1.c ends here */
队列抽象类型的接口定义:
1 /* queue.h --- 2 * 3 * Filename: queue.h 4 * Description:队列抽象类型 接口 5 * Author: magc 6 * Maintainer: 7 * Created: 三 8月 15 15:48:10 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 00:48:43 2012 (+0800) 10 * By: magc 11 * Update #: 69 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 以一个整数队列为例 20 * 定义队列的行为:创建/销毁/入队/出队等,遵守先进先出,队首出,队尾入规则。 21 * 22 */ 23 24 /* Change Log: 25 * 2012-8-17 修改队列抽象类型基于链表抽象类型 26 * 27 */ 28 29 /* Code: */ 30 #ifndef _queue_h 31 #define _queue_h 32 33 #include "../commonlib/genlib.h" 34 #include "list.h" 35 #include "parking.h" 36 #include "list_impl.h" 37 38 #define MaxQueueLenth 100 39 40 41 /* 42 * struct :队列抽象类型结构定义 43 * 44 */ 45 typedef struct queueCDT *queueADT; 46 47 //队列的单元重用链表的,为了便于使用,给它起了一个本土名字。 48 49 typedef listCellP qcellP ; 50 51 /* 2012-8-17 注释,此结构定义改为重用链表list.h中的单元结构 52 * struct :队列单元结构定义 53 * 54 55 typedef struct qcellT{ 56 carP car; 57 struct qcellT *next; 58 59 } *qcellP; 60 */ 61 /************************************************************************* 62 *功能描述:创建一个新队列 63 *参数列表: 64 *返回类型: 65 **************************************************************************/ 66 queueADT NewQueue(void); 67 68 /************************************************************************* 69 *功能描述:销毁一个队列 70 *参数列表: 71 *返回类型: 72 **************************************************************************/ 73 void FreeQueue(queueADT queue); 74 75 /************************************************************************* 76 *功能描述:进入队列(自队尾进入) 77 *参数列表:queue:队列实例,num:要进入队列的一个整数 78 *返回类型: 79 **************************************************************************/ 80 void EnQueue(queueADT queue , qcellP cell); 81 82 /************************************************************************* 83 *功能描述:出队列(自队首出) 84 *参数列表: 85 *返回类型:队列单元 86 **************************************************************************/ 87 qcellP DeQueue(queueADT queue); 88 89 /************************************************************************* 90 *功能描述:判断队列是否已满 91 *参数列表: 92 *返回类型: 93 **************************************************************************/ 94 bool QueueIsFull(queueADT queue); 95 96 /************************************************************************* 97 *功能描述: 判断是否为空队列 98 *参数列表: 99 *返回类型: 100 **************************************************************************/ 101 bool QueueIsEmpty(queueADT queue); 102 103 /************************************************************************* 104 *功能描述:打印输出队列内容(由队首到队尾排列) 105 *参数列表: 106 *返回类型: 107 **************************************************************************/ 108 void PrintQueue(queueADT queue); 109 110 #endif 111 /* queue.h ends here */
队列抽象类型的实现 :
1 /* queue.c --- 2 * 3 * Filename: queue.c 4 * Description:队列模型的实现 5 * Author: magc 6 * Maintainer: 7 * Created: 三 8月 15 16:26:17 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 00:51:18 2012 (+0800) 10 * By: magc 11 * Update #: 167 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 20 * 21 * 22 */ 23 24 /* Change Log: 25 * 2012-8-17 修改代码,基于并重用链表抽象类型的。 26 * 27 */ 28 29 /* Code: */ 30 #include <assert.h> 31 #include <ctype.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <string.h> 35 #include <stdarg.h> 36 #include <stdlib.h> 37 #include <stdio.h> 38 #include "../commonlib/genlib.h" 39 #include "queue.h" 40 //为了统一队列与链表抽象类型,将链表类型作为它的一个属性,它的行为也就可以重用链表的了。 41 struct queueCDT{ 42 listADT list; 43 }; 44 45 46 /* 47 * struct :定义队列类型的具体结构,跟实现方式相关 48 * 49 50 struct queueCDT{ 51 qcellP head; //队首 52 qcellP end; //队尾 53 int lenth; //队列成员个数 54 }; 55 56 *****/ 57 /************************************************************************* 58 *功能描述:创建新队列 59 *参数列表: 60 *返回类型: 61 **************************************************************************/ 62 queueADT NewQueue(void){ 63 queueADT queue = New(queueADT); 64 listADT list = NewList(); 65 queue->list = list; 66 return queue; 67 } 68 /************************************************************************* 69 *功能描述:销毁队列 70 *参数列表: 71 *返回类型: 72 **************************************************************************/ 73 void FreeQueue(queueADT queue){ 74 //销毁每个成员 75 } 76 77 /************************************************************************* 78 *功能描述:进入队列(自队尾进入) 79 *参数列表:queue:队列实例,cell:要进入队列的一个整数 80 *返回类型: 81 **************************************************************************/ 82 void EnQueue(queueADT queue , qcellP cell){ 83 // qcellP cell = New(qcellP); 84 // cell->data = num; 85 // cell->next = NULL; 86 AddCellRearList(queue->list,cell); 87 88 } 89 90 /************************************************************************* 91 *功能描述:出队列(自队首出) 92 *参数列表: 93 *返回类型:队列的成员类型 94 **************************************************************************/ 95 qcellP DeQueue(queueADT queue){ 96 if(QueueIsEmpty(queue))return NULL; 97 qcellP temp = RemoveCellAheadList(queue->list); 98 return temp; 99 } 100 101 /************************************************************************* 102 *功能描述:判断队列是否已满 103 *参数列表: 104 *返回类型: 105 **************************************************************************/ 106 bool QueueIsFull(queueADT queue){ 107 return (queue->list->count == MaxQueueLenth); 108 } 109 110 111 /************************************************************************* 112 *功能描述: 判断是否为空队列 113 *参数列表: 114 *返回类型: 115 **************************************************************************/ 116 bool QueueIsEmpty(queueADT queue){ 117 return (queue->list->count == 0); 118 } 119 /************************************************************************* 120 *功能描述:打印单元信息(作为回调函数) 121 *参数列表: 122 *返回类型: 123 **************************************************************************/ 124 125 static void printCar(void *data){ 126 printf("%s,",((carP)data)->number_id); 127 128 } 129 130 /************************************************************************* 131 *功能描述:打印输出队列内容(由队首到队尾排列) 132 *参数列表: 133 *返回类型: 134 **************************************************************************/ 135 void PrintQueue(queueADT queue){ 136 printf("当前队列共%d个成员:",queue->list->count); 137 PrintList(printCar,queue->list); 138 /**** 139 while(cursor != NULL){ 140 printf("%s,",((carP)cursor->data)->number_id); 141 cursor = cursor->next; 142 } 143 ****/ 144 printf("\n"); 145 } 146 147 148 /** 149 int main(int argc, char * argv[]) 150 { 151 queueADT queue = New(queueADT); 152 EnQueue(queue,100); 153 EnQueue(queue,200); 154 EnQueue(queue,300); 155 EnQueue(queue,400); 156 DeQueue(queue); 157 158 PrintQueue(queue); 159 160 FreeQueue(queue); 161 162 163 } 164 **/ 165 166 /* queue.c ends here */
停车场管理主模块:
头文件:
1 /* parking.h --- 2 * 3 * Filename: parking.h 4 * Description: 停车场头文件 5 * Author: magc 6 * Maintainer: 7 * Created: 四 8月 16 11:41:41 2012 (+0800) 8 * Version: 9 * Last-Updated: 四 8月 16 16:37:40 2012 (+0800) 10 * By: magc 11 * Update #: 15 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 20 * 21 * 22 */ 23 24 /* Change Log: 25 * 26 * 27 */ 28 29 /* Code: */ 30 31 #ifndef _parking_h 32 #define _parking_h 33 34 35 36 /* 37 * struct :汽车结构类型定义 38 * 39 */ 40 typedef struct carT{ 41 string start_time; //进停车场时间 42 string end_time; //出停车场时间 43 string number_id; //车牌 44 45 } *carP; 46 47 48 #endif 49 50 /* parking.h ends here */
1 /* parking.c --- 2 * 3 * Filename: parking.c 4 * Description: 停车场管理仿真 5 * Author: magc 6 * Maintainer: 7 * Created: 四 8月 16 09:41:13 2012 (+0800) 8 * Version: 9 * Last-Updated: 六 8月 18 01:14:52 2012 (+0800) 10 * By: magc 11 * Update #: 475 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 20 * 21 * 22 */ 23 24 /* Change Log: 25 * 26 * 27 */ 28 29 /* Code: */ 30 #include <assert.h> 31 #include <ctype.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <time.h> 35 #include <string.h> 36 #include <stdarg.h> 37 #include <stdlib.h> 38 #include <stdio.h> 39 #include "../commonlib/genlib.h" 40 #include "../commonlib/random.h" 41 #include "../commonlib/strlib.h" 42 #include "stack.h" 43 #include "queue.h" 44 #include "parking.h" 45 #define MaxParkNumber 10 //停车场内车位总数 46 #define UnitPrice 10 //每小时收费10 47 48 49 /* 50 * struct :停车场结构定义 51 * 52 */ 53 typedef struct parkT{ 54 int car_total; //当前停车场内车量总数 55 int income_total; //当前停车场的收入总数 56 stackADT car_stack; //停车场内车位 57 queueADT car_queue; //停车场外便道 58 } * parkP; 59 60 61 static string GenCarNumber(void); 62 static parkP NewPark(void); 63 static carP NewCar(); 64 static void EnPartingStack(parkP park,carP car); 65 static void EnParking(parkP park,carP car); 66 static void EnParkingQueue(parkP park , carP car); 67 static bool IsFullParking(parkP park); 68 static bool IsEmptyParking(parkP park); 69 static void DeParking(parkP park,carP car); 70 static void ChargeParking(carP car); 71 static void PrintParking(parkP park); 72 /************************************************************************* 73 *功能描述: 主函数 74 *参数列表: 75 *返回类型: 76 **************************************************************************/ 77 int main(int argc, char * argv[]) 78 { 79 80 parkP park = NewPark(); 81 int i; 82 for (i = 0; i < 15; i++) { 83 carP car = NewCar(); 84 EnParking(park,car); 85 } 86 PrintParking(park); 87 //以下为模拟数据 88 carP car_out = NewCar(); 89 car_out->number_id = "TJ48812"; 90 DeParking(park,car_out); 91 92 car_out->number_id = "TJ87694"; 93 DeParking(park,car_out); 94 95 car_out->number_id = "TJ93196"; 96 DeParking(park,car_out); 97 98 car_out->number_id = "TJ59759"; 99 DeParking(park,car_out); 100 101 car_out->number_id = "TJ44388"; 102 DeParking(park,car_out); 103 104 car_out->number_id = "TJ82153"; 105 DeParking(park,car_out); 106 107 //PrintList(printCar,park->car_stack); 108 PrintParking(park); 109 110 return 0; 111 } 112 /************************************************************************* 113 *功能描述:打印输出当前停车场的车辆信息 114 *参数列表: 115 *返回类型: 116 **************************************************************************/ 117 static void PrintParking(parkP park){ 118 printf("停车场内"); 119 120 printf("\n"); 121 StackPrint(park->car_stack); 122 printf("停车场便道"); 123 124 printf("\n"); 125 PrintQueue(park->car_queue); 126 127 } 128 /************************************************************************* 129 *功能描述:新进汽车 130 *参数列表: 131 *返回类型: 132 **************************************************************************/ 133 static carP NewCar(){ 134 carP car = New(carP); 135 car->number_id = GenCarNumber(); 136 return car; 137 } 138 /************************************************************************* 139 *功能描述:生成随机车牌号 140 *参数列表: 141 *返回类型: 142 **************************************************************************/ 143 static string GenCarNumber(void){ 144 int num = RandomInteger(23000,99999); 145 string number = IntegerToString(num); 146 string prex = "TJ"; 147 string cn = Concat(prex,number); 148 return cn; 149 } 150 /************************************************************************* 151 *功能描述:创建停车场 152 *参数列表: 153 *返回类型: 154 **************************************************************************/ 155 static parkP NewPark(void){ 156 parkP park = New(parkP); 157 park->car_total = 0; 158 park->income_total = 0; 159 park->car_queue = NewQueue(); 160 park->car_stack = NewStack(); 161 return park; 162 } 163 /************************************************************************* 164 *功能描述:进入停车场 165 *参数列表: 166 *返回类型: 167 **************************************************************************/ 168 static void EnParking(parkP park,carP car){ 169 if(IsFullParking(park)){ 170 //场内满时 171 EnParkingQueue(park , car); 172 } 173 else{ 174 //场内有空位时 175 EnPartingStack(park,car); 176 } 177 178 } 179 /************************************************************************* 180 *功能描述:判断停车场内是否占满 181 *参数列表: 182 *返回类型: 183 **************************************************************************/ 184 static bool IsFullParking(parkP park){ 185 return (park->car_total >= MaxParkNumber); 186 } 187 /************************************************************************* 188 *功能描述:判断停车场内是否为空 189 *参数列表: 190 *返回类型: 191 **************************************************************************/ 192 static bool IsEmptyParking(parkP park){ 193 return (park->car_total == 0); 194 } 195 /************************************************************************* 196 *功能描述:进入停车场内部 197 *参数列表: 198 *返回类型: 199 **************************************************************************/ 200 static void EnPartingStack(parkP park,carP car){ 201 car->start_time = "234";//为了简化问题,这里随便设置一个时间 202 stackElement element = New(stackElement); 203 204 element->data = car; 205 element->next = NULL; 206 park->car_total ++; 207 208 Push(park->car_stack,element); 209 printf("车辆:%s进入停车场内\n",car->number_id); 210 } 211 /************************************************************************* 212 *功能描述:进入便道队列 213 *参数列表: 214 *返回类型: 215 **************************************************************************/ 216 static void EnParkingQueue(parkP park , carP car){ 217 qcellP cell = New(qcellP); 218 cell->data = car; 219 cell->next = NULL; 220 EnQueue(park->car_queue,cell); 221 printf("车辆:%s进入便道队列\n",car->number_id); 222 } 223 /************************************************************************* 224 *功能描述:出场 225 *参数列表: 226 *返回类型: 227 **************************************************************************/ 228 static void DeParking(parkP park,carP car){ 229 printf("%s出场\n",car->number_id); 230 231 stackADT stack_temp = NewStack(); ///创建一个临时栈,用来为车让道时暂存。 232 stackElement elem_temp = NULL; 233 elem_temp = Pop(park->car_stack); 234 //比较当前临时弹出的车辆号码 235 while(elem_temp->data!=NULL){ 236 if (StringEqual(((carP)elem_temp->data)->number_id,car->number_id)){ 237 break;// 当找到要走的车辆时,终止循环 238 } 239 Push(stack_temp,elem_temp);//将让道的车辆放入临时栈中 240 241 elem_temp = Pop(park->car_stack); //继续弹出 242 243 } 244 if(elem_temp == NULL){ 245 printf("在停车场内未找到%s\n",car->number_id); 246 } 247 ((carP)elem_temp->data)->end_time = "2343";//为了简化问题,这里随便设置一个时间 248 ChargeParking((carP)(elem_temp->data)); 249 //将临时栈中车辆依次放回停车场内 250 elem_temp = Pop(stack_temp); 251 while(elem_temp!=NULL){ 252 /// elem_temp->next = NULL; 253 Push(park->car_stack,elem_temp); 254 elem_temp = Pop(stack_temp); 255 256 } 257 //要從便道上隊首的車開進停車場內 258 elem_temp = DeQueue(park->car_queue); //是否可以统一单元类型 259 if(elem_temp!=NULL){ 260 // elem_temp->next = NULL; //置NULL的过程应该由queue.c来完成 261 Push(park->car_stack,elem_temp); 262 263 } 264 265 266 } 267 /************************************************************************* 268 *功能描述:出场,收费 269 *参数列表: 270 *返回类型: 271 **************************************************************************/ 272 static void ChargeParking(carP car){ 273 printf("车辆:%s 出场时间:%s,入场时间:%s\n",car->number_id,car->end_time,car->start_time); 274 275 } 276 /* parking.c ends here */
注:
1)时间仓促,此程序虽然经过两三天工作之余的精雕细琢,注重模块化和抽象化及代码重用,仍然有很多地方需要修改和细化。
2)模拟数据有些简单,大概验证了一下程序的运行效果。
在gcc下运行结果如下:
小结:
1)分析一个问题,一般经过“逐步求精”策略,将大问题划分为多个小问题,然后将各环节,进一步分解为相对独立的方法函数来实现,在数据类型上,可以抽象出相对独立的ADT,如这里我们抽象出多个,如链表,堆栈及队列,而其中链表又作为堆栈和队列的基础类型(重用链表,采用了将链表作为一个结构的属性,相应行为的底层实现就可以利用链表的了)。
2)注意体会模块化开发带来的好处,例如,模块化之后,将程序分解为不同的层次,不同的功能,使程序结构清晰,便于分工合作和集成,开发效率提高,好处多多。
3)注意体会这种一个类型重用另一个类型的方式,如这里链表、堆栈和队列采用相同的单元结构,为了不破坏每个接口定义,将这个公共的结构listCDT都单独放到一个文件里,使相应文件便于引用,不知是否还有其它方式,有待考究。
附件:源代码