学习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的指针来实现跨越层,假若不用这个结构指针来操作链表,则当链表为空时,就无法跨层了。