判断链表是否有环、环的长度、环的入口点

分析:(当前链表中的数据无重复)
  • 1.直接遍历方式,将当前的节点(cur_node)从头节点开始比较直到当前节点的前一个节点(pre_node),若没有相同的值,则说明链表没有环。时间复杂度为O(N^2),过程有点像插入排序。
  • 2.借助额外空间,建立一个HashSet,将已经遍历过的节点的值放入集合中,若遍历至当前节点时,集合中已经存在该节点的值,则说明链表有环。时间复杂度为O(N),额外的空间为O(N)。
  • 3.使用双指针,一个慢指针,一个快指针。通俗一点,若是环形跑道,快指针一定会与慢指针相遇。时间复杂度为O(N),空间复杂度为O(1)。
package test.com;

public class LinkedList_Cycle {
    /**
     * @Author Kyrie
     * @Description :判断链表是否有环
     **/
    public static Node head;  //指向头结点的指针
    public static Node last;  //指向尾节点
    public static int size;   //链表的元素个数

    //初始化链表
    public static void init_list(){
        //起始链表为空链表
        size = 0;
        head  = last; // 头指针与尾指针重合
        last = null;  //尾指针指向的是null

    }
    //插入节点,若链表为空则插入至头节点
    public static void insert(int data, int index){
        if(index < 0 || index > size){
            throw new IndexOutOfBoundsException("索引越界异常");
        }
        Node new_node = new Node(data);
        if(size == 0){
            head = new_node;
            last = new_node;
        }else if(size == index){
            last.next = new_node;
            last = new_node;  //调整尾指针
        }else{
            //getNode方法
            new_node.next = getNode(index);
            getNode(index - 1).next = new_node;
        }
        size++;
    }
    //获取指定索引位置的节点
    public static Node getNode(int index){
        Node tmp = head;
        for (int i = 0; i < index ; i++) {
            tmp = tmp.next;
        }
        return tmp;
    }
    //建立单链表
    public static void createLinkedlist(){
        for (int i = 0; i < 8; i++) {
            insert(12 + i, i);
        }
    }

    //建立含有环的链表
    public static void createLinkedlist_V2(){
        for (int i = 0; i < 8; i++) {
            insert(12 + i, i);
        }
        getNode(7).next = getNode(4); //构造环
    }

    //遍历链表
    public static void printList(){
        Node temp = head;
        while (temp != null){
            System.out.print(temp.data + " ");
            temp = temp.next;
        }
    }
    //判断是否链表有环
    public static boolean isCycle(Node node){  //传入头节点
        Node p1 = node;  //慢指针
        Node p2 = node;  //快指针
        while (p2 != null && p2.next != null){
            p1 = p1.next;
            p2 = p2.next.next;
            if(p1 == p2){
                return true;
            }
        }
        return false;
    }
    //计算链表环的长度
    public static int lenCycle(Node node){  //传入头节点
        Node p1 = node;
        Node p2 = node;
        int count = 0;  //相遇的次数
        int len = 0;
        while (p2 != null && p2.next != null){
            p1 = p1.next;
            p2 = p2.next.next;
            len++;
            if(p1 == p2){
                count++;
                
                if(count == 1){
                    len = 0;
                    continue;
                }

                if(count == 2){
                    return len;
                }
            }
        }
        return -1;
    }
    //返回入环的节点的值
    public static int valueCycle(Node node){
        Node p1 = node;
        Node p2 = node;
        while (p2 != null && p2.next != null){
            //start = start.next;
            p1 = p1.next;
            p2 = p2.next.next;
            int count = 0;
            if(p1 == p2) {
                p2 = node;
                break;
            }
        }
        while(p2 != p1){
            p2 = p2.next;
            p1 = p1.next;
        }
        return p1.data;
    }
    
    public static void main(String[] args) {
        createLinkedlist_V2();
        System.out.println(isCycle(head));   // true;
        System.out.println(lenCycle(head));  // 4
        System.out.println(valueCycle(head)); // 16
    }

}
//定义节点类
class Node{
    public int data;
    public Node next;
    //空参构造
    public Node(){

    }
    //有参构造
    public Node(int data){
        this.data = data;
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值