线性表--顺序表--循环链表(五)

时间:2022-07-28
本文章向大家介绍线性表--顺序表--循环链表(五),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一.介绍

单循环链表,简称循环链表,是另一种形式的链式存贮结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。和单链表唯一的区别就是,尾结点指向头结点,因此循环链表中没有NULL指针。而涉及遍历操作时,其终止条件就不再是像非循环链表那样判别p或p->next是否为空,而是判别它们是否等于某一指定指针,如头指针或尾指针等,在单链表中,从一已知结点出发,只能访问到该结点及其后续结点,无法找到该结点之前的其它结点。而在单循环链表中,从任一结点出发都可访问到表中所有结点,这一优点使某些运算在单循环链表上易于实现。

二.图示

单链表是这样的:

循环链表是这样的:

二.代码实现

1.定义链表

上面已经说过,循环链表和单链表唯一的不同就在于尾结点指向头结点,所以链表的定义和单链表一样。

typedef struct list
{
 int data;
 struct list * next;
}list;

2.初始化头结点

这里初始化头结点也和单链表一样,没有什么可说的。

list * InitListHead()
{
 list *Phead = (list *)malloc(sizeof(list));//创建头结点
 Phead->data = 0;         //该变量可存放该链表长度
 Phead->next = Phead;
 return Phead;                              //创建后返回该头指针
}

3.循环链表结点初始化

void CreateCLinkList(list ** CL,int n)
{
 //利用尾插法建立循环链表CL
 list* rear, *s;
 rear = (*CL); //rear指针动态指向链表的当前表尾,其初值指向头节点
 for (int i = 1; i <= n; i++)
 {
  s = (list *)malloc(sizeof(list));
  s->data = i;
  rear->next = s;
  rear = s;
 }
rear->next = (*CL);//让最后一个节点的next链域指向头节点。
}

至于循环链表的增删查改,都同单链表一样,我们就不在多赘述,只是在遍历这块有一定小猫腻。

4.循环链表的遍历(重点)

如果是这样:

void printList(list * Phead)
{
	list P=Phead;
	while(P->next!=Phead)
	{
	printf("%d",P->data );
	P=P->next;
	}
}

上述代码你会发现,该链表的最后一个结点不会被输出,当p->next=Phead的时候,循环被停止。 这时的是不是又抖机灵想着把while(P->next!=Phead)改为while(P!=Phead)???你想啥呢,这连循环都不会去进去。都 是头结点惹的祸,第一种差一个结点,第二章根本就不去,解决方法是,我们可以进循环之前,把头节点数据先输出,这样显然有点麻烦,代码看着有点笨拙,这时我们就应该想到被我们丢弃的do—while循环。

void printList(list * Phead)
{
list P=Phead;
do{
printf("%d",P->data	);
P=P->next;
}while(P!=Phead);
}

看,do—while天然的无条件执行一次,完美的为我们解决了这个难题。

5.如何判断是否为循环链表(重点)

首先来说说这种循环链表:

这种就比较简单了,只需要判断就没有指向NULL的指针,再看看头结点是不是重复出现,如果重复出现那一定就是循环链表了。 代码如下:

void JudgeList(list * Phead)
{
	list * P=Phead;
     while(P!=NULL)
	{
	    P=P->next;
	    if(P==Phead)
	    return true;
	}
	return false;
}

到这里,你是不是觉得就完了,那就错了,现实偏偏不是这样,偏偏就有下面这种循环链表的存在(你说气不气):

如果再使用上面的代码,函数传入一个头结点,显然没有用了,所以,快慢指针登上历史舞台。 快慢指针是利用不同的步长,然后让快慢指针相遇,则可以证明链表是一个环,也就是循环指针,就好像校园的田径场,跑的快的,最终会追上跑的慢的,所以对于上面这种循环链表,我们可以采用这种方法来判断是否为循环链表。 代码实现:

void JudgeList(list * Phead)
{
 	list * fast;
 	list * slow;
 	fast=slow=Phead;//两个指针在同一起跑线
	while(1)
    {
      	if(fast==slow||fast->next==slow) //快的跑一圈又追上慢的,或者慢指针跑到前面
      	return true;
      	else
      	{
      	slow=slow->next;
      	fast=fast->next->next; //快指针比慢指针多走一步
      	}
    }
}

若有错误,欢迎批评指正,欢迎讨论。 每文一句:超越自己,向自己挑战,向弱项挑战,向懒惰挑战,向陋习挑战。