转自<http://blog.sina.com.cn/s/blog_69824c1f0100v4ob.html>
struct node
{
int data;
struct node * next;
struct node * random;
};
本题来源是ms的一道面试题,要求是将一条有特殊结构的链表进行复制,链表的结构如上,除了正常的2个域之外,多了一个random,它代表一个指向链表 上某一任意节点的指针,要求将该链表复制。如图,其中实线表示next域,虚线表示random域。
难点分析:本题最难的部分就在于如何将random域完好无损的完全拷贝复制到新的链表之上,对于普通链表一个while循环拷贝就可以搞定,但是这里似乎不可行。
突破点:如何保存或记录random域可以作为一个思考的参考点,下面提供2种解法:
1. hash缓存: 我们可以定义一个hash表,key为被拷贝链表中Node的地址,value为新的拷贝链表中Node的值。下面将在伪代码中进一步说明
伪代码如下:
struct node * old_list;
struct node * new_list;
hash ht;
while( old_list != NULL )
{
if( ht.get(old_list) == NULL )
// 当前节点没有被复制过,则拷贝节点,同时将原节点的地址作为key,插入hash表
{
new_node = copy(*old_list);
ht.set(old_list, new_node);
}
else // 已经存在则直接将该节点读出
{
new_node = ht.get(old_list);
}
// 并将新复制的节点插入链表
insert(new_list, new_node);
if( ht.get(old_list->random) == NULL )
// 如果ht的random不存在,那么产生一个random node,并放入hash表
{
random_node = copy(*(old_list->random));
ht.set(old_list->ramdon,random_node);
}
else //否则从hash表中读出random
{
random_node = ht.get(old_list->random);
}
// 将random域进行填充
new_node->random = random_node;
}
这样可以看出,因为地址值是唯一存在的,所以Hash函数的设计可以保证每个节点的值都会被一一映射,并且由于每一个节点都只会被复制一次,并且在代码的遍历过程中就已经完全复制好,空间复杂度为O(n),时间复杂度为O(n)
2. 用一个图的方法看的比较清楚,首先在遍历原来链表的过程中,插入新的节点,比如A_N是copy(A_O)的,同时将A_N->next = A_O->next; A_O->next = A_N;通过一个遍历,我们就可以将链表复制成图中的样子。在完成next域的链接后,需要开始做random域的复制。
在实现了next的结构之后,我们需要开始对new_list的random域和next域进行赋值。
那么有: A_N->random = A_O->random->next;
入图所示:A_O->random为C_O,C_O的next为C_N,这样A_N->random = C_N;
对于 A_N->next = A_N->next->next;即B_N;
该算法复杂度为O(N),空间复杂度为O(1),除了新拷贝的空间之外没有额外地址;
相关推荐
此外,对于空链表的情况,如代码中所示,需要特殊处理,确保函数能够正确返回 NULL。 总的来说,复杂链表的复制是一个涉及到链表操作和指针处理的复杂问题,通过巧妙地在原始链表上构建副本并逐步调整指针关系,...
在本问题中,我们关注的是一个特殊的链表,其中包含了一个额外的随机指针(random pointer),这个指针可以指向链表中的任意节点,而不仅限于下一个节点。这个数据结构在某些算法问题和复杂数据模型中非常有用。 ...
循环链表是一种特殊的线性表,它通过将链表的尾节点指向头节点,形成了一个闭环的数据结构。与普通链表相比,循环链表在处理某些问题时更加方便,比如实现队列、模拟游戏中的轮流机制等。 ### 八种功能概述 1. **...
本例中的代码虽然存在一些不易理解的部分(如注释中的特殊字符),但整体上展示了如何在C语言中创建和操作链表。 以上就是对提供的文件信息进行的详细分析和解释,希望这些知识点能够帮助您更深入地了解C语言中的...
循环链表是一种特殊的链式数据结构,其特点是最后一个节点的指针指向列表的开头,形成一个闭合的循环。在本实验报告中,学生需要实现循环链表的相关操作,包括插入、复制、查找、判断空表以及删除等功能,并对这些...
DOUBLE链表是一种特殊的链表,它具有双向链表的特点,即每个节点都有两个指针,一个指向上一个节点,另一个指向下一个节点。今天,我们将讲述如何使用c语言实现DOUBLE链表。 首先,我们需要定义DOUBLE链表的结构体...
对于检测两个链表是否有交点的问题,首先需要考虑特殊情况,即两个链表的头指针相同,那么它们自然有交点。对于一般情况,可以通过比较两个链表的长度来解决。计算两个链表的长度len1和len2,然后让指针p1从较长链表...
在C语言中,数组形链表是一种特殊的数据结构,它结合了数组的高效访问和链表的灵活扩展性。这种数据结构通常用于处理动态数组,其中元素可以方便地添加或删除,而不需要像传统数组那样预先知道确切的大小。本文将...
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会...
但由于静态链表的特殊性,指针域不再是实际的内存地址,而是数组中的下标。 ```c typedef struct Node { int data; // 数据域 int next_index; // 指针域,表示下一个节点在数组中的下标 } StaticListNode; ``` ...
链表复制涉及创建一个新的链表,其中每个节点都对应原链表的一个节点。这需要为每个原链表的节点创建新的节点,并设置相应的数据和指针。 8. 链表的排序: 链表可以使用各种排序算法进行排序,如冒泡排序、选择排序...
复杂链表是一种特殊的链表结构,它的每个结点不仅有一个指向下一个节点的指针,还有一个随机指针域,该指针域可以指向链表中的任意一个节点或为空结点。这种链表结构使得链表的操作变得更加复杂。 二、复杂链表的...
十字链表是一种特殊的链表形式,它主要用于稀疏矩阵的存储。在稀疏矩阵中,非零元素的数量远少于零元素的数量,因此采用普通的二维数组存储会浪费大量空间。十字链表通过存储非零元素的位置和值来高效地表示这种矩阵...
6. **动态数组扩容**:当顺序表满时,创建新数组并复制旧数组元素,然后释放旧数组。 7. **性能比较**:通过实验比较链表和顺序表在不同操作下的性能差异,如插入、删除和查找。 这个实验将帮助你深入理解这两种...
队列是一种特殊的线性数据结构,它遵循“先进先出”(FIFO,First In First Out)的原则。在计算机科学中,队列被广泛应用在任务调度、数据缓冲、多线程同步等多个领域。本篇文章将深入探讨如何用数组和链表两种数据...
在C++编程中,"异秩链表"是一种特殊的链表结构,它的每个节点可以包含不同类型的附加数据,这在处理具有多种不同类型元素的数据集合时非常有用。在本例中,设计了一个用C++实现的异秩链表,用于管理学校人员的信息,...
“单向链表操作详解(二)”这篇文档可能还涵盖了特殊情况的处理,例如空链表操作、错误处理以及优化链表操作的技巧等。通过详尽的实例和解释,读者可以深入理解单链表的工作原理,并学会在实际编程中灵活运用。阅读...
在C语言中,复杂链表是一种特殊的链表结构,每个节点不仅包含数据域和指向下一个节点的指针,还包含一个额外的指针域,该指针可以指向链表中的任意节点或为空。这种结构使得复杂链表的操作相比简单链表更加复杂,但...
9. **链表的复制**:创建链表的一个完全副本,这需要深拷贝所有节点。 在www.pudn.com.txt文件中,可能包含了题目说明、样例输入输出或者其他相关资料,帮助理解作业要求和测试用例。 总的来说,这个作业涵盖了...
- 如果第一个多项式的指数大于第二个,则将第二个多项式的当前节点复制到结果链表中。 - 如果第一个多项式的指数小于第二个,则将第一个多项式的当前节点复制到结果链表中。 - 最后处理剩余的节点。 #### 主函数 ``...