链表(下)

1.实现单链表反转
有四种方法,代码如下:

package linkedlist;

import java.util.Stack;

public class ReverseIteratively {
    /*
     * 方法一:存储为数组,按照数组的索引逆序进行反转
     * 或者利用栈
     */
    public static void reversePrint(Node head){
        if(head==null){
            return;
        }
        Stack<Node> stack=new Stack<Node>();
        Node current=head;
        while(current!=null){
            stack.push(current);
            current=current.next;
        }
        while(!stack.isEmpty()){
            System.out.println(stack.pop().data+" ");
        }
    }

    /*
     * 方法二:使用三个指针遍历单链表,逐个链接点进行反转
     */
    public static Node reverseIteratively(Node head){
        if(head==null){
            return head;
        }
        Node p=new Node();
        Node q=new Node();
        Node r=new Node();
        p=head;
        q=head.next;
        head.next=null;
        while(q!=null){
            r=q.next;
            q.next=p;
            p=q;
            q=r;
        }
        head=p;
        return head;
    }
    /*
     * 方法三:从第二个结点到第n个结点,逐结点插入到第一个结点之后
     * 最后将第一个结点挪到新表的表尾
     */
    public static Node reverse(Node head){
        Node p=new Node();
        Node q=new Node();
        p=head.next;
        while(p.next!=null){
            q=p.next;
            p.next=q.next;
            q.next=head.next;
            head.next=q;
        }
        p.next=head;
        head=p.next.next;
        p.next.next=null;
        return head;
    }
    /*
     * 方法四:递归,和从尾到头输出单链表相似
     */
    public static Node printListReversely(Node pListHead){
//      if(pListHead!=null){
//          printListReversely(pListHead.next);
//          System.out.println(pListHead.data);
//      }
        if(pListHead==null||pListHead.next==null){
            return pListHead;
        }
        Node rehead=printListReversely(pListHead.next);
        pListHead.next.next=pListHead;//将头结点置于末端
        pListHead.next=null;//防止链表循环
        return rehead;
    }



public static void print(Node head){
        while(head!=null){
            System.out.print(head.data+" ");
            head=head.next;
        }
        System.out.println();
    }


    public static void main(String [] args){
        Node node1=new Node(2);
        Node node2=new Node(4);
        Node node3=new Node(1);
        node1.next=node2;
        node2.next=node3;


//      Node head=reverseIteratively(node1);
//      Node head=reverse(node1);
        Node head=printListReversely(node1);
//      reversePrint(node1);
        print(head);
//      printListReversely(node1);
    }

}

http://blog.csdn.net/feliciafay/article/details/6841115)为了更好地理解方法二,以下图片参考自上述网址:
这里写图片描述

2.寻找单链表的中间结点

package linkedlist;
/*
 * 有两个指针同时从头开始遍历
 * 一个快指针一次走两步,一个慢指针一次走一步
 * 快指针先到链表尾部,而慢指针恰好到达链表中部
 * (快指针到达链表尾部,链表长度为奇数时,慢指针指向的即是链表中间指针;
 * 链表长度为偶数时,慢指针指向的结点和慢指针指向的下一个结点都是链表的中间结点)
 */
public class SearchMid {

    public static Node searchMid(Node head){
        Node p=head;//快指针
        Node q=head;//慢指针
        while(p!=null && p.next!=null &&p.next.next!=null){
            p=p.next.next;
            q=q.next;
        }
        return q;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Node node1=new Node(2);
        Node node2=new Node(4);
        Node node3=new Node(1);
        Node node4=new Node(3);
        node1.next=node2;
        node2.next=node3;
        node3.next=node4;
        Node mid=searchMid(node1);
        System.out.println(mid.data);

    }

}

3.如何检测一个链表是否有环,并找到环的入口点

如果单链表有环,当fast与slow相遇时,slow指针肯定没有遍历完链表,而fast指针已经在环内循环了n圈,假设slow指针走了s步,则fast指针走了2s,设环长为r则满足:
2s=s+nr
s=nr
设整个链表长L,入口处于像雨点距离为x,起点到环入口点距离为a则:
a+x=nr
a+x=(n-1)r+r=(n-1)+L-a
a=(n-1)+(L-a-x)
即从链表起点head到入口点距离a,与从slow和fast的相遇点到入口点的距离相等,于是在链表头和相遇点分别设一个指针,每次走一步,两个指针必定相遇,并且相遇第一点即为环入口点:

package linkedlist;

public class IsLoop {
    /*
     * 定义两个指针fast和slow,二者的初始值都是指向链表头
     * slow每次前进一步,fast每次前进两步,两个指针同时向前移动
     * 快指针每移动一次都要和慢指针进行比较,直到当快指针等于慢指针为止,就证明这个链表是带环的
     * 否则证明该链表是不带环的循环链表(fast先行到达尾部为NUll,则为无环链表)
     */
    public static boolean isLoop(Node head){
        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);
    }

    /*
     * 找到环的入口点
     */
    public static Node findLoopPort(Node head){
        Node slow=head;
        Node fast=head;
        while(fast!=null && fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
            if(slow==fast){//相遇点
                break;
            }
        }
        if(fast==null||fast.next==null){
            return null;
        }
        slow=head;
        while(slow!=fast){
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Node node1=new Node(2);
        Node node2=new Node(4);
        Node node3=new Node(1);
        Node node4=new Node(3);
        Node node5=new Node(5);
        Node node6=new Node(7);
        node1.next=node2;
        node2.next=node3;
//      node3.next=node1;
        node3.next=node4;
        node4.next=node5;
        node5.next=node6;
        node6.next=node3;
        System.out.println(isLoop(node1));
        System.out.println(findLoopPort(node1).data);

    }

}

4.在不知道头指针的情况下删除指定结点

package linkedlist;
/*
 * 1.若待删除的结点为链表尾结点,则无法删除,因为删除后无法使其前驱节点的next指针置为空
 * 2.若待删除的结点不是链表尾结点,可以通过交换这个结点与其后继结点的值,然后删除后继结点
 */
public class DeleteNode {

    public static boolean deleteNode(Node n){
        if(n==null||n.next==null){
            return false;
        }
        int tmp=n.data;
        n.data=n.next.data;
        n.next.data=tmp;
        n.next=n.next.next;
        return true;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Node node1=new Node(2);
        Node node2=new Node(1);
        Node node3=new Node(6);
        node1.next=node2;
        node2.next=node3;
        System.out.println(deleteNode(node3));

    }

}

5.判断两个链表是否相交

链表,只有一个指向下一个结点的指针,所以只有汇聚,没有交叉,如图所示:
这里写图片描述

package linkedlist;

public class IsIntersect {
    /*
     * 两个链表相交,它们一定有着相同的尾结点
     * 思路:分别遍历两个链表,记录它们的尾结点,如果相同则链表相交
     * 算法时间复杂度为O(len1+len2)
     */
    public static boolean isIntersect(Node h1,Node h2){
        if(h1==null||h2==null){
            return false;
        }
        Node tail1=h1;
        while(tail1.next!=null){
            tail1=tail1.next;
        }
        Node tail2=h2;
        while(tail2.next!=null){
            tail2=tail2.next;
        }
        return tail1==tail2;
    }
    /*
     * 如果两个链表相交,如何找到相交的第一个结点
     * 思路:分别计算两个链表的长度len1和len2(设len1>len2)
     * 先对链表h1遍历(len1-len2)个结点到p,此时p和h2到它们相交的结点的距离相等
     * 同时遍历这两个链表,直到遇到相同的结点为止
     */
    public static Node getFirstMeetNode(Node h1,Node h2){
        if(h1==null||h2==null){
            return null;
        }
        Node tail1=h1;
        int length1=0;
        while(tail1.next!=null){
            tail1=tail1.next;
            length1++;
        }
        Node tail2=h2;
        int length2=0;
        while(tail2.next!=null){
            tail2=tail2.next;
            length2++;
        }
        if(tail1!=tail2){
            return null;
        }

        Node t1=h1;
        Node t2=h2;
        if(length1>=length2){
            int d=length1-length2;
            while(d!=0){
                t1=t1.next;
                d--;
            }
        }
        else{
            int d=length2-length1;
            while(d!=0){
                t2=t2.next;
                d--;
            }
        }
        while(t1!=t2){
            t1=t1.next;
            t2=t2.next;
        }
        return t1;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Node node1=new Node(2);
        Node node2=new Node(1);
        Node node3=new Node(9);
        Node node4=new Node(6);
        Node node5=new Node(7);
        Node node6=new Node(3);
        Node node7=new Node(5);
        node1.next=node2;
        node2.next=node6;
        node3.next=node4;
        node4.next=node5;
        node5.next=node6;
        node6.next=node7;
        boolean result=isIntersect(node1,node3);
        System.out.println(result);
        Node firstMeet=getFirstMeetNode(node1,node3);
        System.out.println(firstMeet.data);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值