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
- 16 复杂链表的复制
- 链表16:复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复杂链表的复制
- 复制复杂的链表
- 复杂链表的复制
- [LeetCode-111] Minimum Depth of Binary Tree (二叉树最小深度)
- 大整数乘法---分治
- MySQL慢日志查询用法
- 深入理解Java内存模型(六)——final
- Python学习手册 - 11
- 16 复杂链表的复制
- 从僵尸网络追踪到入侵检测 第8章 Honeyd配置文件使用
- 二叉树三种遍历(递归及非递归)的实现
- 修改mysql数据库的用户名和密码
- 安装完 MySQL 后必须调整的 10 项配置
- Linux下设置环境变量
- MYSQL 备份与恢复
- oracle 的自连接(self join)操作(转载的)
- MySQL处理数据库和表的常用命令