【面试题】复杂链表的复制

一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。

对于这个题,基本会有三个思路:

1.这里链表的复制和单链表最大的不同,就是多了一个自由指针(psub),那么最简单的想法就是,遍历单链表,找到psub指向的节点,然后复制,这样做最简单,事件复杂度为O(n的平方);
2. 基于第一种方法的优化,第一种方法把事件浪费在了查找节点上,那么我们可以建立一个哈希函数,对节点建立唯一的键值对(k,v), 在复制时,利用哈希函数,时间为O(n);
3.当然哈希函数虽好,但是明显是以空间来换时间,那么有没有其他方法呢?能不能不开辟辅助空间呢?
(1)

(2)将新节点的psub连接起来。
1.设置两个指针,一前一后分别指向新旧节点;
2.新节点的psub = 老节点的psub->next;
(3)

思路为:
1.设置三个指针
2.一个作为新链表的头结点;
3.剩余两个交替指向新旧节点,具体如图
#pragma once
#include 
    
    
     
     
#include 
     
     
      
      

typedef struct ListNode{
	int value;
	ListNode* next;
	ListNode* psub;
}Node, *pNode;

pNode createNode(int data)
{
	pNode temp = (pNode)malloc(sizeof(Node));
	temp->next = NULL;
	temp->psub = NULL;
	temp->value = data;
	return temp;
}

void InitList(pNode* pHead)
{
	*pHead = NULL;
}

void Print(pNode pHead)
{
	pNode t = pHead;
	while (t)
	{
		printf("%d->", t->value);
		t = t->next;
	}
	printf("NULL");
}
void push_back(pNode* pHead, int data)
{
	if (NULL == *pHead)
	{
		*pHead = createNode(data);
	}
	else
	{
		pNode tm = *pHead;
		while (tm->next)
		{
			tm = tm->next;
		}
		tm->next = createNode(data);
	}
}

pNode FindNode(pNode pHead, int data)
{
	pNode lt = pHead;
	while (NULL != lt)
	{
		if (lt->value == data)
		{
			return lt;
		}
		lt = lt->next;
	}

	return lt;
}

void pSub(pNode* pHead, int data1, int data2)
{
	if (data2 == 0 || data1 == 0)
	{
		return;
	}
	pNode tem = *pHead;
	while (NULL != tem)
	{
		if (tem->value == data1)
		{
			break;
		}
		tem = tem->next;
	}
	tem->psub = FindNode(*pHead, data2);
}
/*
 *  第一步:将每一个节点创建出来,并插在对应节点的后面
 *  第二步:将每个新建的节点的pSub连接好
 *  第三步:将两个链表分开
 */

void copyNewNode(pNode pHead)
{
	if (NULL == pHead)
	{
		return;
	}

	pNode temp = pHead;
	while ( NULL != temp)
	{
		pNode newNode = createNode(temp->value);
		newNode->next = temp->next;
		temp->next = newNode;

		temp = temp->next->next;
	}
}

void ConnectPsub(pNode pHead)
{
	if (NULL == pHead)
	{
		return;
	}
	pNode pn1 = pHead;
	pNode pn2 = pHead->next;
	while (NULL != pn2->next && NULL != pn2->next->next)
	{
		if (NULL != pn1->psub)
		{
			pn2->psub = pn1->psub->next;
		}
		pn1 = pn1->next->next;
		pn2 = pn2->next->next;
	}
	if (NULL != pn2->next)
	{
		pn2 = pn2->next;
		pn1 = pn1->next;
		if (pn2->psub != NULL)
		{
			pn2->psub = pn1->psub->next;
		}
		else
		{
			return;
		}
	}
}

pNode SeparateList(pNode pHead)
{
	if (NULL == pHead)
	{
		return pHead;
	}

	pNode pold = pHead;
	pNode ppHead = NULL;
	pNode ppNode = NULL;

	ppHead = ppNode = pHead->next;
	while (NULL != ppNode->next)
	{
		pold->next = ppNode->next;
		pold = pold->next;
		ppNode->next = pold->next;
		ppNode = ppNode->next;
	}
	return ppHead;
}


#include "1.hpp"

int main()
{
	pNode p;
	InitList(&p);
	push_back(&p, 1);
	push_back(&p, 2);
	push_back(&p, 3);
	push_back(&p, 4);
	push_back(&p, 5);
	push_back(&p, 6);
	Print(p);
	pSub(&p, 1, 4);
	pSub(&p, 2, 5);
	pSub(&p, 3, 6);
	pSub(&p, 4, 0);
	pSub(&p, 5, 0);
	pSub(&p, 6, 2);
	printf("\n");
	copyNewNode(p);
	Print(p);

	printf("\n");
	ConnectPsub(p);
	Print(SeparateList(p));
	printf("\n");
	return 0;
}
     
     
    
    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值