学科分类
目录
数据结构

循环链表的实现

在单链表中,从一已知结点出发,只能访问到该结点及其后继结点,无法找到该结点之前的其它结点。而在单循环链表中,从任一结点出发都可访问到表中所有结点,这一优点使某些运算在单循环链表上更易于实现。

循环链表在实现上大多操作都与单链表相同,如创建、查找等,这些部分在单链表与双向链表中都有详细的讲解及代码实现,此处就不再重复,接下来主要讲解其插入与删除元素时与单链表的异同。

1、插入元素

在循环链表中插入元素,如果是插入到第一个位置,即头结点之后的位置,则稍稍有一些麻烦,需要处理三个指针,头结点中的指针、尾结点中的指针和插入元素的结点指针。其过程如图17所示。

图1 在循环链表的头结点插入元素

在头结点之后插入元素时,要将新结点中的指针指向此位置上原来的结点,头结点中的指针指向新结点,尾结点指针指向新结点。比单链表多处理了一个尾结点指针。

在尾部插入元素时也有所不同,p->next不再指向NULL,而是指向head->next。

除此两处以外,在其他位置插入元素,则与单链表处理相同。其代码实现如下:

int ClistInsert(pHead ph, int pos, int val) //在链表的pos位置插入元素val
{

    if (ph == NULL || pos < 0 || pos > ph->length)
    {
        printf("插入元素时,参数传入有误!\n");
    }

    pNode pval = NULL;
    //参数传入无误,则为新元素val分配结点
    pval = (pNode)malloc(sizeof(struct Node));
    pval->data = val;                     //将值val保存到此结点中

     //接下来要判断在哪个位置插入元素,先判断链表是否为空
     if (IsEmpty(ph)) //如果链表为空
     {
         ph->next = pval;                  //直接将结点插入到头结点后
         pval->next =pval;                 //将第一个结点指向它自己
     }
    else //循环链表不为空,则分为在头部插入(即头结点后)和普通位置插入
    {
        pNode pRear = ph->next; 
         if (pos == 0) //在第一个位置(头结点后)插入
         {
             //0号位置插入,需要先找到尾结点
            while (pRear->next != ph->next) //循环结束的条件
            {
                pRear = pRear->next;         //pCur指针向后移动
            }
            //while循环结束后,pRear指向尾结点
            //然后插入元素
            pval->next = ph->next;
            ph->next = pval;
            pRear->next = pval;             //这三个步骤顺序不能更改
         }
        else //如果不是0号位置插入,则和单链表无区别
        {
            pNode pCur = ph->next;
            for (int i = 1; i < pos; i++) //就要遍历链表找到要插入的位置
             {
                 pCur = pCur->next;             //pCur指针向后移
             }
             //循环结束后,此时pCur指向的是要插入的位置
             pval->next = pCur->next;         //指针断开再连接的过程
            pCur->next = pval;
        }
    }
    ph->length++;
    return 1;
}

在插入新元素时,先判断链表是否为空,如果为空,则将元素插入到头结点后,然后将其指针指向自身;如果不为空,根据插入的位置作出相应操作。

2、删除元素

在删除元素时,也要考虑删除的是否为头结点后的第一个元素,如果是,则需要将头结点与尾结点的指针指向待删除结点的后继结点,如图2所示。

图2 删除头结点后的第一个元素

如果是删除其他位置的元素,则和单链表处理方式相同。其代码实现如下:

pNode ClistDelete(pHead ph, int val) //删除循环链表ph中的元素val
{
    if (ph == NULL || ph->length == 0)
     {
         printf("参数传入有误!");
     }
    //先找到链表的尾结点
    pNode pRear = ph->next;
    while (pRear->next != ph->next)
    {
        pRear = pRear->next;
    }

    //查找此元素
    pNode pval = ClistFind(ph, val);     //关于ClistFind()函数,与单链表相同
    if (pval == NULL)
        return NULL;

    if (pval == ph->next)                 //如果是第0号位置上的结点
    {
        ph->next = pval->next;
        pRear->next = pval->next;
    }
    else                                  //如果是其他位置的结点
    {
        //就要找到pval的前驱结点
        pNode pRe = ph->next;
        for (int i = 0; i < ph->length; i++)
        {
            if (pRe->next == pval)
            {
                pRe->next = pval->next;
                return pval;
            }
            pRe = pRe->next;
        }
    }
    return NULL;
}

在循环链表中,除了插入和删除操作与单链表稍有不同之外,其他操作与单链表都是一样的,读者可以参照单链表的操作自己动手实现循环链表,并完成测试。

点击此处
隐藏目录