一步一步学习数据结构(3)-链表及其操作实战

来源:互联网 发布:伊朗 沙特 知乎 编辑:程序博客网 时间:2024/06/06 02:46

本次题目全部选自剑指offer,主要是为了锻炼复习一下链表部分的基础知识。(全都java实现)

(1)剑指offer 5:从尾到头打印链表

题目大致为:  输入一个链表的头结点,从未到头反过来打印每个结点的值。

思路:题目的要求是进行从尾到头输出,而链表的查找只能是顺序查找,栈的结构满足这样的条件:先进后出。同样,也可以使用递归的方式求解。

code:
/**
 * @author Administrator
 *
 */
public class ListNode {

    public int value;
    public ListNode next;
    
    
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }   
}
import java.util.Stack;

/*
 * 从尾到头打印链表:输入一个链表的头结点,从尾到头反过来打印每个结点的值。
 * 思路:题目的要求是进行从尾到头输出,而链表的查找只能是顺序查找,栈的结构满足这样的条件:先进后出。同样,也可以使用递归的方式求解。
 */
public class PrintLianBiao {
    
public static void main(String[] args) {
    ListNode head=new ListNode(0);
    ListNode node_one=new ListNode(1);
    ListNode node_two=new ListNode(2);
    ListNode node_three=new ListNode(3);
    ListNode node_four=new ListNode(4);
    head.setNext(node_one);
    node_one.setNext(node_two);
    node_two.setNext(node_three);
    node_three.setNext(node_four);
    node_four.setNext(null);
    System.out.println("第一种方式:递归实现");
    printListReverse_1(head);
    System.out.println();
    System.out.println("第二种方式:非递归实现");
    printListReverse_2(head);
}
/*
 * 用递归实现
 */
public static void printListReverse_1(ListNode head){
    
    if(head!=null){
        if(head.next!=null){
            printListReverse_1(head.getNext());
        }
        System.out.print(head.getValue()+",");
    }
}
/*
 *非递归实现
 */
public static void printListReverse_2(ListNode head){
    Stack<Integer> s=new Stack<Integer>();
    ListNode p=head;
    //进栈
    while(p!=null){
        s.push(p.getValue());
        p=p.getNext();
    }
    //出栈
    while(!s.isEmpty()){
        System.out.print(s.pop()+",");
    }
    System.out.println();
}
}

(2)剑指offer 13:在O(1)时间删除链表结点

题目大致为:  给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

思路:

    想要在O(1)时间内删除链表的指定结点,要遍历的话得O(n),则肯定不能遍历。若是要删除的结点不是尾结点,那么可以将后面的那个值复制到该指针处,并将后面指针所指空间删除,用复制+删除后面的实现删除,时间复杂度为O(1)。对于尾结点,需要遍历,那么时间复杂度是O(n),但是总的时间复杂度为[(n-1)*O(1)+O(n)]/n,结果是O(1)。

codepublic class ListNode {

    public int value;
    public ListNode next;
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
}
/*
 * 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
 * 思路:
    想要在O(1)时间内删除链表的指定结点,要遍历的话得O(n),则肯定不能遍历。
    若是要删除的结点不是尾结点,那么可以将后面的那个值复制到该指针处,并将后面指针所指空间删除,用复制+删除后面的实现删除,时间复杂度为O(1)。
    对于尾结点,需要遍历,那么时间复杂度是O(n),但是总的时间复杂度为[(n-1)*O(1)+O(n)]/n,结果是O(1)。
 */
public class DeleteNodeinList {
public static void main(String[] args) {
    //构建链表
    ListNode head=new ListNode(1);
    ListNode node_2=new ListNode(2);
    ListNode node_3=new ListNode(3);
    ListNode node_4=new ListNode(4);
    ListNode node_5=new ListNode(5);
    ListNode node_6=new ListNode(6);
    ListNode node_7=new ListNode(7);
    head.setNext(node_2);
    node_2.setNext(node_3);
    node_3.setNext(node_4);
    node_4.setNext(node_5);
    node_5.setNext(node_6);
    node_6.setNext(node_7);
    node_7.setNext(null);
    //输出原始链表
    System.out.println("原始链表为:");
    printList(head);
    System.out.println("----------------------");
    //删除结点3
    deleteNode(head, node_3);
    printList(head);
    System.out.println("----------------------");
    //删除头结点
    deleteNode(head,head);
    printList(head);
    System.out.println("----------------------");
    //删除尾结点
    deleteNode(head,node_7);
    printList(head);
    System.out.println("----------------------");
}
/*
 * 打印链表
 */
public static void printList(ListNode head){
    ListNode current=head;
    while(current!=null){
        System.out.print(current.getValue()+",");
        current=current.getNext();
    }
    System.out.println();
}

/*
 * 删除结点
 */
public static void deleteNode(ListNode head,ListNode tobeDeleted){
    if(head==null||tobeDeleted==null){
        return;
    }
    //找到要删除结点的下一个结点
    if(tobeDeleted.getNext()!=null){
        ListNode p=tobeDeleted.getNext();//p为tobeDeleted的下一个结点
        tobeDeleted.setValue(p.getValue());
        //删除p结点
        tobeDeleted.setNext(p.getNext());
    }else if(head==tobeDeleted){
        //如果头结点就是需要删除的结点
        head=null;
    }else{
        //删除尾结点
        ListNode currentNode=head;
        while(currentNode.getNext()!=tobeDeleted){
            currentNode=currentNode.getNext();
        }
        currentNode.setNext(null);
    }
}
}

(3)剑指offer 15:链表中倒数第k个结点

题目大致为:在一个链表中,查找倒数的第k个数。

思路:使用双指针的方式,前一个指针先走k(中间隔k-1个结点),后一个指针才开始走,直到第一个指针走到尾,后一个指针指向的就是要找的倒数第k个数。值得注意的是:1k是否超过链表长度且k必须为正整数;2、链表是否为空。

public class ListNode {

    private int value;
    private ListNode next;
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
    
    
}

public class KthNodefromend {

    public static void main(String[] args) {
        //构建链表
        ListNode head=new ListNode(1);
        ListNode node_2=new ListNode(2);
        ListNode node_3=new ListNode(3);
        ListNode node_4=new ListNode(4);
        ListNode node_5=new ListNode(5);
        head.setNext(node_2);
        node_2.setNext(node_3);
        node_3.setNext(node_4);
        node_4.setNext(node_5);
        node_5.setNext(null);
        print(head);
        //查找第k个
        ListNode p=findKthtotail(head, 3);
        System.out.println(p.getValue());
        
    }
    public static ListNode findKthtotail(ListNode head,int k){
        //首先判断链表是否存在,K是否大于0
        if(head==null||k<0){
            return null;
        }
        ListNode prePoint=head;//第一个指针
        ListNode postPoint=head;//第二个指针
        
        for(int i=0;i<k-1;i++){
            if(prePoint.getNext()!=null){
                prePoint=prePoint.getNext();
            }else{
                return null;
            }
        }
        
        while(prePoint.getNext()!=null){
            prePoint=prePoint.getNext();
            postPoint=postPoint.getNext();
        }
        return postPoint;
    }
    
    public static void print(ListNode head){
        ListNode current=head;
        while(current!=null){
            System.out.print(current.getValue()+",");
            current=current.getNext();
        }
        System.out.println();
    }
}

(4)剑指offer 16:反转链表

题目大致为: 对于一个链表,反转该链表并返回头结点。

思路:

    主要是指针的操作,但是要注意不能断链。这里可以使用非递归的方式求解。

public class ListNode {

    private int value;
    private ListNode next;
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }  
}

/*
 * 反转链表
 * 题目大致意思为:对于一个链表反转该链表并返回头结点
 * 思路:主要是指针的操作,但是要注意不能断链。这里可以使用非递归的方式求解。
 */
public class ReverseListy {
    public static void main(String[] args) {
        //构建链表
        ListNode head=new ListNode(1);
        ListNode node_one=new ListNode(2);
        ListNode node_two=new ListNode(3);
        ListNode node_three=new ListNode(4);
        ListNode node_four=new ListNode(5);
        head.setNext(node_one);
        node_one.setNext(node_two);
        node_two.setNext(node_three);
        node_three.setNext(node_four);
        node_four.setNext(null);
        //打印
        //print(head);
        //打印反转链表
        ListNode reservedhead=reverseList(head);
        ListNode tmp=reservedhead;
        while(tmp!=null){
            System.out.println(tmp.getValue()+",");
            tmp=tmp.getNext();
        }
    }
    //非递归实现
    public static ListNode reverseList(ListNode head){
        ListNode reservedhead=null;
        ListNode pNode=head;
        ListNode pPrev=null;
        while(pNode!=null){
            ListNode pnext=pNode.getNext();
            
            if(pnext==null){
                reservedhead=pNode;
            }
            
            pNode.setNext(pPrev);
            pPrev=pNode;
            pNode=pnext;
        }
        return reservedhead;        
    }
    public static void print(ListNode head){
        ListNode current=head;
        while(current!=null){
            System.out.print(current.getValue()+",");
            current=current.getNext();
        }
        System.out.println();
    }
}

(5)剑指offer 17:合并两个排序的链表

题目大致为:输入两个递增排序的链表,合并这两个链表并使得新链表中的结点仍然按照递增排序的。

思路:

主要是链表中值的比较,取较小的结点插入到新的链表中。

public class ListNode {

    private int value;
    private ListNode next;
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
    
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }     
}

public class UnionTwoList {

    /*
     * 合并两个排序的链表
     * 题目大致意思为:输入两个递增排序的链表,合并这两个链表并使得新链表中的节点仍然按照递增排序
     * 思路:其实主要是链表中值得比较,取较小的结点插入到新的链表当中
     */
    public static void main(String[] args) {
        //构建链表1
        ListNode head1=new ListNode(1);
        ListNode node1_2=new ListNode(3);
        ListNode node1_3=new ListNode(5);
        ListNode node1_4=new ListNode(7);
        head1.setNext(node1_2);
        node1_2.setNext(node1_3);
        node1_3.setNext(node1_4);
        node1_4.setNext(null);
        //构建链表2
        ListNode head2=new ListNode(2);
        ListNode node2_2=new ListNode(4);
        ListNode node2_3=new ListNode(6);
        ListNode node2_4=new ListNode(8);
        head2.setNext(node2_2);
        node2_2.setNext(node2_3);
        node2_3.setNext(node2_4);
        node2_4.setNext(null);
        //打印两个链表
        System.out.println("链表1:");
        printList(head1);
        System.out.println("------------------------");
        System.out.println("链表2:");
        printList(head2);
        System.out.println("------------------------");
        System.out.println("合并后的链表:");
        ListNode head=mergeList(head1,head2);
        printList(head);
        System.out.println("------------------------");
        
    }
    
    
    public static ListNode mergeList(ListNode head1,ListNode head2){
        ListNode head=null;//合并后的头指针
        
        //如果有一个链表为空链表,则合并后直接是另一个链表
        if(head1==null){
            head=head2;
        }
        if(head2==null){
            head=head1;
        }
        //两个都不为空的时候
        if(head1!=null&&head2!=null){
            //node_1和node_2是用于遍历
            ListNode node_1=head1;
            ListNode node_2=head2;
            if(node_1.getValue()<node_2.getValue()){
                head=node_1;
                head.setNext(mergeList(node_1.getNext(), head2));
            }else{
                head=node_2;
                head.setNext(mergeList(head1, node_2.getNext()));
            }
        }
        return head;
    }
    public static void printList(ListNode head){
        ListNode current=head;
        while(current!=null){
            System.out.print(current.getValue()+",");
            current=current.getNext();
        }
        System.out.println();
    }
}

(6)剑指offer 37:两个链表的第一个公共结点

题目大致为:输入两个链表,找出它们的第一个公共结点。


思路:

第一个公共结点开始往后都是公共结点,所以在末尾向前遍历,就可以找到第一个公共结点。利用上面的思想,可以先计算两个链表的长度,计算两个链表的长度差,然后先遍历较长的链表,等到剩余长度相等时开始同时遍历,这样就能较快地找到相同的结点,时间复杂度为O(m+n),其中m,n分别为两个链表的长度。

public class ListNode {

    private int value;
    private ListNode next;
    
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
}

/*
 * 两个链表的第一个公共结点
 * 输入两个链表,找到他们的第一个公共点
 */
public class FirstCommonNodeinList {

    public static void main(String[] args) {
        
        ListNode head1=new ListNode(1);
        ListNode node_2=new ListNode(2);
        ListNode node_3=new ListNode(3);
        ListNode head2=new ListNode(4);
        ListNode node_5=new ListNode(5);
        ListNode node_6=new ListNode(6);
        ListNode node_7=new ListNode(7);
        head1.setNext(node_2);
        node_2.setNext(node_3);
        node_3.setNext(node_6);
        node_6.setNext(node_7);
        node_7.setNext(null);
        head2.setNext(node_5);
        node_5.setNext(node_6);
        ListNode result=findFirst(head1, head2);
        System.out.println("第一个公共结点是:"+result.getValue());
    }
    
    public static ListNode findFirst(ListNode head1,ListNode head2){
        ListNode p1=head1;
        ListNode p2=head2;
        int list_1_len=0;
        int list_2_len=0;
        //分别计算两个链表的长度
        while(p1!=null){
            list_1_len++;
            p1=p1.getNext();
        }
        while(p2!=null){
            list_2_len++;
            p2=p2.getNext();
        }
        //长度差
        int nlength=list_1_len-list_2_len;
        
        ListNode plong=head1;
        ListNode pshort=head2;
        if(list_1_len<list_2_len){
            plong=head2;
            pshort=head1;
            nlength=list_2_len-list_1_len;
        }
        //长的先走nlength步
        for(int i=0;i<nlength;i++){
            plong=plong.getNext();
        }
        //此时长度相等,一起向前走,并判断它们的值是否相等
        while(plong!=null && pshort!=null && plong!=pshort){
            plong=plong.getNext();
            pshort=pshort.getNext();
        }
        return plong;
    }
}

(7)剑指offer 56:链表中环的入口结点

题目大致为: 一个链表中包含环,如何找出环的入口结点?

思路:

   对于上图中的链表,首先得判断是否有环存在,在环存在的情况下求出环中结点的个数,最后类似求链表的倒数第K个结点求出入口结点。这样的过程可以使用快慢指针的方式求解。

public class ListNode {

    private int value;
    private ListNode next;
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
    
}

public class EntryNodeListLoop {

    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        ListNode node_2 = new ListNode(2);
        ListNode node_3 = new ListNode(3);
        ListNode node_4 = new ListNode(4);
        ListNode node_5 = new ListNode(5);
        ListNode node_6 = new ListNode(6);
        head.setNext(node_2);
        node_2.setNext(node_3);
        node_3.setNext(node_4);
        node_4.setNext(node_5);
        node_5.setNext(node_6);
        node_6.setNext(node_3);

        // 找到环的入口结点
        System.out.println("环的入口结点为:" + getEntry(head).getValue());
    }

    /*
     * 求出环内结点的个数
     */
    public static int numOfCircle(ListNode head) {
        // 链表是否存在
        if (head == null) {
            return -1;// -1表示不存在环
        }
        // 建立快慢指针
        ListNode fastNode = head;
        ListNode slowNode = head;

        int num = 0;// 环中结点的个数
        while (fastNode != null && slowNode != null) {
            if (fastNode.getNext() != null && fastNode.getNext().getNext() != null) {
                fastNode = fastNode.getNext().getNext();
            } else {
                return -1;// -1表示不存在环
            }
            slowNode = slowNode.getNext();
            // 相遇表示存在环
            if (slowNode == fastNode) {
                break;// 调出循环
            }
        }
        // 计算环中结点的个数
        num++;
        slowNode = slowNode.getNext();
        while (slowNode != fastNode) {
            slowNode = slowNode.getNext();
            num++;
        }
        return num;
    }

    /*
     * 得到入口的结点
     */

    public static ListNode getEntry(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode fastnode = head;
        ListNode slownode = head;
        for (int i = 0; i < numOfCircle(head); i++) {
            fastnode = fastnode.getNext();
        }
        while (fastnode != slownode) {
            slownode = slownode.getNext();
            fastnode = fastnode.getNext();
        }
        return fastnode;
    }
}

(8)剑指offer 57:删除链表中重复的结点

题目大致为:在一个排序的链表中,如何删除重复的结点?

思路:

原始的链表:


删除重复结点后的链表


链表中结点的删除,最关键的就是不能断链。在删除的过程中,被删除结点的前一个结点的指针必须保存,这样才不会断链,所以必须存在一个指针preNode


public class ListNode {

    private int value;
    private ListNode next;
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    
    public ListNode() {
        super();
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
     this.next = next;
    }
    
}

/*
 * 删除链表中重复的结点
 * 注意:链表中结点的删除,最关键的就是不能断链。在删除的过程中,被删除结点的前一个结点的指针必须保存,这样才不会断链,所以必须存在一个指针preNode。
 * 思路:定义四个结点,前结点prenode,当前结点node,下一个结点nextnode,删除结点delnode,在遇到删除结点时候要保证prenode连接上nextnode,防止断裂情况。
 */
public class DeletethesameNode {

    public static void main(String[] args) {
        ListNode head=new ListNode(1);
        ListNode node_2=new ListNode(2);
        ListNode node_3=new ListNode(3);
        ListNode node_4=new ListNode(3);
        ListNode node_5=new ListNode(4);
        ListNode node_6=new ListNode(4);
        ListNode node_7=new ListNode(5);
        head.setNext(node_2);
        node_2.setNext(node_3);
        node_3.setNext(node_4);
        node_4.setNext(node_5);
        node_5.setNext(node_6);
        node_6.setNext(node_7);
        print(head);
        ListNode result=deleteDuplication(head);
        print(result);
    }
    public static ListNode deleteDuplication(ListNode head){
        //链表为null
        if(head==null){
            return null;
        }
        //只有一个结点
        if(head.getNext()==null){
            return head;
        }
        //临时的头结点
        ListNode root=new ListNode();
        root.setNext(head);
        //记录前驱结点
        ListNode prev=root;
        //记录当前处理的结点
        ListNode node=head;
        while(node!=null&& node.getNext()!=null){
            //有重复结点,与node值相同的结点都需要删除
            if(node.getValue()==node.getNext().getValue()){
                //找到下一个不同值得点,注意其有可能也是重复结点
                while(node.getNext()!=null&&node.getValue()==node.getNext().getValue()){
                    node=node.getNext();
                }
                //指向下一个结点,pre.next也有可能是重复结点
                //所以prev需要移动到下一个结点
                prev.setNext(node.getNext());                
            }else{
                //相邻两个值不同,说明node不可删除,需要保留
                prev.setNext(node);
                prev=prev.getNext();
                        
            }
            node=node.getNext();
        }
        return root.getNext();
    }
    
    public static void print(ListNode head){
        while(head!=null){
            System.out.print(head.getValue()+"->");
            head=head.getNext();
        }
        System.out.println("null");
    }
}

(9)剑指offer 26:复杂链表的复制

题目描述:复制一个复杂链表,在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sbiling指向链表中的任意结点或者null。下图是一个复杂链表的示例,Null的指针没有画出。


解题思路:

1.很直观的解法就是分成两步:

1).复制原始链表上的每一个结点,并用next指针连起来。
2).复制sbiling指针。
但是复制sbiling指针时需要比较高的复杂度。
以上图为例,如果我们要复制B对应B’的的sbiling指针,那就是要找到E’,想要找到E’只能根据
BE要走的步数= B’到E’要走的步数
然而又如D.sbiling = B,指向的结点在它的前面,而链表并没有指向前一个元素的指针,所以,每次都只能根据从链表头结点到目标的结点的步数来找到sbiling应该指向的元素。
这种方法显然效率太低,时间复杂度达到了O(n*n)

2.书中提到了利用哈希表存储(N, N)的配对信息的方法

这是一个在时间上很高效的方法,在查找上,利用哈希表的高效性。但是缺点在于要用额外的空间。

3.更为高效的一种不利用辅助空间的方法

这个方法的巧妙之处在于利用链表结点本身记录sbiling指针的位置。
分成三个步骤
1).根据原始链表的每个结点N创建对应的N’,并把N’连在N的后面。
如下图:

2)看到上图我们就应该知道这个算法的巧妙之处了,B.sbiling就记录在B.sbiling.next,这一步就是通过这个方法设置sbiling指针了。

3).将两个链表断开。

public class ListNode {

    private int value;
    private ListNode next;
    private ListNode sbiling;
    public ListNode(int value, ListNode next, ListNode sbiling) {
        super();
        this.value = value;
        this.next = next;
        this.sbiling = sbiling;
    }
    public ListNode(int value, ListNode next) {
        super();
        this.value = value;
        this.next = next;
    }
    public ListNode(int value) {
        super();
        this.value = value;
    }
    public ListNode() {
        super();
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
    public ListNode getSbiling() {
        return sbiling;
    }
    public void setSbiling(ListNode sbiling) {
        this.sbiling = sbiling;
    }
    
    @Override
    public String toString(){
        StringBuilder sb=new StringBuilder();
        sb.append("value="+value);
        sb.append(",next="+(next==null?"null":next.value));
        sb.append(",sbiling"+(sbiling==null?"null":sbiling.value));
        return sb.toString();
    } 
}

public class CopyListNode {

    public static void main(String[] args) {
        ListNode head =new ListNode(1);
        ListNode node2=new ListNode(2);
        ListNode node3=new ListNode(3);
        ListNode node4=new ListNode(4);
        ListNode node5=new ListNode(5);
        
        head.setNext(node2);
        head.setSbiling(node3);
        
        node2.setNext(node3);
        node2.setSbiling(node5);
        
        node3.setNext(node4);
        
        node4.setNext(node5);
        node4.setSbiling(node2);
        /*while(head!=null){
            System.out.print(head+"->");
            head=head.getNext();
        }
        */
        //System.out.println("---------------");
        ListNode copyhead=copy(head);
        while(copyhead!=null){
            System.out.print(copyhead+"->");
            copyhead=copyhead.getNext();
        }
        
    }
    public static ListNode copy(ListNode head){
        copyList(head);
        
        setsbiling(head);
        
        return disconnect(head);
    }
    
    //1.根据原始链表的每个结点N创建对应的N’,并把N’连在N的后面。
    public static void copyList(ListNode head){
        ListNode node=head;
        while(node!=null){
            ListNode copynode=new ListNode(node.getValue());
            copynode.setNext(node.getNext());
            copynode.setSbiling(null);
            node.setNext(copynode);
            node=copynode.getNext();
        }
    }
    //2.设置sbiling指针
    public static void setsbiling(ListNode head){
        
        ListNode node=head;
        while(node!=null){
            ListNode copynode=node.getNext();
            if(node.getSbiling()!=null){
                copynode.setSbiling(node.getSbiling());
            }
            node=copynode.getNext();
        }        
    }
    //3.断开两个链表
    public static ListNode disconnect(ListNode head){
        
        ListNode node=head;
        ListNode copyhead=null;
        ListNode copynode=null;
        
        
        if(node!=null){
            copyhead=node.getNext();
            node.setNext(copyhead.getNext());
            node=copyhead.getNext();
            copynode=copyhead;
        }
        
        while(node!=null){
            ListNode temp=node.getNext();
            node.setNext(temp.getNext());
            node=node.getNext();
            copynode.setNext(temp);
            copynode=temp;
        }
        return copyhead;
    }
}

0 0