16 复杂链表的复制

来源:互联网 发布:姆潘巴现象知乎 编辑:程序博客网 时间:2024/06/14 06:48

前言

本博文部分图片, 思路来自于剑指offer 或者编程珠玑

问题描述

这里写图片描述

思路

对于这个问题, 书中给出了两种解法, 难点在于对于sibling引用的复制
对于 这两种思路, 我本来是想画图的, 但是 感觉绘制起来挺有难度的, so 文字描述吧, “剑指offer” p148 有详细的解释

思路一 : 然后根据原链表的数据创建一个新的链表, 确保该链表中除了next, sibling引用之外的其他卫星数据和原链表中的数据一致, 使用一个Map维护创建的新旧对象的映射< oldObj_N, newObj_N >, 然后在根据原链表的各个结点的next, sibling引用 配合Map更新复制的链表的各个结点的next, sibling引用到各个新的对应的数据

思路二 : 在原来的链表的每一个结点创建其对应的拷贝结点, 并更新旧结点和新节点的引用, 形成”旧-旧 -> 旧-新-旧-新” 使得新旧两个链表练成一个链表, 然后更新每一个新节点的sibling结点为对应的旧结点的sibling结点的下一个结点, 最后拆分两个链表, 即将新链表 和旧链表的各个结点的各个next引用更新为各自应该的下一个结点

参考代码

/** * file name : Test09ComplexListCopy.java * created at : 4:22:52 PM Jun 7, 2015 * created by 970655147 */package com.hx.test05;public class Test09ComplexListCopy {    // 复制一个复杂的链表    public static void main(String []args) {        int num = 5;        Node first = createComplexList(num);        Node tmp = first;        while(tmp != null) {            Log.log(tmp);            tmp = tmp.next;        }        Log.horizon();        tmp = complexListCopy(first);//      tmp = complexListCopy02(first);        while(tmp != null) {            Log.log(tmp);            tmp = tmp.next;        }    }    // 思路 : 先复制first以及其之后的所有Node的数据, 在更新每一个node的next, sibling数据        // 更新sibling数据使用一个Map, 其在复制所有Node数据的时候构建, 其维护的是原来的Node 和新的Node的映射    static Node lastFirst = null;    static Node lastHead = null;    static Map<Node, Node> nodesMap = new HashMap<Node, Node>();    public static Node complexListCopy(Node first) {        if(first == null) {            return null;        }        if(first == lastFirst) {            return lastHead;        }        nodesMap.clear();        Node head = new Node(first);        nodesMap.put(first, head);        Node tmp = first.next;        while(tmp != null) {            nodesMap.put(tmp, new Node(tmp));            tmp = tmp.next;        }        for(Node node : nodesMap.values() ) {            node.next = nodesMap.get(node.next);            node.sibling = nodesMap.get(node.sibling);        }        lastFirst = first;        lastHead = head;        return head;    }    // 思路 : 在原来的链表中每一个元素之后插入原来的元素的副本    // 然后  跟新每一个副本元素的sibling    // 然后  差分原来的链表 和副本链表    public static Node complexListCopy02(Node first) {        // 复制原来的链表的每一个元素, 并将其插入到改元素之后        Node tmp = first;        while(tmp != null) {            Node newNode = new Node(tmp);            tmp.next = newNode;            tmp = newNode.next;        }        // 更新副本结点的sibling        tmp = first;        while(tmp != null) {            tmp.next.sibling = tmp.sibling.next;            tmp = tmp.next.next;        }        // 差分链表        Node head = first.next;        tmp = first;        Node tmp02 = tmp.next.next;        // 注意更新 next的顺序, 不要先更新了tmp.next....        while(tmp02 != null) {            tmp.next.next = tmp02.next;            tmp.next = tmp02;            tmp = tmp02;            tmp02 = tmp.next.next;        }        tmp.next = tmp.next.next = null;        return head;    }    // 创建一个复杂链表, sibling 随机指向一个结点    static Random rand = new Random();    private static Node createComplexList(int num) {        Node[] nodes = new Node[num];        nodes[nodes.length-1] = new Node(num-1, null, null);        for(int i=nodes.length-2; i>=0; i--) {            nodes[i] = new Node(i, nodes[i + 1], null );        }        for(int i=0; i<nodes.length; i++) {            nodes[i].sibling = nodes[rand.nextInt(num)];        }        return nodes[0];    }    // 一个结点    static class Node {        // 数据, 下一个结点, 兄弟结点        int data;        Node next;        Node sibling;        // 初始化        public Node() {            super();        }        public Node(int data, Node next, Node sibling) {            super();            set(data, next, sibling);        }        public Node(Node node) {            set(node.data, node.next, node.sibling);        }        // setter        public void set(int data, Node next, Node sibling) {            this.data = data;            this.next = next;            this.sibling = sibling;        }        // Debug        public String toString() {             String nextData = "null";            if(next != null) {                nextData = next.data + "@" + next.hashCode();            }            String siblingData = "null";            if(siblingData != null) {                siblingData = sibling.data + "@" + sibling.hashCode();            }            return data + " - " + nextData + " - " + siblingData;        }    }}

效果截图

这里写图片描述

总结

对于第一种思路, 想到不是很难, 第二种思路则是非常巧妙的, 如果不从书籍 或者其他的途径中获取, 估计没有灵感的话, 想破头都不一定能想出来。。

注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!

0 0
原创粉丝点击