复杂链表的复制——26

实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext的指针指向下一个结点外,还有一个m_pSibling的指针指向链表中任意结点或者NULL。

如下如所示的一个复杂链表,没有画出_sib指针的结点表示_sib指向NULL:

   对于复杂链表的复制,首先可以想到的是先遍历一遍链表复制出各个结点并设置好_next指针,复制好单向的链表之后,对于_sib的随机指针则需要每一次都从头遍历找出距当前结点多远的结点才是应该指向的随机结点,虽然可行,但不难发现这样寻找随机结点的时间复杂度是O(N*N);

首先,有一种方法,仍然是先遍历链表创建出相应的结点并设置好每一个的_next指针,之后用一个哈希桶来保存每一个原链表结点的地址和新创建出结点的地址信息,也就是在每一个原链表结点地址的下面链上新创建出对应的链表结点的地址,这样的话一次就能定位新复制出链表中每一个结点的_sib应该指向哪一个对应的结点了;虽然时间复杂度降为了O(N),但这是一种以空间换时间的方法;

另外的一种方法,是在遍历到原链表的一个结点的时候,就新创建出一个结点插入当前结点的后面,完成之后原链表就变成了两个连续重复的结点的双倍长度的链表,这样的话,原来链表中结点的_sib后面的重复的结点,也就会是新创建链表对应结点的_sib的指向,之后再从头访问链表,将原链表中每个结点对应的_sib指针后面的结点赋值给当前结点后面新创建结点的_sib,这样也就完成了新建链表的_sib指向,之后再将两个链表拆开就可以了;

程序设计如下:

#include <iostream>
#include <assert.h>
using namespace std;

int list_num = 0;

struct ComplexListNode//复杂链表结点数据结构
{
    int _val;
    ComplexListNode* _next;
    ComplexListNode* _sib;

    ComplexListNode(int val)//构造函数
        :_val(val)
         ,_next(NULL)
         ,_sib(NULL)
    {}  
};

ComplexListNode* Buy_Node(int val)//构建复杂链表结点
{
    ComplexListNode* node = new ComplexListNode(val);
    return node;
}

//插入结点
void Push_Node(ComplexListNode** phead, int val)
{
    if((*phead) == NULL)
        (*phead) = Buy_Node(val);
    else
    {   
        ComplexListNode* tmp = (*phead);
        while(tmp->_next != NULL)
            tmp = tmp->_next;
        tmp->_next = Buy_Node(val);
    }

    ++list_num;
}

//设置自由结点的指向
void SetSibPointer(ComplexListNode* head, int* positions)
{
    assert(head && positions);

    ComplexListNode* tmp = head;
    ComplexListNode *p[list_num];
    for(size_t i = 0; i < list_num; ++i)
    {
        p[i] = tmp;
        tmp = tmp->_next;
    }

    tmp = head;
    for(size_t i = 0; i < list_num; ++i)
    {
        if(positions[i] != 0)
            tmp->_sib = p[positions[i]];

        tmp = tmp->_next;
    }
}

//销毁链表
void DestoryList(ComplexListNode* head)
{
    if(head != NULL)
    {
        ComplexListNode* tmp = head;
        while(head != NULL)
        {
            head = head->_next;
            delete tmp;
            tmp = NULL;
            tmp = head;
        }
    }
}

//打印链表
void PrintList(ComplexListNode* head)
{
    if(head != NULL)
    {
        ComplexListNode *tmp = head;
        while(tmp != NULL)
        {
            cout<<tmp->_val<<"->";
            tmp = tmp->_next;
        }
        cout<<"NULL"<<endl;

        tmp = head;
        while(tmp != NULL)
        {
            cout<<tmp->_val<<" sibling is ->";
            if(tmp->_sib != NULL)
                cout<<tmp->_sib->_val<<endl;
            else
                cout<<"NULL"<<endl;

            tmp = tmp->_next;
        }
    }
}

//复制复杂链表
ComplexListNode* Clone(ComplexListNode* head)
{
    if(head != NULL)
    {
        ComplexListNode *tmp = head;
        ComplexListNode *newnode = NULL;

        //复制每个结点并插入当前结点的后面
        while(tmp != NULL)
        {
            newnode = Buy_Node(tmp->_val);
            newnode->_next = tmp->_next;
            tmp->_next = newnode;
            tmp = newnode->_next;
        }

        //设置新创建链表结点的sib指针的指向
        tmp = head;
        newnode = tmp->_next;
        while(tmp != NULL)
        {
            if(tmp->_sib != NULL)
                newnode->_sib = tmp->_sib->_next;
            tmp = newnode->_next;
            if(tmp != NULL)
                newnode = tmp->_next;
        }
        //拆分两个链表
        tmp = head;
        ComplexListNode* NewHead = tmp->_next;
        newnode = tmp->_next;
        while(tmp != NULL)
        {
            tmp->_next = newnode->_next;
            tmp = tmp->_next;
            if(tmp != NULL)
            {
                newnode->_next = tmp->_next;
                newnode = newnode->_next;
            }
        }

        return NewHead;
    }
}

int main()
{
    ComplexListNode* head = NULL;
    Push_Node(&head, 7);
    Push_Node(&head, 5);
    Push_Node(&head, 8);
    Push_Node(&head, 2);
    Push_Node(&head, 6);
    Push_Node(&head, 9);
    Push_Node(&head, 3);

    int positions[7] = {2,5,0,4,0,0,4};
    SetSibPointer(head, positions);
    cout<<"Complex List: ";
    PrintList(head);
     ComplexListNode* NewComplexListHead = Clone(head);
    cout<<"New Complex List: ";
    PrintList(NewComplexListHead);
    cout<<"Complex List: ";
    PrintList(head);

    DestoryList(head);
    DestoryList(NewComplexListHead);
    return 0;
}

运行程序:

《完》

时间: 2024-10-20 18:50:46

复杂链表的复制——26的相关文章

《剑指offer》面试题26 复杂链表的复制 Java版

(定义一个新的数据结构,每个节点除了具有普通链表的next域外,还有一个额外的引用指向任意节点.我们要对由该特殊数据结构形成的链表进行复制.) 我的方法:也就是克隆一个这种特殊链表,很快想到先不考虑原链表sibling域,复制出一个新的链表,然后再去给sibling域赋值.由于sibling可以指向任何节点,而且我们是根据原链表的sibling来确定新链表中的sibling,所以每次我们寻找新链表中某个节点的sibling,都要两个指针重新从头开始扫描以确定新链表中的sibling.所以时间复杂

剑指offer之【复杂链表的复制】

题目: 复杂链表的复制 链接: https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?tpId=13&tqId=11178&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为

C语言之复杂链表的复制(图示详解)

什么是复杂链表? 复杂链表指的是一个链表有若干个结点,每个结点有一个数据域用于存放数据,还有两个指针域,其中一个指向下一个节点,还有一个随机指向当前复杂链表中的任意一个节点或者是一个空结点.今天我们要实现的就是对这样一个复杂链表复制产生一个新的复杂链表. 复杂链表的数据结构如下: 1 typedef int DataType; //数据域的类型 2 3 //复杂链表的数据结构 4 5 typedef struct ComplexNode 6 7 { 8 9 DataType _data ; //

剑指Offer24 复杂链表的复制

1 /************************************************************************* 2 > File Name: 24_ComplexListClone.cpp 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年08月31日 星期三 14时24分35秒 6 ********************************

浅谈复杂链表的复制

链表是一种很常见的数据结构,单链表.双向链表.循环链表和复杂链表都是其衍生物.复杂链表之所以命名为复杂链表,也正是由于其结构的复杂.它比其他其他种类的链表多了一个指针域,这个指针域可以指向链表中的任一结点,也可以为空. 其结构定义如下: struct ComplexNode { DataType _data; struct ComplexNode * _next; struct ComplexNode * _random;//随机域 }; 结构示例: ps:蓝色指针为next域,红色为rando

【剑指offer】复杂链表的复制

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26154691 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为一个整数n (1<=n<=1000):n代表将要输入的链表元素的个数.(节点编号从1开始).接下来有n个数,表示链表节点中的值.接下来有n个数Ti,Ti表示第i个节点的另

19--复杂链表的复制。

/* 题目: 复杂链表的复制. struct ComplexListNode { int m_vlaue; ComplexListNode *m_next; ComplexListNode *m_pSibling; }: m_next,连接下一个结点,m_pSibling随便链接结点其他节点. 这样复制结点就有难度,一次遍历明显不可能全部解决. 策略: 第一种方法: 先复制一遍链表,让m_pnext把结点连接起来.第二轮在复制另一个指针,复杂度为O(n*n); 第二种方法: 先复制一遍链表,然后

算法题:复制复杂链表之复制连接法

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 上篇文章算法题:复制复杂链表之空间换时间法我们给出了用映射的方法来为新复制的链表中的每个结点设置any指针,本文给出的是<剑指offer>上给出的算法与代码,<剑指offer>上提到该算法的实现三个步骤:        第一步:复制原始链表的任意结点N并创建新结点N',在把N'连接到N的后面:        第二步:设置每个结点的any指针:        第三步:将长链表分成两个链表,一个是原始链表,另外一个就是我们所要求的复制

复杂链表的复制-剑指Offer

复杂链表的复制 题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 思路 分三步(分而治之) 将链表复制下来追加到每个元素的后面,例如A->A'->B->B'->C->C'... 复制每个元素的random指针 从整体的链表中间隔的取出复制出来的链表 代码 /* public class RandomListNode { int label; RandomListNode next = null; Random