算法精解二十二(C语言版)

单链表的实现与分析

         回顾一下链表元素的组成;一个数据成员和一个指向链表中下一个元素的指针。结构 体ListElmt表示链表中的单个元素(见实例5-1).如你所料,这个结构体拥有两个成员,就是前面介绍的数据成员和指针成员。结构体系List则表示链表这种数据结构(见实例5-1).这个结构体由5个成员组成;size表示链表中的元素个数;match并不有链表本身使用,而是有从链表数据结构派生而来的新类型所使用;destroy是封装之后传递给list_init的析构函数;head是指向链表中头结点元素的指针;tail则是指向链表中末尾结点元素的指针。


List_init

list_init用来初始化一个链表以便能够执行其他的操作(见实例5-2).初始化链表是一宗简单的操作,只要把链表的size成员设置为0,把函数指针成员destroy设置为定义的析构函数,head和tail指针全设置为NULL即可。

list_init的复杂度为O(I),因为初始化过程中的所有步骤都能在一段恒定的时间内完成。


List_destory

list_destory用来销毁链表(见示例5-2),其意义就是移除链表中的所有元素。如果调用list_init时destory参数不为NULL,则当每个元素被移除时都调用list_destrory一次。

list_destroy的运行时复杂度为O(n),n代表链表中的元素个数,这是因为list_rem_next的复杂度为O(1),  而移除每个元素时都调用list_rem_next一次。

list_ins_next

list_ins_next将一个元素插入由element参数所制定的元素之后(见示例5-2)该调用将新元素的数据指向有用户传递进来的数据。向链表中插入新元素的处理步骤很简单,但需要特别小心。有两种情况需要考虑:插入链表头部和插入其他位置。

一般来说,要把一个元素插入链表中,需要将新元素的next指针指向它之后的那个元素,然后将新元素位置之前的结点next指针指向新插入的元素(见图5-3).但是,当从链表头部插入时。新元素之前没有别的结点了。因此,在这种情况下,将新元素的next指针指向当前链表的头部,然后重置头结点指针,使其指向新元素。回顾一下前一节中的接口设计,当传入的element为NULL时代表新的元素将插入链表头部。另外需要注意的是。无论何时当插入的元素位于链表末尾时,都必须更新链表数据结构的tail成员使其指向新的结点。最后,更新统计链表中结点个数的size成员。


List_rem_next

list_rem_next从链表中移除由element所指定的元素之后的那个结点(见示例5-2).移除element之后的那个结点而不是移除elenent本身,关于为何要这样设计将在“问与答”中进行讨论。通插入结点类似,这个调用也需要考虑两个因素:移除的是头结点以及移除其余位置上的结点。

移除操作时很简单的,但同样需要注意一些细节问题(见图5-4).一般来说,为了从链表中移除vhuyige元素,将要移除的目标结点前一个元素的next指针指向目标结点的下一个元素。但是,移除的目标结点是头结点时,目标结点之前并没有其他元素了。因此。在这种情况下,子需要将链表的head成员指向结点的下一个元素。同插入 操作一样。当传入的element为NULL时代表链表的头结点需要移除。另外,无论何时当移除的目标结点是链表的尾部结点时,都必须更新链表结构数据中的tail成员,使其指向  新的尾结点,或者当移除操作似的整个链表成为空链表时需要tail设置为NULL.

最后,更新链表的szie成员,使其减1.当这个调用返回时data将指向已移除结点的数据域。

这些宏实现了链表中的一些简单操作(见示例5-1).一般来说,它们提供了快速访问和检测List和ListElmt结构体成员的能力。

这些操作的运行时复杂度是O(1),因为访问和检测结构体的成员都可以在恒定的时间内完成。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值