在链表中,有环链表,交叉链表,返回倒数第k个节点可谓非常经典,所以对java的实现做总结如下:
1、首先定义一个链表节点的类Node;
class Node{
int value;
Node next;
public Node(){
this(0);//注意调用时必须处在构造方法的第一行
}
public Node(int val){
this.value=val;
this.next=null;
}
}
2、在类LinkList中实现链表的头插创建 ,判环,求倒数第K个节点,以及判断两链表是否相交
class LinkList{
Node head;
public LinkList(){
this.head=new Node();//调用Node的第一个构造方法
}
public void insertHead(int val){ //头插法
Node n=new Node(val);
n.next=this.head.next;
head.next=n;
}
public boolean haveCircle(){//判断有环的思路为两个节点,fast走两步,slow走一步,若fast和slow最终相等,则证明有环,否则不会相等
if(head==null)return false;
Node fast=head;
Node slow=head;
while(fast.next!=null && fast.next.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
break;
}
}
if(fast==slow)return true;
else return false;
}
public Node firstCircleNode(){ //碰撞点到入口点的距离等于head到入口点的距离
if(!this.haveCircle())return null;
Node fast=head.next.next;
Node slow=head.next;
while(fast!=slow){
fast=fast.next.next;
slow=slow.next;
}
Node p=head;
while(p!=slow){
p=p.next;
slow=slow.next;
}
return p;
}
public int getCircleNodeNum(){//第一次相交与第二次相交slow所走过的节点个数;
if(!this.haveCircle())return 0;//如果没有环则返回0;
Node fast=head.next.next;
Node slow=head.next;
Node f1=null;Node f2=null;
int count=0;
while(f1==null || f2==null){
if(fast==slow && f1!=null){
f2=fast;
}
if(fast==slow && f1==null){
f1=fast;
}
if(f1!=null && f2==null){
count ++;
}
fast=fast.next.next;
slow=slow.next;
}
return count;
}
private int listNode(LinkList list){//私有方法用来返回链表的节点数
int n=-1;
Node p=list.head;
while(p!=null){
p=p.next;
n+=1;
}
return n;
}
private Node LinkCross(LinkList list){//分别求出两个链表的个数,让个数多的先走k(多的个数)步
Node p=this.head;//两链表相交,则从交点处汇聚为一条链
Node q=list.head;
if(p==null || q==null)return null;
int np=listNode(this);
int nq=listNode(list);
int n=np-nq;
while(n>0){
p=p.next;
n--;
}
while(n<0){
q=q.next;
n++;
}
while(p!=null || q!=null){
if(p==q)break;
p=p.next;q=q.next;
}
if(p==q)return p;
else return null;
}
public boolean isLinkCross(LinkList list){//判断是否相交
Node p=LinkCross(list);
if(p==null)return false;
else return true;
}
public Node LinkNode(LinkList list){
return LinkCross(list);
}
public Node findReverseKNode(int k){//返回倒数第K个节点时间复杂度为O(n)
int n=listNode(this);
if(n<k)return null;
Node f=head;
Node s=head;
while(k>0){
f=f.next;
k--;
}
while(f!=null){
f=f.next;
s=s.next;
}
return s;
}
public String toString(){
StringBuilder builder=new StringBuilder();
if(haveCircle())return "链表有环";
Node n=head;
while(n.next!=null){
builder.append(n.next.value+" ");
n=n.next;
}
return builder.toString();
}
public LinkList createList(){ //随机生成单链表
LinkList L=new LinkList();
for(int i=0;i<10;i++){
L.insertHead((int)(Math.random()*10));
}
return L;
}
public LinkList createCircleList(){ //随机生成带环链表
LinkList L=createList();
Random r=new Random();
int k=r.nextInt(10);
//System.out.printf("环的入口节点为第%d个\n",k);
Node p=L.head;
Node q=L.head;
while(p.next!=null){
if(k==0)q=p.next;//随机环的入口节点
k--;
p=p.next;
}
p.next=q;//链接形成环;
return L;
}
public void createLink(LinkList List){
Node p=head;
while(p.next!=null){
p=p.next;
}
p.next=List.head.next;
}
}
3、在主函数中对各种方法进行调用检测
public class TLinkList {
public static void main(String [] args) {
LinkList L=new LinkList();
LinkList L1=L.createList();
LinkList L2=L.createCircleList();
System.out.println("判断L1链表是否有环:"+L1.haveCircle());
System.out.println("判断L2链表是否有环:"+L2.haveCircle());
System.out.println("有环链表的入口点的value值为:"+(L2.firstCircleNode()).value);
System.out.println("计算环的节点个数:"+L2.getCircleNodeNum());
System.out.println("L1链表的倒数第3个节点为:"+L1.findReverseKNode(3).value);
System.out.println("L1链表的节点元素为:"+L1.toString());
//创建两条相交链表L3、L4;
LinkList L3=L.createList();
LinkList L4=L.createList();
L3.createLink(L1);//将L1链接在L3的末尾
L4.createLink(L1);//将L1链接在L4的末尾
System.out.println("判断L3和L4是否相交:"+L3.isLinkCross(L4));
System.out.println("两链表链接的节点元素的值为:"+L3.LinkNode(L4).value);
System.out.println("L3链表的节点元素为:"+L3.toString());
System.out.println("L4链表的节点元素为:"+L4.toString());
}
}
运行结果: