复杂链表的复制,一个链表的每个节点,有一个指向next指针指向 下一个节点,还有一个random指针指向这个链表中的一个随机节点 或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
图中红色的指针代表着next指针,绿色的代表着random指针,random可能指向链表中的任何一个元素也可能指向了他自己甚至是NULL,如果想要对这种链表进行复制的话,就不仅仅是之前的普通复制了。
但是还是和以前一样的基本思路,首先需要将各个位置的数据复制出来,
在原有链表每个数据的后边,再对数据进行一个复制先将数据复制出来再将链表中的指针进行复制。
ComplexListNode *cur = list;
ComplexListNode *copy = NULL;
while (cur)
{
copy = BuySListNode(cur->_data);
copy->_next = cur->_next;
cur->_next = copy;
cur = copy->_next;
}
通过简单的while循环就可以在以前数据后边复制一份一样的,在这里注意一定要先将
copy->_next = cur->_next;copy的next指针指向之前cur的next不然如果先将 cur->_next = copy那再找cur->_next的时候就不能找到了。
将原链表变成第二幅图的时候这时候就要开始将random指针进行复制。
cur = list;
copy = cur->_next;
while (cur)
{
if (cur->_random != NULL)
{
copy->_random = cur->_random->_next;
}
else
{
copy->_random = NULL;
}
cur = copy->_next;
copy = cur->_next;
}
这复制random指针是很巧妙的。将cur再次指向链表的头,然后将copy指向cur->_next,这里你copy的random就是你cur的random 的next,因为你之前是将你的链表数据进行过一次复制的。
即使你的某个位置的数据的random指向的是自己,就比如3数据,cur指向的是原链表的3,这里copy指向的是复制之后的3,这里cur->_random != NULL,所以,复制之后的3的random指向的是原链表的random(也就是他自己)的next,就是指向了,复制之后的3.
进行上次while循环之后链表会变成这样。
这里将链表赋值结束之后,最后一步就是将这两个链表进行拆开,拆开之后得到的两个链表就是一模一样的复制前和复制之后的链表。
但是拆开这一步是最复杂,最难理解的一步。
首先用三个指针cur指向链表的头,copy指向复制后的第一个元素,这里还需要设置另一个指针这里设置另外一个指针的原因是,这个复制函数在复制完成后需要返回这个复制后的链表所以需要一个指针指向这个复制之后的链表的头,方便之后对这个链表进行操作。
cur = list;
clone = cur->_next;
while (cur->_next)
{
copy = cur->_next;
cur->_next = copy->_next;
copy->_next = cur->_next->_next;
}
return clone;
首先将复制链表的第一个存下来,方便以后进行返回,之后用while循环,直到链表的结尾。先让copy指向cur->_next,然后让cur->_next指向 copy->_next,之后copy->_next等于cur->_next->_next。即使是最后一个元素也是可以顺利完成的,最后一个copy的元素的next指向的就是空。
其实这些代码,实现起来并不麻烦,只是需要的是思想。
然后很多人写了这个代码之后不会写测试程序不知道,怎么才能验证这个函数的正确性。
typedef struct ComplexListNode
{
int _data;
ComplexListNode* _next;
ComplexListNode* _random;
}ComplexListNode;
ComplexListNode* BuySListNode(int x)
{
ComplexListNode *NewNode;
NewNode = (ComplexListNode*)malloc(sizeof(ComplexListNode));
if (NewNode == NULL)
{
printf("空间分配失败\n");
}
else
{
NewNode->_data = x;
NewNode->_next = NULL;
NewNode->_random = NULL;
}
return NewNode;
}
这里先把结构体和分配空间函数直接拷贝给大家,之后需要的是通过main函数创造一个复杂链表,很多人不知道怎么来创建其实很简单,我就创建一个我画的图中的链表。
int main()
{
ComplexListNode *n1 = BuySListNode(1);
ComplexListNode *n2 = BuySListNode(2);
ComplexListNode *n3 = BuySListNode(3);
ComplexListNode *n4 = BuySListNode(4);
n1->_next = n2;
n2->_next = n3;
n3->_next = n4;
n4->_next = NULL;
n1->_random = n3;
n2->_random = n4;
n3->_random = n3;
n4->_random = NULL;
}
创建四个存着数据为1、2、3、4数据的四个结点,然后手动将四个数据的next,还有random链接起来。
之后想要验证复制是否成功的话,第一个方法你可以通过内存来看一下你的返回的链表的数据,或者说,你可以通过一个myprintf函数,将你每个位置数据、next数据、random数据都打印出来看一下就很容易的判断是不是复制成功了。
因为还有很多程序需要写,这里就不给大家写printf函数了,测试程序就需要大家自己来写一下,判断一下程序的正确性了。
ComplexListNode* CopyComplexList(ComplexListNode* list)
{
ComplexListNode *cur = list;
ComplexListNode *copy = NULL;
ComplexListNode *clone = NULL;
while (cur)
{
copy = BuySListNode(cur->_data);
copy->_next = cur->_next;
cur->_next = copy;
cur = copy->_next;
}
cur = list;
copy = cur->_next;
while (cur)
{
if (cur->_random != NULL)
{
copy->_random = cur->_random->_next;
}
else
{
copy->_random = NULL;
}
cur = copy->_next;
copy = cur->_next;
}
cur = list;
clone = cur->_next;
while (cur->_next)
{
copy = cur->_next;
cur->_next = copy->_next;
copy->_next = cur->_next->_next;
}
return clone;
}