1、首先判断链表是否有环,采用快慢指针来定位,快指针走一步,慢指针走两步,如果有环那么快慢指针一定会在某处相遇,如果没有环那么快指针一定会先到达next为null
2、假设有环,假定链表头到入口的距离为 L, 入口到相遇点的距离为X ,环状链表的周长为 R,并且快慢指针相遇的时候(不考虑在入口相遇)快指针一定先于满指针跑过n圈链表 那么则有如下结论:快指针走过的距离为:f = l + x + n*R 慢指针走过的距离为:l = l + x 并且: f = 2*l 则 l + x + n*R = 2*l + 2*x 推导得出:l = n*r -x 无论快指针走了n圈或者是1圈我们能得到 物理距离:l = r-x 也就是说在环形链表相遇的节点再往入口走的距离和链表头节点到入口距离相同 因此在快慢指针相遇的节点再定义一个指针meet 头节点同时定义一个指针tmp当指针meet和tmp相遇时,这时他们所在的节点就是相遇点
public static MyCycleLinkedList.Node detectCycle(MyCycleLinkedList.Node head) {
if (head == null || head.next == null) {//如果头节点为空或者头节点下一个节点为空说明该链表不成环
return null;
}
MyCycleLinkedList.Node fast = head;
MyCycleLinkedList.Node low = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
low = low.next;
if (fast == low) {//如果快慢指针相遇说明 链表有环
System.out.println("链表有环,相遇点:" + fast.data);
MyCycleLinkedList.Node meet = fast;
MyCycleLinkedList.Node tmp = head;
while (true) {
if (meet == tmp) {
return meet;
}
meet = meet.next;
tmp = tmp.next;
}
}
}
return null;
}
下面是自定义的环形链表实现
package com.lupeng.list;
/**
* @program: suanfa
* @description: 单向链表
* @author: Lu
* @create: 2021-09-23 19:03
**/
public class MyCycleLinkedList<E> implements MyList {
private int size;
private Node first;
private Node entrance;
/**
* 未找到动态数组元素下标
*/
private static final int NOT_FOUND = -1;
public Node getFirst() {
return first;
}
public class Node {
public Node next;
public E data;
public Node() {
}
public Node(E data) {
this.data = data;
}
public Node(Node next, E data) {
this.next = next;
this.data = data;
}
}
public MyCycleLinkedList() {
first = new Node();
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
private Node node(int index) {
Node node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
@Override
public boolean contains(Object o) {
Node carl = first;
if (size == 0) {
return false;
}
if (o == null) {
for (int i = 0; i < size; i++) {
carl = carl.next;
if (carl.data == null) {
return true;
}
}
} else {
for (int i = 0; i < size; i++) {
carl = carl.next;
if (carl.data.equals(o)) {
return true;
}
}
}
return false;
}
@Override
public Object get(int index) {
checkIndexBounds(index, size);
Node carl = first;
for (int i = 0; i < index; i++) {
carl = carl.next;
}
return carl.data;
}
@Override
public void set(int index, Object o) {
checkIndexBounds(index, size);
node(index).data = (E) o;
}
@Override
public void add(Object o) {
add(size, o);
}
@Override
public void add(int index, Object o) {
checkLastIndexBounds(index, size);
if (size == 0) {
first.next = new Node((E) o);
} else {
Node prev = node(index);
prev.next = new Node(prev.next, (E) o);
if (size > 5) {
if (index == size && entrance != null) {
prev.next.next = entrance;
}
} else {
if (index == 5) {
//当添加到第六个元素的时候将该元素标记未环形链表的入口
entrance = prev.next;
}
}
}
size++;
}
@Override
public Object remove(int index) {
Node removed = null;
checkIndexBounds(index, size);
Node node = first;
if (index == 0) {
first = first.next;
} else {
Node prev = node(index);
node = prev.next;
prev.next = node.next;
}
size--;
return removed.data;
}
@Override
public boolean remove(Object o) {
int index = indexOf(o);
if (index == NOT_FOUND) {
return false;
} else {
remove(index);
return true;
}
}
@Override
public int indexOf(Object o) {
if (o == null) {
Node carl = first;
for (int i = 0; i <= size; i++) {
carl = carl.next;
if (carl.data == null) {
return i;
}
}
} else {
Node carl = first;
for (int i = 0; i <= size; i++) {
carl = carl.next;
if (carl.data.equals(o)) {
return i;
}
}
}
return NOT_FOUND;
}
@Override
public void clear() {
first.next = null;
size = 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Size:").append(size).append(",[");
Node carl = first;
int i = 0;
while (true) {
if (carl.next != null) {
carl = carl.next;
sb.append(carl.data);
if (carl.next != null) {
sb.append("_").append(carl.next.data).append(",");
}
i++;
} else {
break;
}
if (i == size) {
break;
}
}
sb.append("]");
return sb.toString();
}
}
package com.lupeng.list;
public interface MyList<E> {
/**
* 获取动态数组中元素的数量
*
* @return
*/
int size();
/**
* 判断数组是否为空
*
* @return
*/
boolean isEmpty();
/**
* 判断动态数组是否包含某个元素
*
* @param e
* @return
*/
boolean contains(E e);
/**
* 返回 index对应位置的元素
*
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
*
* @param index
* @param e
* @return
*/
void set(int index, E e);
/**
* 往数组最后添加元素
*
* @param e
*/
void add(E e);
/**
* 往数组index位置添加元素
*
* @param index
* @param e
*/
void add(int index, E e);
/**
* 删除index位置元素
*
* @param index
*/
E remove(int index);
/**
* 移除某个元素
*
* @param e
* @return
*/
boolean remove(E e);
/**
* 查看某个元素位置
*
* @param e
* @return
*/
int indexOf(E e);
/**
* 清除动态数组中的所有元素
*/
void clear();
/**
* description 判断索引是否越界
*
* @param index
* @param size
* @return
* @author LU.P
* @date 2021/9/18 15:28
*/
default void checkIndexBounds(int index, int size) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("下标越界了");
}
}
default void checkLastIndexBounds(int index, int size) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("下标越界了");
}
}
}