• 13.单链表中,取出环的起始点


    我们平时碰到的有环链表是下面的这种:(图1)

    上图中环的起始点1。 
    但有可能也是下面的这种:(图2)

    此时,上图中环的起始点是2。 

    方法1: 
    这里我们需要利用到上面第8小节的取出环的长度的方法getCycleLength,用这个方法来获取环的长度length。拿到环的长度length之后,需要用到两个指针变量first和second,先让second指针走length步;然后让first指针和second指针同时各走一步,当两个指针相遇时,相遇时的结点就是环的起始点。 
    注:为了找到环的起始点,我们需要先获取环的长度,而为了获取环的长度,我们需要先判断是否有环。所以这里面其实是用到了三个方法。 代码实现: 
    方法1的核心代码:

        // 方法:获取环的起始点。参数length表示环的长度
        public Node getCycleStart(Node head, int cycleLength) {
            if (head == null) {
                return null;
            }
            Node first = head;
            Node second = head;
            // 先让second指针走length步 
            for (int i = 0; i < cycleLength; i++) {
                second = second.next;
            }
            // 然后让first指针和second指针同时各走一步
            while (first != null && second != null) {
                first = first.next;
                second = second.next;
                if (first == second) {
                    return first;
                }
            }
            return null;
        }

    完整版代码:(含测试部分)

    public class LinkCycleStart {
        public Node head;
        public Node current;
    
        // 向链表中添加数据
        public void add(int data) {
            // 判断链表为空的时候
            if (head == null) {// 如果头结点为空,说明这个链表还没有创建,那就把新的结点赋给头节点
                head = new Node(data);
                current = head;
            } else {
                current.next = new Node(data);// 创建新的结点,放在当前节点的后面(把新的节点和链表进行关联)
                current = current.next;// 把链表的当前索引向后移动一位,此步操作完成之后,current结点指向新添加的那个结点
            }
        }
    
        // 方法重载:向链表中添加结点
        public void add(Node node) {
            if (node == null) {
                return;
            }
            if (head == null) {
                head = node;
                current = head;
            } else {
                current.next = node;
                current = current.next;
            }
        }
    
        // 方法:遍历链表(打印输出链表。方法的参数表示从节点node开始进行遍历
        public void print(Node node) {
            if (node == null) {
                return;
            }
            current = node;
            while (current != null) {
                System.out.println(current.data);
                current = current.next;
            }
        }
    
        class Node {
            // 注:此处的两个成员变量权限不能为private,因为private的权限是仅对本类访问
            int data;// 数据域
            Node next;// 指针域
    
            public Node(int data) {
                this.data = data;
            }
    
            public int getData() {
                return data;
            }
    
            public void setData(int data) {
                this.data = data;
            }
    
            public Node getNext() {
                return next;
            }
    
            public void setNext(Node next) {
                this.next = next;
            }
        }
    
        // 方法:检测单链表是否有环
        public Node hasCycle(Node head) {
            if (head == null) {
                return null;
            }
            Node first = head;
            Node second = head;
            while (second != null) {
                first = first.next;
                second = second.next.next;
                if (first == second) {// 一旦两个指针相遇,说明链表是有环的
                    return first;
                }
            }
            return null;
    
        }
    
        // 方法:有环链表中,获取环的长度。参数node代表的是相遇的那个结点
        public int getCycleLength(Node node) {
            if (head == null) {
                return 0;
            }
            current = node;
            int length = 0;
            while (current != null) {
                current = current.next;
                length++;
                if (current == node) {
                    return length;// 当current结点走到原点的时候
                }
            }
            return length;
        }
    
        // 方法:获取环的起始点。参数length表示环的长度
        public Node getCycleStart(Node head, int cycleLength) {
            if (head == null) {
                return null;
            }
            Node first = head;
            Node second = head;
            // 先让second指针走length步 
            for (int i = 0; i < cycleLength; i++) {
                second = second.next;
            }
            // 然后让first指针和second指针同时各走一步
            while (first != null && second != null) {
                first = first.next;
                second = second.next;
                if (first == second) {
                    return first;
                }
            }
            return null;
        }
    
        public static void main(String[] args) {
            LinkCycleStart list1 = new LinkCycleStart();
            Node second = null; // 把第二个结点记下来
            // 向链表中添加数据
            for (int i = 0; i < 4; i++) {
                list1.add(i);
                if (i == 2) {
                    second = list1.current;// 把第二个结点记下来
                }
            }
    
            list1.add(second);// 将尾结点指向链表的第二个结点,于是单链表就有环了
            Node current1 = list1.hasCycle(list1.head);// 获取相遇的那个结点
            int length = list1.getCycleLength(current1);
            System.out.println("环的起始点是" + list1.getCycleStart(list1.head, length).data);
        }
    
    }

    测试结果:

    环的起始点是2

  • 相关阅读:
    MQCONN failed (Reason = 2277)
    MQ打开队列模式 input和input_exclusive
    mq 消息最大长度 最大是100M
    Easyui Datagrid的Rownumber行号显示问题
    ajax请求时session已过期处理方案
    seafile Windows Memcached
    seafile 接口频度控制
    你的旧船票能否搭上这艘巨轮?——解读近5年大数据产业发展规划
    第一章 输入/输出知识
    It looks like you don't have a C compiler and make utility installed. 错误
  • 原文地址:https://www.cnblogs.com/guweiwei/p/6866194.html
Copyright © 2020-2023  润新知