数据结构与算法(java):线性表(链表-快慢指针)

线性表(链表-快慢指针)

快慢指针指的是定义两个指针,这两个指针的移动速度一快一慢,以此来制造出自己想要的差值,通过这个差值找到链表上对应的结点。一般情况下,快指针的移动步长为慢指针的两倍

1、中间值问题

a~g是链表的结点,想要通过快慢指针找到中间值,图示如下,slow指针每次移动一个步长,fast每次移动两倍slow指针的步长距离。
在这里插入图片描述

代码演示

public class FastAndSlowTest01 {
    //结点类,这里是静态内部类
    private static class Node<T>{
        T item; //存储数据
        Node next;

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

    public static void main(String[] args) {
        //创建结点
        Node first = new Node("a",null);
        Node second = new Node("b",null);
        Node third = new Node("c",null);
        Node fourth = new Node("d",null);
        Node fifth = new Node("e",null);
        Node sixth = new Node("f",null);
        Node seven = new Node("g",null);

//        Node eight = new Node("h",null);
//        Node nine = new Node("i",null);

        //指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = sixth;
        sixth.next = seven;

//        seven.next = eight;
//        eight.next = nine;

        //查找中间值
        Object mid = getMid(first);
        System.out.println(mid);
    }

    public static Object getMid(Node first){
        //定义两个指针
        Node fast = first;
        Node slow = first;

        //使用两个指针遍历链表,当快指针指向的结点没有下一个结点,则结束,结束之后,慢指针所指即为中间值
        while(fast != null && fast.next != null){
            //改变两个指针的值:
            //这里的规律是:结合图来看哈,可以发现,fast的下一个位置是fast当前位置往前移了两次,同理slow,往前移了1次
            fast = fast.next.next;
            slow = slow.next;
        }

        return slow.item;
    }
    
}

中间值结果为
d

无论是偶数个结点还是奇数个结点都是可以找出中间值的
当结点个数为8个的时候,中间值结果为e,结点个数为9个的时候中间值结果也为e

2、单链表是否有环问题

在这里插入图片描述

思路

通过使用快慢指针是否会相遇,来判断单链表是否有环。
关于为什么会相遇,会牵扯到数学知识,待我刷LeetCode遇到相关题后再详细写下来,哈哈哈(懒)

代码
public class FastAndSlowTest02 {
    //结点类,这里是静态内部类,通过静态内部类可以创建结点
    private static class Node<T>{
        T item; //存储数据
        Node next;

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

    public static void main(String[] args) {
        //创建结点
        Node first = new Node("a",null);
        Node second = new Node("b",null);
        Node third = new Node("c",null);
        Node fourth = new Node("d",null);
        Node fifth = new Node("e",null);
        Node sixth = new Node("f",null);
        Node seven = new Node("g",null);


        //指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = sixth;
        sixth.next = seven;
        //产生环
        seven.next = third;

        //判断是否有环
        boolean circle = isCircle(first);
        System.out.println(circle);
    }

    private static boolean isCircle(Node first) {
        //定义两个指针
        Node fast = first;
        Node 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;
    }
}

3、有环链表的入口问题

就是找到成环的那个结点

图示

在这里插入图片描述

思路

先判断是否有环,判断了有环后,设定一个新指针指向链表的起点,且步长和慢指针一致为1,通过判断慢指针与新指针相遇的地方就是环的入口(这也牵扯到数学知识。。。懒,就不详细讲了,可以试试找规律)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码
public class FastAndSlowTest03 {
    //结点类,这里是静态内部类,通过静态内部类可以创建结点
    private static class Node<T>{
        T item; //存储数据
        Node next;

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

    public static void main(String[] args) {
        //创建结点
        Node first = new Node("a",null);
        Node second = new Node("b",null);
        Node third = new Node("c",null);
        Node fourth = new Node("d",null);
        Node fifth = new Node("e",null);
        Node sixth = new Node("f",null);
        Node seven = new Node("g",null);

        //指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = sixth;
        sixth.next = seven;
        //产生环
        seven.next = third;

        Node entrance = getEntrance(first);
        System.out.println(entrance.item);
    }

    private static Node getEntrance(Node first) {
        //创建快慢指针
        Node fast = first;
        Node slow = first;
        Node 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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值