`
阿尔萨斯
  • 浏览: 4202491 次
社区版块
存档分类
最新评论

系统程序员成长计划-Write once, run anywhere(WORA)(下)

 
阅读更多

1.专用链表和通用链表各自的特点与适用范围。

专用链表在这里是指它的实现和调用耦合在一起,只能被一个调用者使用,而不能单独在其它地方被重用。通用链表则相反,它具有通用性,可以在多处被重复使用。尽管通用链表相对专用链表来说有很多优越之处,不过简单的断定通用链表比专用链表好也是不公正的,因为它们都有自己的优点和适用范围:

专用链表的优点:

更高性能。专用链表的实现和调用在一起,可以直接访问数据成员,省去了包装函数带来的性能开销,可以提高时间性能。专用链表无需实现完整的接口,只要满足自己的需要就行了,生成的代码更小,因此可以提高空间性能。

更少依赖。自己实现不用依赖于别人。有时候你要写一个规模不大的跨平台程序,比如想在展讯手机平台和MTK手机平台上运行,虽然有现存的库可用,但你又不想把整个库移植过去,那么实现一个专用链表是不错的选择。

实现简单。实现专用链表时,不需要考虑在各种复杂应用情况下的特殊要求,也不需要提供完整的接口,所以实现起来比通用链表更为简单。

通用链表的优点(从全局来看):

可靠性更高。通用链表的实现要复杂得多,复杂的东西意味着不可靠。但它是可以重复使用的,其存在的问题会随每一次重用而被发现和改正,慢慢的就行成一个可靠的函数库。

开发效率更高。通用链表的实现要复杂得多,复杂的东西也意味着更高的开发成本。同样因为它是可以重复使用的,开发成本会随每一次重用而降低,从整个项目来看,会大大提高开发效率。

考虑到链表是最常用的数据结构之一,很多地方都会用到它,实现通用的链表会更有价值。接下来我们要实现一个通用的链表,不过请大家记住,实现通用的链表并不是我们的目标,而是我们学习软件设计方法的手段。前面我许诺过要以简单的数据结构讲述复杂的软件设计方法,链表就是其中的载体之一。

2.如何编写一个通用的链表?

编写通用链表是一项复杂的任务,不可能在这一节中把它阐述清楚,这里我们先考虑三个问题:

存值还是存指针

通用链表首先是要做能够存放任何数据类型的数据,新手常见的做法是定义一个抽象数据类型,需要什么存放什么就定义成什么。如:

typedef int Type;
typedef struct _DListNode
{
    struct _DListNode* prev;
    struct _DListNode* next;
    Type data;
}DListNode;

这样的链表算不上是通用的,因为你存放整数时编译一次,存放字符串时,重义Type再编译一次,存放其它类型同样要重复这个过程。麻烦不说,关键是没有办法同时使用多个数据类型。我们要找到一种同时可以表示不同数据类型的类型才行,有人说可以用union,但是数据类型是无穷无尽的,不可能在union中表示它们的全部。

可行的办法有两种:

存值:

typedef struct _DListNode
{
    struct _DListNode* prev;
    struct _DListNode* next;
    void*  data;
    size_t length;
}DListNode;

存入时拷贝一份数据,保存数据的指针和长度。考虑到拷贝数据会带来性能开销,不合符C语言的风格,而且C语言中没有构造函数,实现深拷贝比较麻烦,所以在C语言中以这种方式实现的链表很少见。

存指针:

typedef struct _DListNode
{
    struct _DListNode* prev;
    struct _DListNode* next;
    void*  data;
}DListNode;

只是保存指向对象的指针,存取效率高,是C语言中常见的做法。在存放整数时,可以把void*强制转换成整数使用,以避免内存分配(在现实中,90%以上的情况,链表都是存放结构的)。

让C++可以调用

这不是一个重要的话题,只是顺便提一下。C++中允许同名函数存在,所以编译器会对函数名重新编码。C++代码包含C语言的头文件时,重新编码名字与C语言库中的原函数名不一致,结果造成找不到函数的情况。为了让C语言实现的函数在C++中可以调用,需要在头文件中加点东西才行:

#ifdef __cplusplus
extern "C" {
#endif
…
#ifdef __cplusplus
}
#endif

它表示如果在C++中调用这里的函数,编译器不能对函数名进行重新编码。

完整的接口

作为一个通用的链表,接口要比较完整才行,否则无法满足各种情况的需要(提供完整的接口并不违背最小接口原则)。实现具有完整接口的链表不是件容易的事,读者先实现插入删除等基本操作就行了,后面我们会慢慢扩展它的功能。

(为了避免读起来拗口,本文把双向链表简写成链表了,希望读者不要介意)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics