当前位置: 首页 > news >正文

解决单链表中的环问题

 

 给定一个单链表,只给出头指针h

  1. 如何判断是否存在环?
  2. 如何知道环的长度?
  3. 如何找出环的连接点在哪里?
  4. 带环链表的长度是多少?

 

问题1   如何判断是否有环

使用追赶的方法,设定两个指针slowfast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。

clip_image001[6]clip_image002[6]clip_image003[6]clip_image004[6]clip_image005[6]clip_image006[6]clip_image007[10]clip_image008[6]clip_image009[18] 

clip_image010[6]clip_image007[11] 

clip_image011[6]clip_image012[6]clip_image009[19]clip_image009[20]clip_image009[21]slow fast

 

问题2   如何判断环的长度

相遇点出同时出发,fast指针和slow指针再次相遇时,slow指针走过的点的个数就是环的长度。试问会不会slow在不到一圈的地方两者相遇呢?不会,因为假设slows,fast2s。二者相遇则二者距离必相差圈数的倍数,即:2s-s = k*圈距离=s。此时k=1。因此得出结论:从相遇到再次相遇,slow再走完整的一圈。

 

问题3   如何找出环的连接点

定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。

clip_image013[6]clip_image014[6]                                                                

证明:

链表形状类似数字6 
假设甩尾(在环外)长度为 a(结点个数),环内长度为 b  
则总长度(也是总结点数)为 a+b  
从头开始,0 base 编号。 
将第 i 步访问的结点用 S(i) 表示。i = 0, 1 ...
ia 时,S(i)=i  
ia 时,S(i)=a+(i-a)%b

分析追赶过程 
两个指针分别前进,假定经过 x 步后,碰撞。则有:S(x)=S(2x)
由环的周期性有:2x=tb+x 。得到 x=tb  
另,碰撞时,必须在环内,不可能在甩尾段,有 x>=a

连接点为从起点走 a 步,即 S(a) 
S(a) = S(tb+a) = S(x+a)
 

得到结论:从碰撞点 x 前进 a
步即为连接点

根据假设易知 S(a-1) 在甩尾段,S(a) 在环上,而 S(x+a) 必然在环上。所以可以发生碰撞。 又,同为前进 a 步,同为连接点,所以必然发生碰撞。

综上,从 x 点和从起点同步前进,第一个碰撞点就是连接点。

 

问题4   带环链表的长度是多少

问题2知道环的长度,问题3知道环外边的长度。两者相加即为总长度。

 

参考代码

#include <stdlib.h>
#include <stdio.h>

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

node *Create_list()   //建立链表
{
	node *p_return, *p;
	p_return = NULL;

	node *n1 = (node *)malloc(sizeof(node));
	n1->data = 1;
	n1->next = NULL;
	p = n1;
	p_return = p;

	node *n2 = (node *)malloc(sizeof(node));
	n2->data = 2;
	n2->next = NULL;
	p->next = n2;
	p = n2;

	node *n3 = (node *)malloc(sizeof(node));
	n3->data = 3;
	n3->next = NULL;
	p->next = n3;
	p = n3;

	node *n4 = (node *)malloc(sizeof(node));
	n4->data = 4;
	n4->next = NULL;
	p->next = n4;
	p = n4;

	node *n5 = (node *)malloc(sizeof(node));
	n5->data = 5;
	n5->next = NULL;
	p->next = n5;
	p = n5;

	node *n6 = (node *)malloc(sizeof(node));
	n6->data = 6;
	n6->next = NULL;
	p->next = n6;
	p = n6;

	p->next = n3;

	return p_return;
}

node *find_in_node(node *p1, node *p2)   //找到入环的结点
{
	while(p1 != p2)
	{
		p1 = p1->next;
		p2 = p2->next;
	}
	return p1;
}
int get_out_len(node *p1, node *p2)   //计算出环外边的长度
{
	int num = 0;
	while(p1 != p2)
	{
		p1 = p1->next;
		p2 = p2->next;
		num++;
	}
	return num;
}

node *check_loop(node *p)  //检查是否有环
{
	node *p_slow, *p_fast;
	p_slow = p;
	p_fast = p;
	int tag = 0;
	while(p_slow && p_fast->next)
	{
		p_slow = p_slow->next;
		p_fast = p_fast->next->next;
		if(p_slow == p_fast)
		{
			tag = 1;
			break;
		}
	}
	if(tag == 1)
	{
		printf("Have loop\n");
		return p_slow;
	}
	else
	{
		printf("Not have loop\n");
		return NULL;
	}
}
int get_len_loop(node *var_loop)   //得出环的长度
{
	node *p = var_loop->next;
	int num = 1;
	while(p != var_loop)
	{
		p = p->next;
		num++;
	}
	return num;
}

int main()
{
	node *p = Create_list();
	node *coin_loop = check_loop(p);
	if(coin_loop)
	{
		int len_loop = get_len_loop(coin_loop);
		printf("Length of Loop is:%d\n", len_loop);
		node *in_node = find_in_node(p, coin_loop);
		int len_out = get_out_len(p, coin_loop);
		printf("Length of out Loop is %d\n", len_out);
		printf("Length of all is %d\n", len_out + len_loop);
	}
}

 

相关文章:

  • Shadow Mapping With PCF
  • 批量查看mysql多从状态和修改多从主库指向
  • 删除异常的MS SQL进程
  • Android的五种数据存储方式
  • 路由器VRRP配置
  • Eclipse user library位置
  • ORACLE 10g 64位下载地址
  • 设置中的一些默认值
  • 浅析Ad Exchange广告交易模式
  • Chrome浏览器调用摄像头拍照
  • Struts2之自定义类型转换器
  • linux系统下调度数据库类型资源库中的kettle job
  • Fragment的学习
  • 标书
  • Bootstrap3.0学习第十八轮(JavaScript插件——下拉菜单)
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • Android框架之Volley
  • maya建模与骨骼动画快速实现人工鱼
  • node-glob通配符
  • Python3爬取英雄联盟英雄皮肤大图
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • Vue小说阅读器(仿追书神器)
  • 排序算法之--选择排序
  • 普通函数和构造函数的区别
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 字符串匹配基础上
  • Spring第一个helloWorld
  • 阿里云重庆大学大数据训练营落地分享
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • !!Dom4j 学习笔记
  • ###项目技术发展史
  • #define用法
  • (4)STL算法之比较
  • (js)循环条件满足时终止循环
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (分布式缓存)Redis持久化
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (转)ORM
  • (转)VC++中ondraw在什么时候调用的
  • (转)大型网站架构演变和知识体系
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • .Mobi域名介绍
  • .Net 8.0 新的变化
  • .NET DataGridView数据绑定说明
  • /proc/stat文件详解(翻译)
  • [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略
  • [AutoSar]状态管理(五)Dcm与BswM、EcuM的复位实现
  • [BUUCTF]-PWN:[极客大挑战 2019]Not Bad解析
  • [CareerCup][Google Interview] 实现一个具有get_min的Queue
  • [Labtools 27-1429] XML parser encountered a problem in file
  • [LeetCode]剑指 Offer 40. 最小的k个数
  • [MAUI]集成高德地图组件至.NET MAUI Blazor项目