`
madbluesky
  • 浏览: 84647 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多

有环链表如何高效的判断是否有环,以及在何处产生环?

采用2个指针不同步数(步数小的每次1步,步数大的每次2步),步数大的如果能够与步数小的相遇则必然存在环。

 

相遇后的情况如图,假设相遇后步数大的回绕环遍历了n遍,步数小的肯定一遍也没遍历完,假设第一段距离为a,第2段距离为c,第3段距离为b

则有(a+c)*2 = a+n(b+c)+c,转换后得 a = n(b+c) - c,也就是说,从出发点出发,移动a的距离,刚好等于相遇点出发移动n个整圈减c的距离,这个点刚好就是环产生的点,由此可以设置2个指针,分别从根节点与相遇点出发,第一次相遇的地方则是环产生的点。

完成证明后,代码较为简单,如下

 

package com.xhb.algorithms;

public class MyLinkedList {
	private LinkListNode<Integer> root = new LinkListNode<Integer>(null, null);
	private int length;
	private int point;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		MyLinkedList list = new MyLinkedList(10045, 232);
		System.out.println(list.isHasRound());
		System.out.println("the point cut obj is " + list.getCutPoint());
	}

	/**
	 * 初始化一个环链表
	 */
	private MyLinkedList(int length, int point) {
		this.length = length;
		this.point = point;
		LinkListNode<Integer> current = this.root;
		for (int i = 1; i <= this.length - 1; i++) {
			current = current.next(new LinkListNode<Integer>(new Integer(i),
					null));
		}
		if (this.point < 0) {
			current.next(null);
		} else {
			LinkListNode<Integer> pointObj = this.root;
			for (int i = 0; i < point; i++) {
				pointObj = pointObj.next();
			}
			current.next(pointObj);
		}
	}

	public Integer getCutPoint() {
		LinkListNode<Integer> seekPoint = this.getSeekPoint();
		System.out.println(seekPoint.data());
		LinkListNode<Integer> a = this.root;
		while (true) {
			a = a.next();
			seekPoint = seekPoint.next();
			if (a == seekPoint) {
				return a.data();
			}
			// System.out.println(a.data() +"," + seekPoint.data());
		}
	}

	private LinkListNode<Integer> getSeekPoint() {
		LinkListNode<Integer> a = this.root;
		LinkListNode<Integer> b = this.root;
		a = a.next();
		b = b.next().next();
		while (true) {
			a = a.next();
			b = b.next();
			if (b == null) {
				return null;
			}
			if (a == b && b != null) {
				return b;
			}
			b = b.next();
			if (b == null) {
				return null;
			}
			if (a == b && b != null) {
				return b;
			}
		}
	}

	public boolean isHasRound() {
		return this.getSeekPoint() != null;
	}
}

class LinkListNode<T> {
	private LinkListNode<T> next = null;
	private T data;

	public LinkListNode(T data, LinkListNode<T> next) {
		this.data = data;
		this.next = next;
	}

	public LinkListNode<T> next() {
		return next;
	}

	public LinkListNode<T> next(LinkListNode<T> next) {
		this.next = next;
		return next;
	}

	public T data() {
		return this.data;
	}

	@Override
	public String toString() {
		return data.toString();
	}
}
  • 大小: 15.9 KB
分享到:
评论

相关推荐

    用C++实现的循环链表

    这些代码可能包含上述操作的示例,有助于学习和掌握循环链表的实现细节。 总之,循环链表是C++编程中一个重要的数据结构,理解和熟练掌握其原理和操作,对于提升编程能力、解决实际问题具有重要意义。通过实践和...

    链表面试题目总结 全

    在面试中,还可能被问到两个无环链表是否相交的问题。一个常见的方法是分别遍历两个链表并计算它们的长度,然后将较长链表先移动(长度差)的步数,之后两个指针同步移动,当两个指针指向同一个节点时,即找到了交点...

    C 代码 执行迭代函数计算,并寻求确定 周期的最近元素和周期长度, 使用弗洛伊德方法.rar

    6. **测试和调试**:`cycle_floyd_test.c`可能包含了各种测试用例,对`cycle_floyd.c`中的函数进行调用,以确保在不同情况下的正确性,包括无环链表、有环链表以及环的位置和大小变化的情况。 这个实现不仅展示了...

    c++习题

    2. **判断单向链表中是否带有环链表** - 检测链表环可以通过使用两个指针,一个快指针每次移动两步,慢指针每次移动一步。如果链表有环,快指针最终会追上慢指针;若无环,则快指针会到达链表尾部。 3. **寻找倒数...

    java代码-寻找链表的头节点,每个节点,有 id 和 nextId 两个属性,nextId 表示指向节点 Id。现在请实现一个办法寻找该链表的头节点。

    在Java编程中,链表是一种常见的数据结构,用于存储一系列有序的元素。在这个问题中,我们面临的是...最后,测试代码部分应该包含各种情况,如无环链表、有环链表、单个节点链表以及空链表,以验证我们的实现是否正确。

    数据结构习题集1

    - (b) 该关系表示了一个有环链表,b指向c,c不指向d,而是b指向d,形成了一个环,依然是线性结构。 - (c) 该关系表示了一个有向图,d有两个入边和一个出边,不属于简单的线性结构。 2. **时间复杂度**: - 时间...

    leetcode:LeetCode Top 100 Liked Questions | Top Interview Questions | LeetCode 用户最喜欢的100题 | 面试最容易被问到的题

    * 另一种方法,把问题转换成有环链表,找环的起始节点。O(n) O(1) lc142 * 二分查找,每次看一边数字的个数, O(nlog(n)) O(1) * Tips:剑指offer原题 */ RoadMap :soccer_ball: :basketball: :hamburger: ...

    leetcode338-books:图书

    另一种方法,把问题转换成有环链表,找环的起始节点。O(n) O(1) lc142 * 二分查找,每次看一边数字的个数, O(nlog(n)) O(1) * Tips:剑指offer原题 */ RoadMap :soccer_ball: :basketball: :hamburger: LeetCode ...

Global site tag (gtag.js) - Google Analytics