现在的位置: 首页 > 综合 > 正文

ADT实现的改进

2013年09月10日 ⁄ 综合 ⁄ 共 2021字 ⁄ 字号 评论关闭

      在前面关于ADT堆栈、队列、二叉搜索树的实现都是简单的实现方式,目的是对这几种常见的ADT有一个实现方式的认识,在实际的编程中,前面的几种实现方式限制太多,最主要的一个问题是它们把用于保存结构的内存和那些用于操纵它们的函数都封装在一起了,如果一个程序需要不止一个的堆栈,那么这种封装形式如何实现超过一个的堆栈呢?几乎无法实现。

      这个限制的改进方式比较简单,以数组形式的堆栈为例:我们需要将实现模块中关于数组的声明和top_element的声明去除。把它放入用户代码模块,然后通过指向此数组的指针参数被堆栈函数访问,这样实现模块中的函数就不再固定于某个数组了。用户可以创建任意数量的数组,并通过调用堆栈函数将这些数组作为堆栈使用。

注意:这种方式将使这个堆栈数组失去了封装性,因为数组是由用户创建的,用户了解数组的全部细节,用户可以不通过堆栈函数直接访问数组,例如在不是栈顶的位置增加一个新值或者加一个新值但不调整top_element的值这些都将导致数据丢失或者非法数据或者导致堆栈函数运行。而避免发生这些问题的责任就交给用户

还存在一个问题是用户必须确保向堆栈函数传递正确的堆栈和top_element参数,也就是说传递的堆栈必须对应相应的top_element,如果参数发生混淆,其结果就是垃圾,这个问题有一个比较好的解决方式是将堆栈数组和它的的top_element值捆绑在一个结构中来避免发生这种情况。

拥有超过一种的类型:有之前的几种ADT的实现也可以知道,ADT 的类型在头文件的定义,还是以堆栈为例,堆栈的类型在stack.h头文件中定义,如果同时需要一个整数堆栈和一个浮点堆栈,此前的实现方式就无能为力了。解决这个问题有三种方式:

1、另外编写一份堆栈函数的拷贝,用于处理不同的数据类型,这种方式可以达到目的,但涉及大量重复代码,这就是的程序的维护工作变得更加困难。

2、更为优雅的方法是把整个堆栈模块实现为一个#define宏,把目标类型作为参数。然后便可以用于创建每种目标类型的堆栈函数,但是这里引入一个新问题,我们必须找到一种方法为不同类型的堆栈函数产生独一无二的函数名,这样他们之间不会互相冲突,并且每种类型只能创建一组函数。

3、存储一个void *类型的值。将整数和其他数据都按照一个指针的空间进行存储,使用强制类型转换把参数的类型转换为void * 后再执行push函数,top函数返回的值再转换回原先的类型。为了使堆栈也使用与较大的数据(例如结构),可以在堆栈中存储指向数据的指针。注意:这种方式绕过了类型检查,我们没有办法正式传递给push函数的值正式堆栈所使用的正确类型,如果一个整数意外地压入到一个元素类型为指针的堆栈中,其结果可想而知。

         下面就针对第二种方法来实现多个堆栈(用数组实现)。

 

1、使用宏的实现方式(文件保存为:stack.h文件):

 

         

 

        调用这个宏的方式:

 

         

        实际上使用上面的这种方式可以模拟面向对象语言中的泛型特性。

 

 

抱歉!评论已关闭.