思路:判断链表中是否有环,可以使用快慢指针(fast low)遍历链表实现,fast每次走两步,low每次走一步,如果他们在链表中相遇,则说明有环,否则fast提前遇上NULL,说明链表无欢。
关键代码:
//判断环
int link_list_judge(node *head)
{
//定义fast low指针,分别从head开始遍历
node *fast,*low;
fast=low=head;
//fast每次循环两次,low每次前进一位
while(fast->next&&low->next) //关键步骤:循环退出条件
{
//low指针出发
low=low->next;
//fast指针出发(并判断)
if((fast=fast->next->next)==NULL)
{
printf("链表无环!\n");
return 0;
}
else if(fast==low)
{
printf("链表有环!\n");
return 1; //返回整型数值进行判断
}
}
return 0;
}
循环退出条件:循环开始,需判断fast->next是否是有效节点,利用和low指针的与逻辑操作,可实现,当然这样也可实现判断链表可能为空的情况,fast指针指向第二个节点(不包含head)时,需判断fast当前存入的地址。
完整代码:
/*分析:链表中如果存在环,那么链表
尾节点一定不指向NULL,并且会产生循环
解题思路:对要判断的链表,从头结点开始,
遍历链表,直到遇到第二个相同的节点
具体解题思路:利用快慢指针(双指针)
设计两个指针fast和low,fast和low从
同一位置同时出发(head),fast每次
走两步,low每次走一步,如果fast遇到
NULL,说明该链表没环;
*/
#include <stdio.h>
#include <stdlib.h>
// 节点设计
typedef struct node
{
int data;
struct node *next;
} node;
// 函数声明
// 初始化节点
node *link_list_init(void);
// 头插
void link_list_add(node *head, int add_data);
// 尾插
void link_list_add_tail(node *head, int add_data);
// 遍历链表
void link_list_show(node *head);
// 生成环
void link_list_ring(node *head);
// 尾节点寻找函数
node *link_list_tail(node *head);
// 遍历带环链表
void link_list_show_ring(node *pos, node *head);
//判断环
int link_list_judge(node *head);
// 主函数(单向不循环链表)
int main(int argc, char const *argv[])
{
// 创建空链表
node *head = link_list_init();
// 循环输入数据
int cmd;
while (1)
{
printf("Pls enter the num!:");
scanf("%d", &cmd);
while (getchar() != '\n')
;
if (cmd > 0)
{
link_list_add_tail(head, cmd); // 添加数据
link_list_show(head);
}
else if (cmd == 0)
link_list_ring(head); // 生成环
else
{ // else
link_list_judge(head); // 判断环
//printf("head_:%d\n",head->next->data);
}
}
return 0;
}
// 初始化节点
node *link_list_init(void)
{
// 申请堆空间
node *new = malloc(sizeof(node));
// 判断能否正常申请堆空间
if (new == NULL)
{
printf("malloc failed\n");
return NULL;
}
// 新节点数据域清空和指针域处理
new->data = 0;
new->next = NULL;
// 返回新节点
return new;
}
// 头插
void link_list_add(node *head, int add_data)
{
// 申请新节点空间
node *new = link_list_init();
// 新节点数据域
new->data = add_data;
// 新节点指针域
new->next = head->next;
head->next = new;
}
// 尾插
void link_list_add_tail(node *head, int add_data)
{
// 定义指针寻找尾节点
node *pos = head;
while (pos->next != NULL)
{
pos = pos->next;
}
// 参数传递给头函数进行头插入链
link_list_add(pos, add_data);
}
// 遍历链表
void link_list_show(node *head)
{
// 定义指针遍历链表
node *pos = head->next;
for (pos; pos != NULL; pos = pos->next)
printf("%d ", pos->data);
printf("\n");
}
// 遍历带环链表
void link_list_show_ring(node *pos, node *head)
{
printf("环中链表:");
node *u = pos;
do
{
printf("%d ", u->data);
u=u->next;
}while(u!=pos);
printf("\n");
}
// 生成环
void link_list_ring(node *head)
{
if(head->next==NULL)
{
printf("空链表,头结点既是环本身!\n");
return ;
}
int j=link_list_judge(head);
if(j==1)
{
printf("停止生成链环!\n");
return ;
}
printf("环节点之前的整链表:");
link_list_show(head);
// 自定义指向节点
int dd;
printf("请输入要从哪个数据开始成环:");
scanf("%d", &dd);
while (getchar() != '\n')
;
// 定义指针寻找目的节点
node *pos = head->next;
while (dd != pos->data)
{
pos = pos->next;
if (pos == NULL)
{
printf("匹配失败!\n");
return;
}
}
// 匹配成功,tail指向该结点,形成环
link_list_tail(head)->next = pos;
printf("已形成环!\n");
link_list_show_ring(pos, head);
}
// 尾节点寻找函数
node *link_list_tail(node *head)
{
node *pos = head;
while (pos->next != NULL)
pos = pos->next;
return pos;
}
//判断环
int link_list_judge(node *head)
{
//定义fast low指针,分别从head开始遍历
node *fast,*low;
fast=low=head;
//fast每次循环两次,low每次前进一位
while(fast->next&&low->next) //关键代码:循环结束条件
{
low=low->next;
//双指针开始出发
//由于fast要移动两位,为防止fast溢出链表,fast每次前进都需要检查当前fast结点
if((fast=fast->next->next)==NULL)
{
printf("链表无环!\n");
return 0;
}
else if(fast==low)
{
printf("链表有环!\n");
return 1; //返回整型数值进行判断
}
}
return 0;
}