链表成环问题

链表成环问题

问题概述:
判断一个单链表是否有环
问题本质:
追及问题

package algorithm;

import java.util.Iterator;

public class LinkList<T> implements Iterable<T>{
    //记录链表头节点
    private Node head;
    //记录链表长度
    private int len;
    //创建一个内部类,存储链表结点
    private class Node{
        private T element;
        private Node next;

        public Node(T element, Node next) {
            this.element = element;
            this.next = next;
        }
    }
    public LinkList(){
        head = new Node(null,null);
        len = 0;
    }
    //使用尾插法插入元素
    public void insert(T element){
        Node n = head;
        while(n.next!=null){
            n = n.next;
        }
        //创建新结点
        Node Newnode = new Node(element, null);
        n.next = Newnode;
        len++;
    }

    @Override
    public Iterator<T> iterator() {
        return new LIterator();
    }

    private class LIterator implements Iterator<T>{
        private Node n;
        public LIterator(){
            this.n = head;
        }
        @Override
        public boolean hasNext() {
            return n.next!=null;
        }

        @Override
        public T next() {
            n = n.next;
            return n.element;
        }
    }
    public static void main(String[] args) {
        LinkList<String> list = new LinkList<>();
        list.insert("1");
        list.insert("2");
        list.insert("3");
        list.insert("4");
        list.insert("5");
        //构建一个简易环
        list.Cycle();
        System.out.println();
        //普通方法
        System.out.println(list.searchlow());
        //巧妙方法
        System.out.println(list.search());
    }
    //从尾巴构建一个环(仅使用本例)
    public void Cycle(){
        Node n = head;
        Node test = head;
        while (n.next!=null){
            n = n.next;
        }
        n.next = test.next.next;
    }
    //寻找方法-low
    //思想:遇到一个结点,就将其之前的所有节点与该结点比较,如果两结点相同,则证明有环,否则证明无环
    //使用两个标记位确定两个结点始终是一前一后,即n始终是next的遍历指针而不会和next相同,导致无环误判
    //时间复杂度o(n2),空间复杂度o(n)
    public Boolean searchlow() {
        //获取头节点
        Node n = head;
        //获取头节点的next节点
        Node next = head.next;
        int nlen = 0;
        int nextlen = 1;
        while (next.next!=null){
            while (nlen < nextlen){
                if(n == next){
                    return true;
                }
                n = n.next;
                nlen++;
            }
            next = next.next;
            nextlen++;
            nlen = 0;
            n = head;
        }
        return false;
    }
    //让一个指针每次移动两个结点,另一个指针移动一个结点。
    //思想:如果有环,就像运动员跑步,跑的快的总会追上跑的慢的
    //时间复杂度o(n),空间复杂度o(1)
    public Boolean search(){
        Node n = head;
        Node next = head;
        while (next!=null && next.next != null){
            n = n.next;
            next = next.next.next;
            if(n == next){
                return true;
            }
        }
        return false;
    }
}

问题扩展:

  • 相遇点位置
  • 环的大小
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值