取出链表的环的起始节点(Java)

思路:

先判断链表是否有环,有环的话取得环的长度,使用两个指针,一个先走环的长度步,然后再一起走,相交点即为环的起始节点

分析:
     * 1、两个指针遍历链表,一个一次走一步,一个一次两步,能相交到一个点,则证明有环,相交点必在环上
     * 2、根据相交点,遍历一圈,再次到达原节点,即取得环的长度
     * 3、取得环的长度len后,一个指针先走len步,一个在一起走,第一次到达相同的节点即为环的起始节点
     

代码:

package com.datastructure.link;

/*
 * 数据结构-单链表之获取链表环的第一个节点
 */
public class LinkedListGetCircleNode
{

    /*
     * 元素的基本定义
     */
    static class Node{
        /*
         * value
         */
        private int value;
        
        /*
         * 链表的下一个元素
         */
        private Node next;
        
        public Node (int value) {
            this.value = value;
        }
        
        
        // 链表有环时 不能使用这种打印方式
        @Override
        public String toString() {
            if (this.next == null) {
                return String.valueOf(this.value);
            }
            return this.value + "->" + this.next.toString();
        }
        
    }
    
    /*
     * 获取单链表中环的起始节点
     * 
     * 如:
     * node0->node1->node5->node6->ode1  需要取出node1
     * node0->node1->node5->node6->node0  需要取出node0
     * 
     * 
     * 思路:先判断链表是否有环,有环的话取得环的长度,使用两个指针,一个先走环的长度步,然后再一起走,相交点即为环的起始节点
     * 
     * 分析:
     * 1、两个指针遍历链表,一个一次走一步,一个一次两步,能相交到一个点,则证明有环,相交点必在环上
     * 2、根据相交点,遍历一圈,再次到达原节点,即取得环的长度
     * 3、取得环的长度len后,一个指针先走len步,一个在一起走,第一次到达相同的节点即为环的起始节点
     * 
     */
    
    /**
     * 获取链表的一个环内节点,无环则返回null
     */
    public static Node getCircleNodeInLink(Node node) {
    	if(node == null) {
    		return null;
    	}
    	
    	Node first = node;
    	Node second = node;
    	
    	// 两个指针,一个一次走一步,一个一次走两步,会相遇,说明有环
    	while (second != null && second.next != null && first != null) {
    		first = first.next;
    		second = second.next.next;
    		
    		// 先赋值first second,在判断,避免循环刚开始即返回
    		if (first == second) {
    			return first;
    		}
    	}
    	
    	return null;
    }
    
    /*
     * 获取环的长度
     */
    public static int getCircleLen(Node node) {
    	if (node == null) {
    		throw new RuntimeException("link is empty");
    	}
    	
    	// 获取一个环内节点
		Node oneCircleNode = getCircleNodeInLink(node);
		
		// 以环内节点为起始,再次遍历到该节点,说明到达了一周
		if (oneCircleNode != null) {
			Node curNode = oneCircleNode.next;
			int count = 1;
			while (curNode != null) {
				if (curNode == oneCircleNode) {
					return count;
				}
				count++;
				curNode = curNode.next;
			}
		}
    	
    	return 0; 
    }
    
    // 获取第一个环内节点
    public static Node getFirstNodeInCircle(Node node) {
    	if (node == null) {
    		return null;
    	}
    	
    	// 暂存环的头结点
    	Node fast = node;
    	Node low = node;
    	
    	// 获取环长度
    	int circleLen = getCircleLen(node);
    	if (circleLen <= 0) {
    		return null;
    	}
    	
    	for (int i = 0; i < circleLen; i++) {
    		fast = fast.next;
    	}
    	
    	while (fast != null && low != null) {
    		if (fast == low) {
    			return fast;
    		}
    		fast = fast.next;
    		low = low.next;
    	}
    	
    	return null;
    }
    
    
    public static void main(String args[]) {
    	
    	Node noCircle = createTestLinkedList(5, null);
        
        // 链表是否有环
        System.out.println("link has circle? " + getCircleNodeInLink(noCircle));
        // 环的长度
        System.out.println("link circle len? " + getCircleLen(noCircle));
        // 环的起始节点
        System.out.println("link first circle node? " + getFirstNodeInCircle(noCircle));
        
        
        Node node1 = new Node(11);
        Node node2 = new Node(12);
        node1.next = node2;
        Node node3 = new Node(13);
        node2.next = node3;
        Node node4 = new Node(14);
        node3.next = node4;
        node4.next = node1;
        
    	Node circle = createTestLinkedList(5, node1);
        
        // 链表是否有环
        System.out.println("link has circle? " + getCircleNodeInLink(circle).value);
        // 环的长度
        System.out.println("link circle len? " + getCircleLen(circle));
        // 环的起始节点
        System.out.println("link first circle node value? " + getFirstNodeInCircle(circle).value);
        
    }
    
    private static Node createTestLinkedList(int n, Node addNode) {
        Node head = new Node(0);
        Node curNode = head;
        for (int i = 1; i < n; i++) {
            curNode.next = new Node(i);
            curNode = curNode.next;
        }
        curNode.next = addNode;
        return head;
    }

}

参考:

链表题目Java实现:https://www.cnblogs.com/qianguyihao/p/4782595.html

猜你喜欢

转载自blog.csdn.net/zangdaiyang1991/article/details/88596182