C语言丨线性表(四):循环链表

线性表是由数据类型相同n\left ( n\geq 0 \right )个数据元素组成的有限序列,通常记为:

\left ( a_{1},a_{2},\cdots ,a_{i-1},a_{i},a_{i+1},\cdots ,a_{n} \right )

其中n为表长,n=0时称为空表;下标i表示数据元素的位序

线性表的特点是组成它的数据元素之间是一种线性关系,即数据元素“一个接在另一个的后面排列,每一个数据元素的前面和后面都至多有一个其他数据元素”。

本文在介绍线性表的基本概念的基础上,重点介绍单循环链表和双循环链表及相应的算法


定义

循环链表是一种首尾相接的链表。在单链表中,将终端结点的指针域NULL改为指向头结点,就得到了单链表形式的循环链表——单循环链表。把双链表最后一个结点的后继指针指向第一个结点,第一个结点的前驱指针指向最后一个结点,就组成了双循环链表

单循环链表

在用头指针表示的单循环链表中,找开始结点a_{1}的时间为O\left ( 1 \right ),而要找终端结点a_{n},则需要从头指针开始遍历整个链表,其时间为O\left ( n \right )。如果改用尾指针R来表示单循环链表,则开始结点a_{1}和终端结点a_{n}的存储地址分别为R->next->next和R,所以查找开始结点a_{1}和终端结点a_{n}的时间均为O\left ( 1 \right )。因此实际应用中多采用尾指针表示单循环链表。

由于单循环链表和单链表的区别仅在于单循环链表用尾指针存储链表,单链表用头指针存储链表,以及终端结点的指针域不同,因此单循环链表的建立、插入、删除、检索等算法只需在单链表的算法基础上稍作修改即可。单链表的详细介绍可参见如下链接,下面直接给出代码:

C语言丨线性表(二):线性链表(单链表)

建立

CLinkList *CreateCLinkList()
{
    CLinkList *R, *p, *s;
    DataType x;/*设DataType为数据元素的类型*/
    R = (CLinkList *)malloc(sizeof(CLinkList));/*先用R代表头结点,避免浪费内存*/
    R->next = NULL;
    scanf(&x);/*读入数据元素的值*/
    p = R;
    while (x!=flag)
    {
        s = (CLinkList *)malloc(sizeof(CLinkList));
        s->data = x;
        s->next = NULL;
        p->next = s;
        p = p->next;
        scanf(&x);
    }
    p->next = R->next;/*将终端结点的指针域NULL改为指向头结点*/
    R = p;/*让尾指针指向终端结点
    return R;
}

插入

int InsertCLinkList(CLinkList *R, int i, DataType x)
/*在有线性链表R中第i个位置前插入元素x*/
{
    CLinkList *p;
    CLinkList *s;
    int j = 0;
    p = R;
    while (p->next!=R && j<i-1)
    {
        p = p->next;
        j++;
    }/*循环直到p指向第i-1个元素*/
    if (p->next == R)
        return -1;/*i大于表长加1*/
    s = (CLinkList *)malloc(sizeof(CLinkList));
    s->data = x;
    s->next = p->next;/*插入数据元素x*/
    p->next = s;
    return 1;
}

删除

int DeleteCLinkList(CLinkList *R, int i)
/*在单循环链表中删除第i个元素*/
{
    CLinkList *p;
    CLinkList *q;
    int j = 0;
    p = R;
    while (p->next==R && j<i-1)
    {
        p = p->next;
        j++;
    }/*循环直到p指向第i-1个元素*/
    if (p->next == R)
        return -1;/*删除节点不合法*/
    q = p->next;
    p->next = q->next;/*删除第i个数据元素*/
    free(q);/*释放第i个数据元素所占内存*/
    return 1;
}

检索

LinkList *SearchCLinkList(CLinkList *R, DataType x)
/*在单循环链表R中查找值为x的结点,找到后返回其指针,否则返回空*/
{
    CLinkList *p = R->next;/*p指向线性链表的第一个数据元素*/
    while (p!=R && p->data!=x)
        p = p->next;
    if (p==R && p->data!=x)
        return NULL;
    return p;
}

双循环链表

把双链表最后一个结点的后继指针指向第一个结点,第一个结点的前驱指针指向最后一个结点,并用cdlist指针存储双链表,就组成了双循环链表。因此,双循环链表的建立、插入、删除和检索算法也与双链表大同小异。双链表的详细介绍可参见如下链接,下面直接给出代码:

C语言丨线性表(三):双链表

建立

CDLinkList *CreateCDLinkList()
{
    CDLinkList *cdlist, *p, *q;
    cdlist = (CDLinkList *)malloc(sizeof(CDLinkList));
    p = (CDLinkList *)malloc(sizeof(CDLinkList));
    if (cdlist==NULL || p==NULL)
    {
        free(cdlist);
        free(p);
        return NULL;
    }
    DataType x;
    scanf(&x);
    p->data = x;
    cdlist->llink = p;
    p->llink = NULL;
    p->rlink = NULL;
    scanf(&x);
    while (x != flag)/*flag为建立结束的标志*/
    {
        q = (CDLinkList *)malloc(sizeof(CDLinkList));
        if (q == NULL)
        {
            CDLinkList *pr;
            p = cdlist->llink;
            while (p != NULL)
            {
                pr = p->rlink;
                free(p);
                p = pr;
            }
            free(cdlist);
            return NULL;
        }
        q->data = x;
        q->llink = p;
        q->rlink = NULL;
        p->rlink = q;
        scanf(&x);
    }
    cdlist->rlink = q;
    cdlist->llink->llink = q;
    q->rlink = cdlist->llink;
    return cdlist;
}

插入

int Insert(CDLinkList *cdlist, CDLinkList *p, DataType x)
{
    CDLinkList *q = (CDLinkList *)malloc(sizeof(CDLinkList));
    if (q == NULL)
        return 0;
    q->data = x;/*数据域赋值*/
    if (p->rlink == cdlist->llink)/*在表尾插入元素*/
    {
        cdlist->rlink = q;
        q->llink = p;
        q->rlink = p->rlink;
        p->rlink = q;
        return 1;
    }
    if (p == cdlist)/*若p为cdlist,认为在表头插入元素*/
    {
        q->llink = cdlist->llink->llink;
        q->rlink = cdlist->llink;
        cdlist->llink->llink = q;
        cdlist->llink = q;
        return 1;
    }
    q->llink = p;
    q->rlink = p->rlink;
    p->rlink->llink = q;
    p->rlink = q;
    return 1;
}

删除

int DeleteCDLinkList(CDLinkList *cdlist, CDLinkList *p)
/*在双循环链表删除结点p,成功返回1,否则返回0*/
{
    CDLinkList *q = p->rlink, *s = p->llink;/*q指向p的后继,s指向p的前继*/
    if (s!=cdlist->rlink && q==cdlist->llink)/*删除的是最后一个结点*/
    {
        cdlist->rlink = p->llink;
        p->llink->rlink = p->rlink;
        free(p);
        return 1;
    }
    if (s==cdlist->rlink && q!=cdlist->llink)/*删除的是第一个结点*/
    {
        cdlist->llink = p->rlink;
        p->rlink->llink = p->llink;
        free(p);
        return 1;
    }
    if (s==cdlist->rlink & q==cdlist->llink)/*双循环链表只有一个结点*/
    {
        cdlist->rlink = cdlist->llink = NULL;
        free(p);
        return 1;
    }
    if (s!=cdlist->rlink && q!=cdlist->llink)
    {
        p->llink->rlink = p->rlink;
        p->rlink->llink = p->llink;
        free(p);
        return 1;
    }
    return 0;
}

检索

CDLinkList *SearchCDLinkList(CDLinkList *cdlist, DataType x)
{
    CDLinkList *p = cdlist->llink, *q = cdlist->rlink;
    while (p->data!=x && q->data!=x)
    {
        p = p->rlink;
        q = q->llink;
        if (p==q || p->llink==q)
            break;
    }
    if (p->data == x)
        return p;
    else if (q->data == x)
        return q;
    else
        return NULL;
}

参考文献:

文益民 张瑞霞 李健 编著,数据结构与算法(第2版),清华大学出版社,P33-34.

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值