您的位置:首页 > 理论基础 > 数据结构算法

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

2016-12-13 12:28 417 查看

本次题目全部选自剑指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个数。值得注意的是:1、k是否超过链表长度且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’只能根据

B到E要走的步数= 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;

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: