复杂链表的复制

复杂链表的复制,一个链表的每个节点,有一个指向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;


}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
”的理解,不少于300字。 1. 对C中“指针”的理解 在C语言中,指针是一种特殊的数据类型,它可以存储另一种数据类型的内存地址。指针的本质是一个内存地址,它可以指向任何内存单元,包括变量、函数、数组等。指针可以让程序直接访问内存中的数据,而不是通过变量名或数组名来访问。指针在C语言中应用广泛,它是C语言的重要特性之一。 指针的声明方式和变量的声明方式类似,只需要在变量名前面加上一个星号(*),就可以定义一个指针变量。例如,int *p;就定义了一个指向int类型数据的指针变量p。指针变量可以通过赋值操作来指向指定的内存单元,例如,p=&a;就表示让指针p指向变量a的内存地址。通过指针变量可以直接访问指向的内存单元,例如,*p=10;就表示将变量a的值设置为10。 指针在C语言中应用广泛,主要用于以下几个方面: 1)内存管理:指针可以动态分配内存、释放内存,实现灵活的内存管理。 2)数据结构:指针可以实现链表、树等复杂数据结构,提高程序的效率和灵活性。 3)函数调用:指针可以作为函数参数传递,实现函数间的数据共享和数据传递。 4)指针数组:指针数组是一个数组,其中的每个元素都是一个指针,可以实现对多个数据的操作。 总之,指针是C语言中非常重要的特性,其应用广泛,能够提高程序的效率和灵活性,但也需要程序员具有一定的技能和经验来正确使用指针,避免出现指针错误等问题。 2. 对C中“引用”的理解 在C语言中,引用是一种特殊的指针,它可以让程序访问内存中的数据,但不需要使用指针的语法。引用是C++语言中的一个特性,在C语言中并没有官方的引用类型,但可以通过指针来实现引用的功能。 引用的本质是一个内存地址,但它与指针的语法不同,引用可以像变量一样使用,而不需要使用星号(*)和取地址符(&)来访问。引用可以理解为一个别名,它指向与之关联的变量或对象,对引用的操作实际上是对其关联的变量或对象的操作。 引用在C++语言中应用广泛,主要用于以下几个方面: 1)函数调用:引用可以作为函数参数传递,通过引用传递可以避免数据的复制,提高程序的效率。 2)返回值:函数可以返回引用类型的值,通过引用返回可以避免数据的复制,提高程序的效率。 3)操作符重载:引用可以作为操作符重载函数的参数或返回值,实现自定义的数据类型操作。 总之,引用是C++语言中非常重要的特性,其应用广泛,能够提高程序的效率和灵活性。在C语言中,虽然没有官方的引用类型,但可以通过指针来实现类似引用的功能。了解引用的概念和使用方法,对于程序员来说是非常有益的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值