【本文链接】

http://www.cnblogs.com/hellogiser/p/clone-of-complex-linked-list.html

【题目】

有一个复杂链表,其结点除了有一个next指针指向下一个结点外,还有一个sibling指向链表中的任一结点或者NULL。其结点的C++定义如下:

 C++ Code 
1
2
3
4
5
6
7
 
// complex node struct
struct ComplexNode
{
    int value;
    ComplexNode *next;
    ComplexNode *sibling;
};

下图是一个含有5个结点的该类型复杂链表。图中实线箭头表示next指针,虚线箭头表示sibling指针。为简单起见,指向NULL的指针没有画出。

请完成函数ComplexNode* Clone(ComplexNode* pHead),以复制一个复杂链表。

分析】

在常见的数据结构上稍加变化,这是一种很新颖的面试题。要在不到一个小时的时间里解决这种类型的题目,我们需要较快的反应能力,对数据结构透彻的理解以及扎实的编程功底。

分为2步:

(1)复制每一个节点,连接next,初步生成【新链表】,时间复杂度为T(n)=O(1)*n=O(n);

(2)连接sibling,假设在【新链表】中定位sibling的时间复杂度为T,则总的时间复杂度为T(n)=T*n;

由此可见,最为关键的是如何在【新链表】中快速定位sibling节点

【方法1】

统计从头结点该sibling节点的步长step。

假设【原始链表】中的某节点N的sibling指向结点S。由于S的位置在链表上有可能在N的前面也可能在N的后面,所以要定位N的位置我们需要从原始链表的头结点开始找。假设从【原始链表】的头结点开始经过step步找到结点S。那么在【新链表】上从头结点开始经过step可以到结点N'的sibling对应的结点S'。定位sibling的时间复杂度为T=O(n) 。总的时间复杂度O(n2),空间复杂度为O(1)

【方法2】

使用map映射记录<A,A'>,<B,B'>,<C,C'>,这样定位sibling的时间复杂度为T=O(1) 。总的时间复杂度O(n),但是空间复杂度为O(n),相当与以O(n)的空间消耗实现了O(n)的时间效率。

【方法3】

根据原始链表的每个结点N,创建对应的N'。让后将N和N'连接起来,这样定位sibling的时间复杂度为T=O(1) ,之后重新分成2个链表即可。总的时间复杂度O(n),空间复杂度为O(1)

(1)创建新节点,并连接next。

(2)定位sibling并连接。

(3)链表拆分成两个:把奇数位置的结点链接起来就是原始链表,把偶数位置的结点链接出来就是复制出来的链表。

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
 
// complex node struct
struct ComplexNode
{
    int value;
    ComplexNode *next;
    ComplexNode *sibling;
};

//Clone all nodes in a complex linked list with pHead,
//and connect all nodes with next link.
void CloneNodes(ComplexNode *pHead)
{
    //  A-A'-B-B'-C-C'
    if(NULL == pHead)
        return;
    ComplexNode *pNode = pHead;
    while(pNode != NULL)
    {
        ComplexNode *pNewNode = new ComplexNode();
        pNewNode->value = pNode->value;
        pNewNode->next = pNode->next;
        pNewNode->sibling = NULL; // init NULL

// connect pNode and pNewNode
        pNode->next = pNewNode;

//move to next node
        pNode = pNewNode->next;
    }
}

//Connect sibling nodes in a complex link list
void ConnectSiblingNodes(ComplexNode *pHead)
{
    //  A-A'-B-B'-C-C'
    if(NULL == pHead)
        return;
    ComplexNode *pNode = pHead;
    while(pNode != NULL)
    {
        ComplexNode *pNewNode = pNode->next;
        // connect sibling nodes
        if(pNode->sibling != NULL)
            pNewNode->sibling = pNode->sibling->next;
        else
            pNewNode->sibling = NULL;
    }
}

// Split a complex list into two:
// Reconnect nodes to get the original list, and its cloned list
ComplexNode *ReconnectNodes(ComplexNode *pHead)
{
    //  A-A'-B-B'-C-C'
    if(NULL == pHead)
        return;
    ComplexNode *pNode = pHead;
    ComplexNode *pNewHead = pHead->next;
    ComplexNode *pNewNode = pNewHead;
    while(pNode != NULL)
    {
        // reconnect next nodes for pNode
        pNode->next = pNewNode->next;
        // move pNode to next
        pNode = pNewNode->next;

// reconnect next nodes for pNewNode
        if(pNode != NULL)
        {
            pNewNode->next = pNode->next;
            pNewNode = pNode->next;
        }
        else
        {
            pNewNode->next = NULL;
            pNewNode = NULL;
        }
    }
    return pNewHead;
}

ComplexNode *Clone(ComplexNode *pHead)
{
    CloneNodes(pHead);
    ConnectSiblingNodes(pHead);
    return ReconnectNodes(pHead);
}

【参考】

http://zhedahht.blog.163.com/blog/static/254111742010819104710337/

http://www.cnblogs.com/kedebug/archive/2012/12/21/2828131.html

【本文链接】

http://www.cnblogs.com/hellogiser/p/clone-of-complex-linked-list.html

49. 3种方法实现复杂链表的复制[clone of complex linked list]的更多相关文章

  1. C语言数据结构-创建链表的四种方法

    结点类型: typedef int datatype; typedef struct NODE{ datatype data; struct NODE *next; }Node,*LinkList; ...

  2. 用python介绍4种常用的单链表翻转的方法

    这里给出了4种4种常用的单链表翻转的方法,分别是: 开辟辅助数组,新建表头反转,就地反转,递归反转 # -*- coding: utf-8 -*- ''' 链表逆序 ''' class ListNod ...

  3. 【java基础 13】两种方法判断hashmap中是否形成环形链表

    导读:额,我介绍的这两种方法,有点蠢啊,小打小闹的那种,后来我查了查资料,别人都起了好高大上的名字,不过,本篇博客,我还是用何下下的风格来写.两种方法,一种是丢手绢法,另外一种,是迷路法. 这两种方法 ...

  4. 转载 50种方法优化SQL Server数据库查询

    原文地址 http://www.cnblogs.com/zhycyq/articles/2636748.html 50种方法优化SQL Server数据库查询 查询速度慢的原因很多,常见如下几种: 1 ...

  5. 哈希表(一):解决hash冲突的几种方法

    (一)线性探测法 线性探测法是最简单的处理冲突的方法. (1)插入元素:插入元素时,如果发生冲突,算法将从该槽位向后遍历哈希表,直到找到表中的下一个空槽,并将该值放入到空槽当中. (2)查找元素:查找 ...

  6. C#中常用的读取xml的几种方法(转)

    本文完全来源于http://blog.csdn.net/tiemufeng1122/article/details/6723764,仅作个人学习之用. XML文件是一种常用的文件格式,例如WinFor ...

  7. 改善C#程序,提高程序运行效率的50种方法

    改善C#程序,提高程序运行效率的50种方法   转自:http://blog.sina.com.cn/s/blog_6f7a7fb501017p8a.html 一.用属性代替可访问的字段 1..NET ...

  8. Java 字符串拼接 五种方法的性能比较分析 从执行100次到90万次

    [请尊重原创版权,如需引用,请注明来源及地址] > 字符串拼接一般使用“+”,但是“+”不能满足大批量数据的处理,Java中有以下五种方法处理字符串拼接,各有优缺点,程序开发应选择合适的方法实现 ...

  9. Matlab中数组元素引用——三种方法

    Matlab中数组元素引用——三种方法   1.Matlab中数组元素引用有三种方法 1 2 3 1.下标法(subscripts) 2.索引法(index) 3.布尔法(Boolean) 注意:在使 ...

随机推荐

  1. 内核控制Meta标签:让360浏览器默认使用极速模式打开网页(转)

    为了让网站页面不那么臃肿,也懒的理IE了,同时兼顾更多的国内双核浏览器,在网页页头中添加了下面两行Meta控制标签. 1,网页头部加入 <meta name="renderer&quo ...

  2. git 命令学习

    last-update: 2016年10月27日 1. git stash 简短描述 当你正在进行项目中某一部分的工作,但是里面的东西处于一个比较杂乱的状态,但是却想要切换到其他分支.问题是,你不想提 ...

  3. caffe添加自己的层

    首先修改src/caffe/proto/下的caffe.proto,修改好后需要编译 然后修改include/caffe/layers/logwxl_layer.hpp 然后修改src/caffe/l ...

  4. 浅谈servlet

    刚开始接触servlet的时候,其实不是太理解servlet的,后来经过慢慢摸爬滚打式的的学习,有了一点自己的理解. servlet的产生还要从Java和HTTP说起: Java的servletAPI ...

  5. 学记:spring boot使用官网推荐以外的其他数据源druid

    虽然spring boot提供了4种数据源的配置,但是如果要使用其他的数据源怎么办?例如,有人就是喜欢druid可以监控的强大功能,有些人项目的需要使用c3p0,那么,我们就没办法了吗?我们就要编程式 ...

  6. 【codeforces 148D】 Bag of mice

    http://codeforces.com/problemset/problem/148/D (题目链接) 题意 包中有w个白鼠,b个黑鼠.公主和龙轮流画老鼠,公主先画,谁先画到白鼠谁就赢.龙每画完一 ...

  7. 分享一些平时测试用的sql payloads

    1:BOOL SQLINJECTION \'"%df'%df" and 1=1 and 1=2' and '1'='1' and '1'='2" and "1& ...

  8. LinuxMint配置Git(图文教程)

    1.生成秘钥(直接回车,秘钥存放路径看命令行信息) 2.打开秘钥,需要注意的是.ssh可能是隐藏的,这时需要Ctrl+H显示隐藏文件夹 3.复制秘钥,添加到GitHub(Settings), 4.添加 ...

  9. JAVA源码分析-HashMap源码分析(一)

    一直以来,HashMap就是Java面试过程中的常客,不管是刚毕业的,还是工作了好多年的同学,在Java面试过程中,经常会被问到HashMap相关的一些问题,而且每次面试都被问到一些自己平时没有注意的 ...

  10. JS中class和id的区别

    class和id的区别 class用于css的,id用于js的. 1)class页面上可以重复.id页面上唯一,不能重复. 2)一个标签可以有多个class,用空格隔开.但是id只能有id.