数据结构——链表:拷贝一个带随机指针的链表

链表入门(二):

拷贝一个带随机指针的链表。

分析:

1.考虑这个问题之前,先思考如何拷贝一个普通的链表:即只有数据和一个next指针的链表。这其实很简单,只需要创建新节点,让新节点的值与就节点相同即可,再将链表连接起来就大功告成了。

上代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
	int data;
	struct Node* next;
}Node;

//创建节点
Node* BuyNode(int data) {
	Node* node = (Node*)malloc(sizeof(Node));
	node->data = data;
	node->next = NULL;
	return node;
}

void NodePrint(Node* head) {
	//先进行判空
	Node* cur = head;
	if (cur == NULL) {
		printf("链表为空!!!\n");
	}
	while (cur != NULL) {
		printf("%d -->", cur->data);
		cur = cur->next;
	}
}





int main() {
	Node* n1 = BuyNode(10);
	Node* n2 = BuyNode(20);
	Node* n3 = BuyNode(30);
	Node* n4 = BuyNode(40);
	//连接链表
	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	NodePrint(n1);
	//开始拷贝原链表
	printf("\n\n拷贝的链表是:\n");
	Node* cur = n1;
	Node* copy = NULL;
	Node* last = NULL;//用来记录新链表的尾结点
	while (cur != NULL) {
		Node* node = (Node*)malloc(sizeof(Node));
		//如果拷贝链表为空
		if (copy == NULL) {
			node->data = cur->data;
			node->next = NULL;
			copy = node;
			last = node;
		}
		//拷贝链表非空
		else {
			node->data = cur->data;
			node->next = NULL;
			last->next = node;
			last = node;
		}
		cur = cur->next;
	}
	NodePrint(copy);
	system("pause");
	return 0;
}

这就是普通链表的拷贝过程。

2。学会拷贝普通链表以后,再来考虑拷贝带随机指针的链表。

首先看带随机指针的链表长什么样:

如图,我们用代码将它们的random的指向写出来,就是这样:

node1->random=node3;

node2->random=node1;

node3->random=node3;

node->4->random=NULL;

分析:

我们是否能像普通链表拷贝那样直接复制结点来连接链表?答案是否定的。

原因:比如:当复制node1的时候node3还没有创建,因此random会指向一段非法的内存空间,我们无法去直接拷贝它。

在这里我们利用他们的next来进行拷贝。方法如下:

三部曲:

1.复制旧链表的结点并将其尾插到旧链表的结点中去。

2.根据旧链表的random值设置新链表的random的值

3.将设置好random后的链表拆分成旧链表和新链表。

来张图瞧瞧:

这就是基本思路,话不多说,上代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
	int data;
	struct Node* next;
	struct Node* random;
}Node;

Node* BuyNode(int data) {
	Node* node = (Node*)malloc(sizeof(Node));
	node->data = data;
	node->random = NULL;
	node->next = NULL;
	return node;
}

Node* NodeInit(Node* head) {
	head = NULL;
	return head;
}

Node* CopyNode(Node*head) {
	//先复制链表的结点并插入到原节点的后面
	Node* cur = head;//用来遍历旧链表的结点
	while (cur != NULL) {
		Node* node = (Node*)malloc(sizeof(Node));
		node->data = cur->data;
		node->random = NULL;

		node->next = cur->next;
		cur->next = node;
		cur = node->next;
	}
	//再根据原节点的random对先结点的random进行修改
	cur = head;
	while (cur != NULL) {
		
		if (cur->random != NULL) {
			cur->next->random = cur->random->next;
		}
		cur = cur->next->next;
	}
	//最后将链表拆分成旧链表和新链表,再将新链表的头节点返回即可
	//:需要做的就是修改旧链表结点的next和新链表节点的next
	//因为最后要返回的是新链表的头节点,所以先将它记录下来
	cur = head;
	Node* newhead = head->next;
	while (cur!=NULL) {
		Node* node = cur->next;//用来遍历新链表结点
		cur->next = node->next;
		if (node->next != NULL) {
			node->next = cur->next->next;
		}
		cur = cur->next;
	}
	return newhead;
}

void NodePrint(Node* head) {
	Node* cur = head;
	if (cur == NULL) {
		printf("链表为空!!!\n");
	}
	else {
		while (cur != NULL) {
			printf("%p : %d (%p)--->  ", cur, cur->data, cur->random);
			cur = cur->next;
		}
	}
	return;
}



int main() {
	Node* n1 = BuyNode(10);
	Node* n2 = BuyNode(20);
	Node* n3 = BuyNode(30);
	Node* n4 = BuyNode(40);
	//连接链表
	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	//n4->next = NULL;
	//random指针的指向
	n1->random = n3;
	n2->random = n1;
	n3->random = n3;
	n4->random = NULL;
	NodePrint(n1);
	printf("\n\n复制后的新链表:\n\n\n");
	Node* newnode = CopyNode(n1);
	NodePrint(newnode);
	system("pause");
	return 0;
}

总结:

复制带随即指针的链表步骤——三部曲:

1.复制旧结点的内容插入到旧结点的后面(并将结点的random置空即为NULL)

2.根据旧结点的random指向来设置新链表的random指向。

3.将链表拆分成旧链表和新链表,拆分后的新链表就是目标链表了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值