定义一个单链表,先定义一个节点,实现判断链表是否为空、在链表中插入节点(头插和尾插)、删除节点等操作
//定义节点
class Node{
int value; //结点存放的值
Node next; //next域
public Node(){
this(0); //this引用
}
Node(int value){
this.value = value;
this.next = null;
}
}
//定义单链表
class LinkList{
Node head; //头结点
LinkList next; //next域
public LinkList(){
head = new Node();
}
//判断链表是够否空
public boolean empty(){
return head.next == null;
}
//头插法
public void insertHead(int value){
Node n = new Node(value); //定义一个新节点
n.next = head.next; //将n插到头结点后
head.next = n;
}
//尾插法
public void insertTail(int value){
Node ptail = head; //将头结点赋予尾
while(ptail.next != null){
ptail = ptail.next;
} //找到单链表的尾部
ptail.next = new Node(value); //插入新节点
}
//删除值为value的节点
public void delete(int value){
Node pcur = head.next;
Node ppre = head;
while(pcur != null){
if(pcur.value == value){
ppre.next = pcur.next;
break;
}
ppre = pcur;
pcur = pcur.next;
}
}
//自己实现toString的方法,利用StringBuilder//可以改变底层元素的值
public String toString(){
StringBuilder builder = new StringBuilder();
Node n = head.next;
while(n != null){
builder.append(n.value+" ");//插入值为value的节点
n = n.next;
}
return builder.toString();
}
}
1.判断单链表是否有环:定义两个引用变量,慢变量slow,快变量fast,慢变量一次走1个节点,快变量一次走2个节点,当两个变量所指的值相等时退出循环
//判断当前单链表是否有环 true:有环 false:没有环
public boolean haveCircle(){
Node slow = head;
Node fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
return true;
}
}
return false;
}
2.如果单链表有环,返回环的入口节点
先判断是否有环,若有环,将快引用fast移回到头结点,慢引用slow在它们的相交节点,同时向后移直至再次相交,相交节点就是入口节点
慢指针slow走到相遇点走了x+y,快指针走了x+y+(n-x-y)+y,而快指针走的距离是慢指针的两倍,即快指针走了2x+2y,所以2x+2y = x+y+(n-x-y)+y,即2x + y = n
public Node firstCircleNode(){
//碰撞点到连接点的距离 = 头指针到连接点的距离
if(this.haveCircle() == false){
return null;
}
else{
Node fast = this.head;
Node slow = this.head;
while(fast != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
fast= head;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return fast;
}
}
3.寻找单链表的倒数第K个节点:
定义两个引用变量,第一个变量在正数第K个节点位置,第二个变量个在头部,然后两个变量一起遍历直至第一个变量走到尾部,然后返回第二个变量所指的节点
public Node findReverseKNode(int k){
Node p1= head;
Node p2= head;
if(p1 == null || k < 1){
return null;
}
while(p1.next != null && k > 1){
p1 = p1.next; //正数第k个
k--;
}
while(p1 != null){
p1 = p1.next; // k = length - (length - k)
p2 = p2.next;
}
return p2;
}
4.判断链表相交(只传入一个参数,另一个环引用此函数)
先求出两个链表的长度,然后让长链表先跑两个链表长度之差,接着两个链表一起向后遍历直至有值相等
public boolean isLinkCross(LinkList list){
if (!(this.haveCircle() || list.haveCircle())) {
int l1 = this.length();
int l2 = list.length();
int n;
Node p = this.head;
Node q = list.head;
if(l1 > l2){ //如果p是长链表,让p先走长度之差
n = l1 - l2;
for(int i=0;i<n;++i){
p = p.next;
}
}
else{ //如果q是长链表,让q先走长度之差
n = l2- l1;
for(int i=0;i<n;++i){
q = q.next;
}
}
while(p!=q && p.next != null){
p = p.next;
q = q.next;
if(p == q){
retern true;
break;
}
}
else if (this.HaveCircle()&&list.HaveCircle()) {
if (firstCircleNode() ==firstCircleNode()){
return true;
// 两个有环单链表,它们环的入口结点相同时,它们相交
}
else{
return false;
}
}
return false;
}