新的起点
做自己喜欢并适合的事情

导航

 

  线性表Arrary List也就是基于数组实现的表结构,由于基于数组实现,所以其特点非常明显:随机访问(访问指定序号的节点)时间开销O(1),插入删除(在当前位置插入删除)时间开销O(N)。

  表结构的操作主要有创建、插入(头、尾、当前位置)、删除(头、尾、当前位置)、查找(指定键值、指定序号)和游走(指向头、尾、上一个节点、下一个节点),一般来讲基于数组的表结构都是预先指定最大容量,这样使用起来会比较不方便,所以可以利用realloc实现表结构的扩容。

  Arrary List实现的代码可以参见附件(辅助异常检查CheckError.h,头文件AList.h,代码文件AList.c,模块功能测试ListDemo.c),下面主要讨论实现过程中的一些问题:

1.从程序稳定性的角度,必须对可能引起程序崩溃的函数参数以及状态进行检查,所以除了计算指定最大节点数量计算所需内存字节数的ALIST_get_size直接返回int,其他各函数均返回HRESULT状态码,然后在外部调用后应当检查hr值是否为RET_S_OK,以便确认函数调用成功,当然ListDemo仅是对函数功能是否正常进行验证以及演示如何使用,这些检查没有加入。PS,如果是声明为static的内部函数,由于进入其他函数已经检查状态,并且如果调用这些函数时可以保证不会出现异常,个人认为可以省略这些检查。

这样的做法与有一些库函数直接使用NULL,-1等值表示调用失败应该是更好一些(通过查看hr的具体值可以知道具体的错误原因)。

2.ALIST的定义如下:

// ALIST结构定义
typedef struct tagALIST
{
    int            max_count;    // 最大长度
    int            used_count;   // 已经使用长度
    int            curr;         // 当前节点的位置
    ALIST_NODE    nodes[1];      // ALIST的第一个节点
} ALIST;

 

这里nodes声明为长度为1的数组而非指针,其好处在于配合get_size或者直接create函数一次直接分配ALIST以及表的节点所需的内存,避免了二次申请内存或者将指针指向内存位置的操作(如一次分配LIST+NODES的内存,再将nodes指向LIST结束后的第一个位置),该思路源于gdi中颜色调板的数据结构设计。同时,这样做也可以防止创建长度为0的表结构导致head和tail无效。

3.CHECK_REALLOC的宏定义如下

#define CHECK_REALLOC(type, ptr, new_size)  \
{                                           \
    void *tmp;                              \
    tmp = (type)realloc(ptr, new_size);     \
    CHECK_ERROR_HR(NULL == tmp,             \
                   ERR_RET_MEM_ALLOC,       \
                   ERR_MSG_MEM_ALLOC);      \
    ptr = tmp;                              \
}

 

使用tmp临时指针避免realloc失败(内存不足,不能够分配指定长度的内存,realloc保持原先的内存分配并返回NULL)导致原指针值为NULL而导致原先的内存泄漏。

 

Alist的相关代码

                                    BSKER于2011.11.06

posted on 2011-11-06 00:05  Kevin W  阅读(214)  评论(0编辑  收藏  举报