主要内容:
检测链表是否有环、在不知道头指针的情况下怎么删除非末尾节点、判断两个链表是否相交、找到相交链表的交点。
重点是看懂解题思路,思路明白了,代码就非常好写了。
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;
}
}