系统程序员成长计划-Write once, run anywhere(WORA)(下)
2,338 views| 2008-11-10| 李先静| 系统程序员成长计划| | 6 条评论转载时请注明出处和作者联系方式
文章出处:http://www.limodev.cn/blog
作者联系方式:李先静 <xianjimli@gmail.com>
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++中调用这里的函数,编译器不能对函数名进行重新编码。
完整的接口
作为一个通用的链表,接口要比较完整才行,否则无法满足各种情况的需要(提供完整的接口并不违背最小接口原则)。实现具有完整接口的链表不是件容易的事,读者先实现插入删除等基本操作就行了,后面我们会慢慢扩展它的功能。
(为了避免读起来拗口,本文把双向链表简写成链表了,希望读者不要介意)
系统程序员成长计划 Share
Comments
Tags
Recent Posts
Most Viewed
- 系统程序员成长计划写作提纲 - 19,605 views
- Android IPC机制详解 - 6,277 views
- 系统程序员成长计划-走近专业程序员(上) - 6,253 views
- 系统程序员成长计划-写得又快又好的秘诀(一) - 5,391 views
- 系统程序员成长计划-背景知识 - 5,070 views
- i++循环与i–循环的执行效率 - 4,712 views
- 系统程序员成长计划-Write once, run anywhere(WORA)(上) - 4,701 views
- 系统程序员成长计划-走近专业程序员(下) - 4,254 views
- Linux下的调试工具 - 4,017 views
- Advanced Linux Sound Architecture (ALSA) 研究笔记 - 4,017 views
- 系统程序员成长计划-序 - 3,985 views
- 系统程序员成长计划-写得又快又好的秘诀(三) - 3,930 views
- 中国人与自由软件文化研究(搞笑版) - 3,735 views
- Android中的MessageQueue,Handler,Looper和Thread - 3,686 views
- 答复:我不会OOO,仍然可以XXX - 3,659 views
Categories
- Android (28)
- Broncho-A1-Hack (6)
- DirectFB (7)
- FTK(嵌入式GUI) (24)
- GTK+ (29)
- KVM hack notes (8)
- Linux Mobile (65)
- Management (5)
- Mozilla (9)
- Open Source (5)
- Programming (34)
- Tools (9)
- Uncategorized (23)
- Win32 (3)
- X Windows (31)
- 沉思录 (29)
- 系统程序员成长计划 (67)
Blogroll
gallery
Linux guru
推荐网站
Recent Comments
- Dig on 嵌入式GUI FTK设计与实现-事件源(FtkSource)
- 用心生活每一天 » GNU gprof: linux profiling tools 使用 on gcc profiling的工作原理
- JavaScript for: i++ vs i–-传播、沟通、分享-一直“有你” on i++循环与i–循环的执行效率
- Frankly Law on 嵌入式GUI FTK介绍(11)-交叉编译
- tracing on Linux下的调试工具
- ndljsn on FTK移植指南(初稿)
- tracing on 爬塘朗山
- tracing on GTK+(基于DirectFB)的字体处理
- Kely on 系统程序员成长计划写作提纲
- tracing on 爬塘朗山



November 10th, 2008
yetiboy
November 11th, 2008
在笔记本上看,字体太大!(firefox字体大小默认+允许网页选择自己的字体风格)
越来越像我们离散作业习题了 >_<
这样的void*结构致使有些对链表的操作需要额外的回调函数,似乎有点不那么通用了。感觉还是linux内核中实现的generic链表结构通用,针对性也非常的强。 但是又没有怎么见到在内核之外用过(当然由我自己孤陋寡闻的原因)。
admin
November 11th, 2008
呵,字体还是改为14pt吧。
你的意见很好。linux kernel中的双向链表确实有些创意,它一反常态以容器为主,数据结构要为容器服务,在特定的应用环境中有一定的通用性。但它的问题在于假设数据结构一定要存放于容器中,而且被定死要存放到双向链表中,这在正常情况是不能被接受的,我想这就是它很难推广的原因。
meierduo
November 26th, 2008
博主,我是菜鸟级的,也没有做过实际应用。想问个问题,对于如上的通用链表,如果打印的时候要回调函数。那么是否,链表元素输入的时候也要调用回调函数,因为我们预先也不知道输入元素的数据类型?
admin
November 26th, 2008
to meierduo: 链表的实现者不知道里面存的什么类型,使用者当然是知道的,否则这个链表还有什么用。
The linux mobile development » Blog Archive » 系统程序员成长计划写作提纲
May 25th, 2009
[...] 1.2 谁动了你的隐私(上)(下) 1.3 Write once, run anywhere(WORA)(上)(下) 1.4 拥抱变化(上)(下) 1.5 Don’t Repeat Yourself(DRY) (上)(下) 1.6 [...]
luqi
August 24th, 2009
关于通用链表的问题,intel有提供’bothway linked list utility’,很好用的.一直在看lz的文章,很有启发,感谢了
struct XLinkedListNode
{
void *Data;
struct XLinkedListNode_Root *Root;
struct XLinkedListNode *Next;
struct XLinkedListNode *Previous;
};