std::list 循环删除指针_数据结构和算法分析 2.5循环链表

回到家之后,多花时间陪陪家人,多干家务,少学习b06f17298874fb6ea9ad73164be80ad4.png

从单链表升级到双链表之后,很多操作一下子就变得简单容易了。 

但有一个很麻烦的问题始终没有解决:如何从任意结点出发通过遍历访问所有结点?

下面的循环链表就是这个问题的解决方案。

循环单链表

8ef687b37e32dccddcb2c91ec3f9c474.png将单链表尾结点的指针由 NULL 改为指向头结点,整个链表形成一个环。从表中任一结点出发均可找到链表中其他结点。

「循环单链表」「非循环单链表」的不同之处在于:

  • 循环单链表没有 NULL 指针
  • p 所指节点为尾节点的条件:p->next == L

例 1

某线性表最常用的操作是:在尾元素之后插入一个元素和删除第一个元素

采用下列哪种存储方式最节省运算时间

A. 单链表

B. 仅有头结点指针的循环单链表

C. 双链表

D. 仅有尾结点指针的循环单链表

四种结构删除第一个元素的时间复杂度都是 O(1),现在仅需考虑在尾结点后插入新元素的操作。要在尾结点之后插入元素首先要找到尾结点

  • 单链表遍历整个链表找到尾结点的时间复杂度为 O(n)
  • 仅有头结点的指针的循环单链表,尽管首尾相连,但只有一个指向头结点的指针,仍要通过遍历链表来找到尾结点,插入的时间复杂度为 O(n)
  • 双链表,尽管可以反向遍历,但首尾没有相连,仍需要遍历链表来找到尾结点,插入的时间复杂度也为 O(n)
  • 仅有尾结点指针的循环链表找到尾结点的时间复杂度为 O(1)
插入删除
单链表O(n)O(1)
仅有头结点指针的循环单链表O(n)O(1)
双链表O(n)O(1)
仅有尾结点指针的循环单链表O(1)O(1)

「仅有尾结点指针的循环链表」的插入函数和删除函数如下所示

voidlistInsert( node **l, int e ){
  node *s;
  s = ( node* )malloc( sizeof( node ) );
  s->data = e;
  s->next = (*l)->next;
  (*l)->next = s;
  *l = s;
}
voidlistDelete( node *l ){
  node *t;
 t = l->next;
  l->next = l->next->next;
  free( t );
}

循环双链表

601fe5b13a6d78709951604b2337e49f.png在双向链表的基础上修改头结点和尾结点的指针域,形成两个环。

「循环双链表」「非循环双链表」的不同之处:

  • 循环双链表没有 NULL 指针
  • p 所指结点为尾结点的条件:p->next == L
  • 由L可以直接找到尾结点:L->prior

例 2

如果含有 n( n > 1 )个元素的线性表的运算只有 4 种

  1. 删除第一个元素
  2. 删除尾元素
  3. 在第一个元素前面插入新元素
  4. 在尾结点的后面插入新元素

最好使用下列哪个存储方式

A. 只有尾结点指针没有头结点的循环单链表

B. 只有尾结点指针没有头结点的非循环双链表

C. 只有首结点指针没有尾结点指针的循环双链表

D. 既有头指针又有尾指针的循环单链表

和上面的例1类似,抓住四个操作的本质,分析它们在对应的存储结构下工作的时间复杂度

  1. A选项的结构删除尾元素时要通过遍历找到尾元素之前的结点
  2. B选项的结构对第一个元素操作时先要通过遍历找到头结点
  3. C选项的结构完成4个操作的时间复杂度都是O(1)
  4. D选项的结构删除尾元素时要通过遍历找到尾元素之前的结点
1234
AO(1)O(n)O(1)O(1)
BO(n)O(1)O(n)O(1)
CO(1)O(1)O(1)O(1)
DO(1)O(n)O(1)O(1)
可见 「只有首结点指针没有尾结点指针的循环双链表」 的效率最高,对应的函数如下所示
voidheadDelete( node **l ){
  node *t = *l;
  (*l)->prior->next = (*l)->next;
  (*l)->next->prior = (*l)->prior;
  *l = (*l)->next;
  free( t );
}
voidtailDelete( node *l ){
  node *t = l->prior;
  l->prior->prior->next = l;
  l->prior = l->prior->prior;
  free( t );
}
voidlistInsert( node *l, int e ){
  node *s;
  s = ( node* )malloc( sizeof( node ) );
  s->data = e;
  s->next = l;
  l->prior->next = s;
  s->prior = l->prior;
  l->prior = s;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值