学习ADT有一周了,从了解到使用,慢慢找到了一点感觉,通过一系列的基础数据类型如堆栈,队伍,扫描器等常见结构模型练习体会它的威力。这些大多都参考自《程序设计抽象思想-C语言描述》,但不是照搬过来了,为了真正提高自己的基本技能,尽力自己独立完成,遇到再去参考大师的思路,这样一方面提高自己的动手能力,另一方面明确了自己的问题,有针对性地学习别人的长处。
ADT在模块化开发中发挥了极其重要的作用,它可使一个复杂程序变得有层次,更模块化,易于开发和重用。首先它将一般程序划分为接口,实现和客户端三层,每层都有自己的职责,应用到实现中可能是三组不同的人员,在一定程序上,使这三层关系分明,如接口是通过一个头文件,定义一个抽象数据类型,及其行为,实现层依照接口定义,实现底层表示和行为的实现代码,而且底层表示和实现是有一定自由的,可根据实际,选择高效的实现方式;而客户端作为接口的使用者,对接口的实现层并不了解,也不需要了解。只需根据接口定义及其说明,来调用相应的行为函数,来完成复杂的任务。
借用一下书中插图,让这个层次关系更直观一点点:
注:不同层之间通过指针来传递数据和地址,完成协作的
这里将《C编程思想之抽象数据类型(ADT)(一)》博文中的堆栈抽象类型重新用链表形式实现一次,这也体现了接口的意义,只注重行为,不限制底层限制,这里同样还是那个接口stack.h,只是将底层实现由数组形式,改成了链表形式。
废话少说,让我们直奔代码:
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月 15 12:00:08 2012 (+0800) 10 * By: magc 11 * Update #: 62 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * ADT 接口 20 * 只定义行为,而不限制底层表示和实现 21 * 22 */ 23 24 /* Change Log: 25 * 26 * 27 */ 28 29 /* Code: */ 30 #ifndef _stack_h 31 #define _stack_h 32 #include "../commonlib/genlib.h" 33 34 #define MaxStackSize 100 35 36 37 38 typedef struct stackCDT *stackADT; 39 40 typedef struct cellT{ 41 int data; 42 struct cellT *next; 43 } * stackElement; 44 45 /************************************************************************* 46 *功能描述:创建新堆栈 47 *参数列表: 48 *返回类型:堆栈指针 49 **************************************************************************/ 50 stackADT NewStack(void); 51 52 /************************************************************************* 53 *功能描述:释放堆栈内存空间 54 *参数列表: 55 *返回类型: 56 **************************************************************************/ 57 void FreeStack(stackADT stack); 58 59 /************************************************************************* 60 *功能描述:压栈 61 *参数列表: 62 *返回类型: 63 **************************************************************************/ 64 void Push(stackADT stack ,int data ); 65 66 /************************************************************************* 67 *功能描述:出栈 68 *参数列表: 69 *返回类型:弹出的元素 70 **************************************************************************/ 71 int Pop(stackADT stack); 72 73 /************************************************************************* 74 *功能描述:判断当前栈是否为空 75 *参数列表: 76 *返回类型:TRUE or FALSE 77 **************************************************************************/ 78 bool StackIsEmpty(stackADT stack ); 79 80 /************************************************************************* 81 *功能描述:判断当前栈是否已满 82 *参数列表: 83 *返回类型: 84 **************************************************************************/ 85 bool StackIsFull(stackADT stack); 86 87 /************************************************************************* 88 *功能描述:获取当前栈的深度 89 *参数列表: 90 *返回类型: 91 **************************************************************************/ 92 int StackDepth(stackADT stack); 93 94 /************************************************************************* 95 *功能描述:读取堆栈顶端元素值 96 *参数列表: 97 *返回类型: 98 **************************************************************************/ 99 int StackTop(stackADT stack); 100 101 /************************************************************************* 102 *功能描述:打印堆栈元素的内容 103 *参数列表: 104 *返回类型: 105 **************************************************************************/ 106 void StackPrint(stackADT stack); 107 108 #endif 109 /* 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月 15 15:10:24 2012 (+0800) 10 * By: magc 11 * Update #: 184 12 * URL: 13 * Keywords: 14 * Compatibility: 15 * 16 */ 17 18 /* Commentary: 19 * 底层采用链表的形式实现堆栈 20 * 同样实现stack.h接口中的行为 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 <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 :堆栈的底层实现的结构定义 43 * 44 */ 45 struct stackCDT { 46 stackElement head; //记录堆栈第一个元素地址,即栈顶 47 int depth; //记录堆栈深度,即元素总个数 48 }; 49 /************************************************************************* 50 *功能描述:创建新堆栈实例 51 *参数列表: 52 *返回类型:空堆栈 53 **************************************************************************/ 54 stackADT NewStack(void){ 55 stackADT stack = New(stackADT); 56 stack->head = NULL; 57 stack->depth = 0; 58 } 59 60 /************************************************************************* 61 *功能描述:释放堆栈内存空间(每个元素的空间都需要释放) 62 *参数列表: 63 *返回类型: 64 **************************************************************************/ 65 void FreeStack(stackADT stack){ 66 stackElement element = stack->head; 67 while(element != NULL){ 68 stack->head = element->next; 69 FreeBlock(element); 70 element = stack->head; 71 } 72 FreeBlock(stack); 73 } 74 75 76 /************************************************************************* 77 *功能描述:压栈 head始终指向栈顶,压栈是从head端添加元素 78 *参数列表: 79 *返回类型: 80 **************************************************************************/ 81 void Push(stackADT stack ,int data){ 82 //先创建一个元素 83 stackElement element = New(stackElement); 84 element->data = data; 85 element->next = NULL; 86 //将新元素添加到栈顶 87 if(stack->head == NULL){ 88 stack->head = element; 89 stack->depth++; 90 } 91 else{ 92 stackElement element_temp = stack->head; 93 stack->head = element; 94 element->next = element_temp; 95 stack->depth++; 96 } 97 printf("%d进栈\n",data); 98 99 } 100 101 /************************************************************************* 102 *功能描述:出栈(将栈顶元素弹出) 103 *参数列表: 104 *返回类型:弹出的元素 105 **************************************************************************/ 106 int Pop(stackADT stack){ 107 if(stack == NULL){ 108 Error("堆栈为NULL"); 109 } 110 if(StackIsEmpty(stack)){ 111 return NULL; 112 } 113 stackElement element_temp = stack->head; 114 stack->head = stack->head->next; 115 stack->depth--; 116 int res = element_temp->data; 117 FreeBlock(element_temp);//注意弹出的同时,释放该元素所占内存空间 118 119 printf("弹出元素%d\n",res); 120 return res; 121 } 122 123 /************************************************************************* 124 *功能描述:判断当前栈是否为空 125 *参数列表: 126 *返回类型:TRUE or FALSE 127 **************************************************************************/ 128 bool StackIsEmpty(stackADT stack ){ 129 return (stack->head == NULL); 130 } 131 /************************************************************************* 132 *功能描述:判断当前栈是否已满 133 *参数列表: 134 *返回类型: 135 **************************************************************************/ 136 bool StackIsFull(stackADT stack){ 137 return (stack->depth == MaxStackSize); 138 } 139 140 141 /************************************************************************* 142 *功能描述:获取当前栈的深度 143 *参数列表: 144 *返回类型: 145 **************************************************************************/ 146 int StackDepth(stackADT stack){ 147 return stack->depth; 148 } 149 150 /************************************************************************* 151 *功能描述:读取堆栈顶端元素值 152 *参数列表: 153 *返回类型: 154 **************************************************************************/ 155 int StackTop(stackADT stack){ 156 if(stack->depth == 0)return NULL; 157 return stack->head; 158 } 159 160 161 /************************************************************************* 162 *功能描述:打印堆栈元素的内容 163 *参数列表: 164 *返回类型: 165 **************************************************************************/ 166 void StackPrint(stackADT stack){ 167 if(stack->depth == 0) return ; 168 printf("共%d个元素:",StackDepth(stack)); 169 stackElement element = NULL; 170 for(element = stack->head;element!=NULL;element = element->next){ 171 printf("%d,",element->data); 172 } 173 printf("\n"); 174 175 } 176 177 178 /************************************************************************* 179 *功能描述:主函数 180 *参数列表: 181 *返回类型: 182 **************************************************************************/ 183 int main(int argc, char * argv[]) 184 { 185 stackADT stack = NewStack(); 186 Push(stack,45); 187 Push(stack,55); 188 Push(stack,66); 189 Pop(stack); 190 191 StackPrint(stack); 192 printf("\n"); 193 194 195 } 196 197 198 199 200 201 202 203 /* stack1.c ends here */
注: 这里为了检测功能,在stack.c中添加了main函数,若去掉main函数,就可作为独立的模块,应用在其它应用程序中了。
在GCC下编译运行的结果为:
小结:
1)接口 stack.h中定义了不完全类型stackCDT,这里只是声明了抽象类型的名字,具体结构的定义,交给实现层stack.c 来定义,因为它是数据类型的底层表示,会随底层的实现形式的变化而变化,同时也也遵守了接口的原则:只重行为,不限制实现形式。
2)stackCDT结构定义中包含了一个链表的头指针,这是由于堆栈指针需要跨越接口和实现层,当作为空链表时,有了这个,链表虽为NULL,但仍能通过结构stackCDT的指针来实现跨越层,假若不用这个结构指针来操作链表,则当链表为空时,就无法跨层了。