算法:判断链表是否有环并且求入环口

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("下标越界了");
        }
    }

}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值