链表是一长串的数据,可是当一长串的数据相交或者相互环绕的时候就变成了相交的链表和有环的链表,此文主要说明一下有环链表和相交链表的一些基本操作。
​链表的代码​​

有环链表

创建实验条件

public void createLoop()
{
Entry cur = head;
while(cur.next!=null)
{
cur = cur.next;
}
cur.next = head.next.next;
}

18-咸鱼学Java-特殊的链表(环和交)_链表

判断是否有环

public boolean isLoop()
{
Entry fast = head;
Entry slow = head;
while(fast!=null&&fast.next!=null)
{
fast = fast.next.next;
slow = slow.next;
if(fast==slow)
{
return true;
}
}
return false;
}

此方法为设置两个引用,其中一个引用一次走两步,一个一次走一步,如果两个引用在某一位置相遇,则说明有环。

获得环的入口点

public int getEntryLoop()
{
if(!isLoop())
return -1;

Entry fast = head;
Entry slow = head;
while(fast!=null&&fast.next!=null)
{
fast = fast.next.next;
slow = slow.next;
if(fast==slow)
{
break;
}
}
slow = head;
while(fast!=slow)
{
fast = fast.next;
slow = slow.next;
}

return fast.data;
}

18-咸鱼学Java-特殊的链表(环和交)_链表_02


所以在相遇的时候,将某一个引用放到链表的头,然后两个指针都开始一步一步的走,当他们再次相遇的时候就是环的入口点了。

求环的长度

public int getLoopLength()
{ if(!isLoop())
return -1;
boolean tag = false;
Entry fast = head;
Entry slow = head;
int count=0;
while(fast!=null&&fast.next!=null)
{
fast = fast.next.next;
slow = slow.next;
if(fast==slow&&tag==true)
break;
if(fast==slow&&tag ==false)
tag=true;
if(tag=true)
count++;
}
return count;
}

此方法的原理为,在其第一次相遇的时候设置一个标志位,当此标志位一直为true的时候,计数器进行计数,当两个引用再次相遇的时候进行跳出,此时count就位环的长度。

环测试

public static void main(String[] args) {
Link2 i = new Link2();
i.insertHead(11);
i.insertHead(10);
i.insertHead(9);
i.insertHead(8);
i.insertHead(7);
i.show();//显示链表
System.out.println(i.isLoop());//判断是否有环
i.createLoop();//创建环
System.out.println(i.isLoop());//判断是否有环
System.out.println(i.getEntryLoop());//获得环的入口
System.err.println(i.getLoopLength());//获得环的长度
}

结果
​​​[7 8 9 10 11 ]
false
true
8
3

相交叉的链表

实验环境

public static void CreateCut(Link2 t1,Link2 t2)
{
Entry head1 = t1.getHead();
Entry head2 = t2.getHead();
head1.next.next = head2.next.next;

}

18-咸鱼学Java-特殊的链表(环和交)_链表_03

判断是否相交

public static boolean isCut(Link2 t1,Link2 t2)
{
Link2.Entry head1 = t1.getHead(); //获得两个链表的头结点
Link2.Entry head2 = t2.getHead();
int len1 = t1.getLength(); //获取到两个链表长度
int len2 = t2.getLength();
int mylen = len1-len2; //找到两个链表的差值
if(mylen<0) //如果mylen小于0代表t2比t1长
{
head1 = t2.getHead(); //此时换一下位置即可,保证head1为最长元素的头结点
head2 = t1.getHead();
}
for (int i = 0; i <mylen; i++) { //对长的先进行遍历
head1 = head1.next;
}
while(head1!=null&&head2!=null&&head1!=head2) //进行循环,直到两个链表找到交点,或者遍历完成
{
head1 = head1.next;
head2 = head2.next;
}
if(head1 == head2 && head1!=null && head2!=null)//如果找到交点 返回true 负责为false
{
return true;
}
else
{
return false;
}
}

此操作最重要的是在他们长度不相等的时候,想办法让他们同步。然后才能找到相交的点。

获得相交点

public static int isCutPoint(Link2 t1,Link2 t2)
{
Link2.Entry head1 = t1.getHead();
Link2.Entry head2 = t2.getHead();
int len1 = t1.getLength();
int len2 = t2.getLength();
int mylen = len1-len2;
if(mylen<0)
{
head1 = t2.getHead();
head2 = t1.getHead();
}
for (int i = 0; i <mylen; i++) {
head1 = head1.next;
}
while(head1!=null&&head2!=null&&head1!=head2)
{
head1 = head1.next;
head2 = head2.next;
}
if(head1 == head2 && head1!=null && head2!=null)
{
return head1.data;
}
else
{
return -1;
}
}

和判断相交相同,只是返回的时候返回所处位置的data即可。

相交测试

public static void main(String[] args) {
Link2 i = new Link2();
Link2 j = new Link2();
i.insertHead(11);
i.insertHead(10);
i.insertHead(9);
i.insertHead(8);
i.insertHead(7);
j.insertHead(6);
j.insertHead(5);
j.insertHead(3);
j.insertHead(2);
j.insertHead(1);
i.show();
j.show();
System.out.println(isCut(i, j));
CreateCut(i, j);
System.out.println(isCut(i, j));
i.show();
j.show();
System.out.println(isCutPoint(i, j));
}

结果
​​​[7 8 9 10 11 ]
[1 2 3 5 6 ]
false
true
[7 2 3 5 6 ]
[1 2 3 5 6 ]
2​