一:判断是否有环
思路:使用快慢引用法解决 是否有环
假设链表是一个有环链表,且由f指向c构成环。那么 使用两个指针 A 和 B,让两指针同时向后遍历 而且B的遍历速度是A的两倍,呢么如果是有环的话,B终究会追上A。因此我们可以 以AB是否相遇作为判断是否有环的必要条件。
下面是图例:
最终BA在e相遇,于是可以得出 此链表有环。
代码:
public Entry<E> isLoop(){
Entry<E> fast = first , slow = first;//定义两个指针,分别是快和慢
//遍历一遍链表,如果最后是null的话就代表没有环
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
//如果俩相遇了,代表有环
if (fast == slow){
return fast;
}
}
return null;
}
二:求出成环的位置
思路:s=vt(路程=速度*时间)用方程思想列等式解
因为路程知道,速度知道(二倍关系),时间也知道(相等),所以可以列等式求关系。再用代码体现出关系,就可以解决这道题了。
如图:假设链表是Link fast是快的那个指针,Slow是慢的呢个指针,蓝色是fast走过的路程,绿色是slow走过的路程
K是环的入口,P是快慢指针相遇的地方
a,b,c 分别代表三段长度。
所以图就可以变成:
然后,让指针从 相遇点p 和起始点 同时遍历,这样由于 c = a 所以p和first在k相遇,而k就是入口点。
代码:
public Entry<E> getIntersectEntry(){
Entry<E> meet = isLoop();
if(meet == null){
return null;
}
Entry<E> p = meet;
Entry<E> q = first;
while (p!=q){
p = p.next;
q = q.next;
}
return p;
}
无头结点单链表结构:
/*
* 不带头节点 的单链表
* */
public class NhLinkedList<E> {
private class Entry<T> {
private T value;
private Entry<T> next;
public Entry(){
}
public Entry(T value,Entry<T> next){
this.value = value;
this.next = next;
}
}
private Entry<E> first;
private Entry<E> last;
private int size;
public NhLinkedList(){
first = null;
last = null;
}
// 增
//头插
public void addHead(E value){
first = new Entry<>(value,first);
size++;
if(last == null){
last = first;
}
}
//尾插
public void addEnd(E value){
Entry<E> entry = new Entry<>(value,null);
size++;
last.next = entry;
last = entry;
if(first == null){
first = last;
}
}
//第i个地方插入
public void addIni(int i,E value){
try {
Entry<E> entryI = first;
for (int p = 1; p < i - 1; p++) {
entryI = entryI.next;
}
Entry<E> p = new Entry<>(value, entryI.next);
size++;
entryI.next = p;
}catch (NullPointerException e){
System.out.println(e);
}
}
// 删
//初始化单链表
public void init(){
first = null;
last = null;
}
//删除第i个 ,,判断第i个是否可删除
public void delI(int i){
if(i>size || i<1){
System.out.println("越界");
return;
}
//头删
if(i == 1){
first = first.next;
size--;
}
//尾删
else if(i == size){
last = null;
size--;
}
//中间删除
else {
Entry<E> entryI = first;
for (int p = 1; p < i-1; p++) {
entryI = entryI.next;
}
entryI.next = entryI.next.next;
entryI.next.value = null;
entryI.next.next = null;
size--;
}
}
// 改
//改第i个
public void change(E value,int i){
Entry<E> entryI = first;
for(int p = 1;p < i;p++){
entryI = entryI.next;
}
entryI.value = value;
}
// 查
//查第i个
public void searchI(int i){
try {
Entry<E> entryI = first;
for (int p = 1; p < i; p++) {
entryI = entryI.next;
}
System.out.println("第 "+i+" 个是: "+entryI.value);
}catch (NullPointerException e){
System.out.println("超出查询范围");
}
}
//按查value
public void searchV(E value){
try {
Entry<E> entryV = first;
int i = 1;
while (i < size) {
if (entryV.value == value) {
System.out.println(value+" 在第 :" + i + "个");
}
entryV = entryV.next;
}
System.out.println("没有查到");
}catch (NullPointerException e){
System.out.println("超出查询范围");
}
}
//查链表长度
public int size(){
int num = 0;
for(Entry<E> p = first ; p!=null ; p=p.next){
num++;
}
return num;
}
// 判断链表成环,并且求出环的位置
public Entry<E> isLoop(){
Entry<E> fast = first , slow = first;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
return fast;
}
}
return null;
}
public Entry<E> getIntersectEntry(){
Entry<E> meet = isLoop();
if(meet == null){
return null;
}
Entry<E> p = meet;
Entry<E> q = first;
while (p!=q){
p = p.next;
q = q.next;
}
return p;
}
//打印链表
public void show(){
for(Entry<E> p = first ; p!=null ; p=p.next){
System.out.print(p.value);
}
}
}
————————————————
版权声明:本文为CSDN博主「阎八一」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40879743/article/details/90646399