单向链表问题——快慢指针

使用快慢指针解决单向链表中有三个经典问题:

1.中间值问题

设置两个指针fast和slow,其中fast每次移动2个节点,slow每次移动1个节点,当fast走到最后一个节点时,slow刚好指向了链表的中间。
在这里插入图片描述在这里插入图片描述
代码实现:

package cn.yqd.itcast.test;

public class FastSlowTest {

    public static void main(String[] args) throws Exception {
        //创建结点
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);

        //完成结点之间的指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;

        //查找中间值
        Node mid = getMid(first);
        System.out.println("中间值为:"+mid.item);
    }

    /**
     * @param first 链表的首结点
     * @return 链表的中间结点的值
     */
    public static Node getMid(Node<String> first) {
        //定义两个指针
        Node fast = first;
        Node slow = first;
        //使用两个指针遍历链表,当快指针指向的结点没有下一个结点了,就可以结束了,结束之后,慢指针指向的结点就是中间值
        while(fast!=null &&fast.next!=null){
            //变化fast的值和slow的值
            fast = fast.next.next;
            slow=slow.next;
        }

        return slow;
    }

    //结点类
    private static class Node<T> {
        //存储数据
        T item;
        //下一个结点
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}

2.是否有环问题

由于fast和slow两个指针的速度不同,如果链表存在环,则一定会出现fast指针领先一圈追上slow指针的情况,所以当fast==slow时,证明链表有环。
在这里插入图片描述
在这里插入图片描述
代码实现:

package cn.yqd.itcast.test;

public class CircleListCheckTest {
    public static void main(String[] args) throws Exception {
        //创建结点
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);

        //完成结点之间的指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;
//        //产生环
//        seven.next = third;

        //判断链表是否有环
        boolean circle = isCircle(first);
        System.out.println("first链表中是否有环:"+circle);
    }

    /**
     * 判断链表中是否有环
     * @param first 链表首结点
     * @return ture为有环,false为无环
     */
    public static boolean isCircle(Node<String> first) {
        //定义快慢指针
        Node<String> fast = first;
        Node<String> slow = first;

        //遍历链表,如果快慢指针指向了同一个结点,那么证明有环
        while(fast!=null && fast.next!=null){
            //变换fast和slow
            fast = fast.next.next;
            slow = slow.next;

            if (fast.equals(slow)){
                return true;
            }
        }

        return false;
    }

    //结点类
    private static class Node<T> {
        //存储数据
        T item;
        //下一个结点
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}

3.有环链表入口问题

当用快慢指针证明了链表中环的存在时,我们此时再创建一个新指针指向链表的起点,并且步长与慢指针一致,此时,当新指针与慢指针相遇时,相遇的节点就是环的入口。(据说这一结论是一个数论问题,我暂时也没搞明白)
在这里插入图片描述
在这里插入图片描述
代码实现:

package cn.yqd.itcast.test;

public class CircleListInTest {
    public static void main(String[] args) throws Exception {
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);
        Node<String> eight = new Node<String>("hh", null);

        //完成结点之间的指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;
        seven.next = eight;
        //产生环
        eight.next = third;

        //查找环的入口结点
        Node<String> entrance = getEntrance(first);
        System.out.println("first链表中环的入口结点元素为:"+entrance.item);
    }

    /**
     * 查找有环链表中环的入口结点
     * @param first 链表首结点
     * @return 环的入口结点
     */
    public static Node getEntrance(Node<String> first) {
        //定义快慢指针
        Node<String> fast = first;
        Node<String> slow = first;
        Node<String> temp = null;

        //遍历链表,先找到环(快慢指针相遇),准备一个临时指针,指向链表的首结点,继续遍历,直到慢指针和临时指针相遇,那么相遇时所指向的结点就是环的入口
        while(fast!=null && fast.next!=null){
            //变换快慢指针
            fast = fast.next.next;
            slow = slow.next;

            //判断快慢指针是否相遇
            if (fast.equals(slow)){
                temp = first;
                continue;
            }

            //让临时结点变换
            if (temp!=null){
                temp = temp.next;
                //判断临时指针是否和慢指针相遇
                if (temp.equals(slow)){
                    break;
                }
            }
        }

        return temp;
    }
    //结点类
    private static class Node<T> {
        //存储数据
        T item;
        //下一个结点
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值