数据结构—链表(三)

4 篇文章 0 订阅

主要内容:

检测链表是否有环、在不知道头指针的情况下怎么删除非末尾节点、判断两个链表是否相交、找到相交链表的交点。

重点是看懂解题思路,思路明白了,代码就非常好写了。

package com.sf.linkedlist;

/**
 * Created by laxe on 2016/12/1.
 */
public class LinkedListDemo2 {
    static Node head=null;
    public static void main(String args[]) {
        head = new Node(1);
        Node next1 = new Node(2);
        Node next2 = new Node(3);
        Node next3 = new Node(4);
        Node next4 = new Node(5);
        Node next5 = new Node(6);
        Node next6 = new Node(7);

        head.next = next1;
        next1.next = next2;
        next2.next = next3;
        next3.next = next4;
        next4.next = next5;
        next5.next=next6;
        //next6.next=next3;
        showList(head);
        //System.out.println(isLoop());
        //Node port=findLoopPort();
        //System.out.print(port.val);


        deleteNode(next1);
        showList(head);
    }


//检测一个链表是否有环
    /**
     * 思路:设置两个指针,慢指针每次走一步,快指针每次走两步。
     *       二者同时走,每次走完都比较一下是否相等,相等就代表这个链表是带环的单向链表。
     *
     *
     * */
    public static boolean isLoop(){
        Node fast=head;
        Node slow=head;

        if(fast==null)
            return false;

        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                return true;
            }
        }
        return !(fast==null || fast.next==null);
    }
//找到带环单链表的入口点
    /**
     * 思路:在上个算法的基础上,
     *       找到快慢指针的相遇点为node,链表起始点为head,
     *       head和node每次同时前进一步,二者相遇点即为环的入口点。
     * 其实理解起来有点困难,可以尝试自己画图理解一下
     * */
    public static Node findLoopPort(){
        Node fast=head;
        Node slow=head;

        if(fast==null)
            return null;

        Node meet=null;//快慢指针相遇点
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow) {
                meet = slow;
                break;
            }
        }
        if(fast==null || fast.next==null)
            return null;

        Node start=head;
        while(start!=meet){
            start=start.next;
            meet=meet.next;
        }
        return meet;
    }

//在不知道头指针的情况下删除指定节点
    /**
     * 若待删除的节点为链表尾节点,那么无法删除,因为删除后无法使前驱结点的next指向null;
     * 若待删除的节点不是链表尾节点,那么可以通过交换这个节点与其后继节点的值,然后删除后继结点。
     *
     * */
    public static void deleteNode(Node node){
        if(node==null || node.next==null)
            return;
        int temp=node.val;
        node.val=node.next.val;
        node.next.val=temp;
        node.next=node.next.next;
    }

//如何判断两个链表是否相交
    /**
     * 如果两个链表相交,那么他们一定有相同的尾节点。
     * 思路:分别遍历两个链表,记录他们的尾节点,如果他们的尾节点相同,那么两个链表相交,否则不相交。
     *
     * */
    public static boolean isIntersect(Node h1,Node h2){
        if(h1==null || h2==null)
            return false;
        Node t1=h1;
        Node t2=h2;
        while(t1!=null){
            t1=t1.next;
        }

        while(t2!=null){
            t2=t2.next;
        }

       return t1==t2;
    }

    /**
     * 如果两个链表相交,如何找到他们交响的第一个节点呢
     * 思路:首先分别计算两个链表的长度len1,len2(假设了len1>len2),
     *       接着先对链表head1遍历(len1-len2)个节点到节点p,此时节点p与head2到他们相交的距离相等,此时同时遍历两个链表
     *       直到遇到相同的节点为止,这个节点就是他们相交的节点。
     *       需要注意,在找相交点之前,需要先判断两个链表是否相交,相交再去找相交点。
     * */
    public static Node getFirstMeetNode(Node h1,Node h2){
        if(h1==null || h2==null)
            return null;
        Node t1=h1;
        Node t2=h2;
        int len1=0;
        int len2=0;
        while(t1!=null){
            t1=t1.next;
            len1++;
        }

        while(t2!=null){
            t2=t2.next;
            len2++;
        }
        if(t1!=t2)
            return null;

        Node r1=h1;
        Node r2=h2;
        if(len1>len2){
            int d=len1-len2;
            while(d!=0){//找到解题思路中说到的“p”
                r1=r1.next;
                d--;
            }
        }

        if(len1<len2){
            int d=len2-len1;
            while(d!=0){//找到解题思路中说到的“p”
                r2=r2.next;
                d--;
            }
        }
        while(r1!=r2){
            r1=r1.next;
            r2=r2.next;
        }
        return r1;


    }

    /**
     * 打印链表
     * */
    public static void showList(Node head){
        if(head==null)
            return;
        Node tmp=head;
        while(tmp!=null)
        {
            if(tmp.next!=null) {
                System.out.print(tmp.val+"->");
                tmp = tmp.next;
            }else{
                System.out.print(tmp.val);
                tmp = tmp.next;
            }
        }
        System.out.println();
    }

    /**
     * 获取链表的长度
     * */
    public static int length(){
        int length=0;
        Node tmp=head;
        while(tmp!=null){
            length++;
            tmp=tmp.next;
        }
        return length;
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值