数据结构之循环链表和双向链表

标签: 数据结构 循环链表 双向链表 c
11人阅读 评论(0) 收藏 举报
分类:

数据结构之循环链表和双向链表

1.循环链表

循环链表是另一种形式的链式存储结构,其特点是单链表的最后一个结点的指针不为空,而是指向头结点(带头结点的链表)或第一个结点(不带头结点的链表),整个链表形成一个。这样从链表任何一个位置出发,均可以找到表中的其他结点。循环链表根据指针域是一个还是多个,可以分为单循环链表多重循环链表

对于单循环链表而言,判断链表是否为空不再是panda头结点的指针是否为空,而是判断头结点的指针是否指向自身,如上图所示。循环链表基本操作的算法和单链表没什么区别,只是循环结束条件(表尾)不再是判断指针pp->next是否为空,而是判断他们是否等于头结点。

有些时候,循环链表中设一个指向表尾的尾指针对某些应用更加方便。这样,尾指针访问头结点和尾结点都非常方便,相当于既指向了头结点,又指向了尾结点。如把由尾指针指引的单循环链表表示的线性表A和B进行合并(即将A和B合并成一个链表),实现起来非常方便。只需要修改两个指针即可,其运算时间为O(1)。代码如下:

q = B->next;        // q指向B的头结点
B->next = A->next;  // B的指针指向A的头结点
A->next = q->next;  // A的为节点指针指向B的第一个结点,B链接到A上
A = B;              // A指向B,作为合并后链表的尾指针
free(q);            // 释放B的头结点

2.双向链表

在单链表中,对于任何一个结点通过其指向后继的指针,就可以直接访问其后继结点,其时间复杂度为O(1)。显然,在单链表中访问其前驱结点,必须要从表头结点顺链查找,其时间复杂度为O(n)。显然,在单链表中访问某个元素的前驱十分不便。如果在链表的结点结构中同时包含分别指向其前驱和后继结点的两个指针域,就很容易解决单链表中访问前驱困难的问题,这种链表称作双向链表

如图(a)所示,双向链表的结点结构除了数据域之外,还包含两个指针域(用于指向前驱结点的前驱指针域和用于指向后继结点的后继指针域)。其结点结构定义如下:

typedef struct DNode{
    ElemType data;
    struct DNode *prior;    // 指向前驱结点的指针域
    struct DNode *next;     // 指向后继结点的指针域
}DListNode,*DLinkList;

如图(b) (c)所示,对于带有头结点的双向链表,其头结点prior域为空,尾结点的next域为空;显然对于一个空的双向链表,两个指针域均为空。

双向链表也可以是循环链表,双向循环链表的头结点的前去指针prior指向表尾结点,尾结点的后继指针next指向头结点;对于一个空表,头结点的两个指针均指向头结点自身。

在双向链表中,诸如计算表的长度定位元素和获取元素等操作,仅涉及一个方向的指针,这些操作与单链表的操作相同。由于需要修改两个方向上的指针,在双向链表中进行插入和删除等操作与单链表有较大的差异。

1.在双向链表中插入元素

在长度为n的双向链表的第 i(1≤i≤n+1)个位置上插入元素时,需要修改两个方向上的指针。在线性表的第i个位置插入元素e时,需要通过修改指针将含有的数据元素e的结点链接到元素ai-1和ai所在结点之间。

基本过如下:

  1. 找到第i个结点(插入位置),将指针p指向该结点,包含数据元素e的结点将链接到此结点的前驱和后继节点之间。注意,如果是在第i+1个位置上插入元素,则p指向头结点。
  2. 产生一个新结点s,并将数据元素e存放到该结点的数据域中
  3. 对指针进行操作,具体如代码所示
Status InsertList(DLinkList H, int i, ElemType e){
    if(!H)
        return Err_InvalidParam;
    DListNode *p,*s;
    int j = 1;
    p = H->next;
    while(p!=H && j<i){
        p = p->next;
        j++;
    }
    if(j>i || (p==H&&j<i))
        return Err_IllegalPos;
    s = (DListNode*)malloc(sizeof(DListNode));
    if(!s)
        return Err_Memory;
    s->data = e;
    s->prior = p->prior;    // 将新结点s的前驱指针指向p的前驱结点
    p->prior->next = s;     // 将p的前驱的后继指针指向s
    s->next = p;            // 将s的后继指针指向p
    p->prior = s;           // 将p的前驱指针指向s
    return OK;
}

注意,代码中对于指针的更新涉及到四步,前两步必须先更新插入结点s的前驱指针与p先驱结点的后继指针。因为如果先进行下两步的操作,将p的前驱指针指向s,则此时无法通过p的前驱指针得到p的前驱元素,从而无法将s链接到链表中。

2. 在双向链表中删除元素

与单链表相同,对于双向链表,删除线性表知道位置的数据元素,只需把指定位置的结点从双向链表中删除,并释放该结点空间即可。

算法基本过程如下:

Status DeleteList(DLinkList H, int i, ElemType *e){
    DListNode *p;
    if(!H)
        return Err_InvalidParam;
    DListNode *p;
    p = H->next;
    int j = 1;
    while(j<i && p!=H){
        p = p->next;
        j++;
    }
    if(p==H || j>i)
        return Err_IllegalPos;
    *e = p->data;
    p->prior->next = p->next;   // 将p的前驱结点的后继指针指向p的后继结点
    p->next->prior = p->prior;  // 将p的后继结点的前去指针指向p的前驱
    free(p);
    return OK;
}

注意,对指针的更新涉及到的两步顺序可以不同

查看评论

数据结构——循环单链表和双向链表

1.循环单链表 1.循环单链表特点: 链表中最后一个结点的指针域不再是结束标志,而是指向整个链表的第一个结点,从而使链表形成一个环。和单链表相同,循环单链表也有带头结点和不带头结点两种。带头结点的...
  • xiaofei__
  • xiaofei__
  • 2016-03-25 21:57:39
  • 2712

数据结构——线性表 (顺序表、单链表、静态链表、循环链表、双向链表)

线性表 ---顺序存储结构 ---链式存储结构(单链表、静态链表、循环链表、双向链表)...
  • daijin888888
  • daijin888888
  • 2017-04-12 16:06:27
  • 2319

数据结构 循环链表、双向链表、一元多项式

单循环链表的实现typedef int Elemtype; typedef struct node{ Elemtype data; struct node *next; }node,*linklist...
  • qq_33846054
  • qq_33846054
  • 2017-04-04 14:43:35
  • 221

数据结构与算法之六 双向链表和循环链表

在本章中,你将学习: 执行双链接列表 执行循环链接列表 应用链接列表以解决编程问题 现在,考虑一个示例,您需要以降序的方式显示这些数字。 如何解决此问题? 每一个节点链接到序列中的...
  • zhangchen124
  • zhangchen124
  • 2016-06-11 18:36:13
  • 2589

数据结构JavaScript——双向链表、双向循环链表

双向链表的JS实现
  • zhuwq585
  • zhuwq585
  • 2016-11-11 15:04:39
  • 512

数据结构学习之循环链表结构

注:本文的主要目的是为了记录自己的学习过程,也方便与大家做交流。转载请注明来自: http://blog.csdn.net/ab198604         循环链表在单向链表及双向链表的...
  • ab198604
  • ab198604
  • 2013-01-04 17:55:53
  • 5585

数据结构之线性结构--双向循环链表

一、双向循环链表特点双向循环链表的结构是在双向链表的基础上使头节点的前驱指针指向末尾的节点,而使末尾的节点的一个指针指向开始节点,形成一个循环结构。 双向循环链表在进行节点的删除的时候的操作:...
  • wangmeiqiang
  • wangmeiqiang
  • 2016-10-08 00:47:06
  • 781

数据结构学习之双向循环链表的基本操作(非递归实现)

【摘要】前一篇博客阐述了循环单链表,它虽然能够实现从任一结点出发沿着链能找到其前驱结点,但时间耗费是O(n)。如果希望从表中快速确定某一个结点的前驱,另一个解决方法就是在单链表的每个结点里再增加一个指...
  • xy010902100449
  • xy010902100449
  • 2015-06-18 21:19:23
  • 1216

单链表,双链表和循环链表之间的区别详解

链表是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每个节点里存到下一个节点的指针。由于不须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比顺序表O(logn)快...
  • zhongwen7710
  • zhongwen7710
  • 2014-09-06 17:41:37
  • 8429
    个人资料
    等级:
    访问量: 117
    积分: 71
    排名: 157万+
    文章分类
    文章存档