算法题:复制复杂链表之复制连接法

说明:本文仅供学习交流,转载请标明出处,欢迎转载!

上篇文章算法题:复制复杂链表之空间换时间法我们给出了用映射的方法来为新复制的链表中的每个结点设置any指针,本文给出的是《剑指offer》上给出的算法与代码,《剑指offer》上提到该算法的实现三个步骤:

       第一步:复制原始链表的任意结点N并创建新结点N‘,在把N‘连接到N的后面;

       第二步:设置每个结点的any指针;

       第三步:将长链表分成两个链表,一个是原始链表,另外一个就是我们所要求的复制链表。

     
 为了能够更加明显第理解整个求解过程,我们同样给出如下图:

实现代码如下:

#include<iostream>
#include<utility>
using namespace std;
struct Node
{
	int value;
	Node* next;
	Node* any;//指向某个结点
	Node(int v):value(v),any(NULL),next(NULL){}
};
/*创建一个链表,1->2->3->4->5->6->7*/
Node* CreateList()//创建一个单链表
{
   Node *head;
   Node *n1=new Node(1);
   Node *n2=new Node(2);
   Node *n3=new Node(3);
   Node *n4=new Node(4);
   Node *n5=new Node(5);
   Node *n6=new Node(6);
   Node *n7=new Node(7);
   head=n1;
   n1->next=n2;
   n1->any=n3;
   n2->next=n3;
   n2->any=n4;
   n3->next=n4;
   n4->next=n5;
   n5->any=n7;
   n5->next=n6;
   n6->next=n7;
   n7->next=NULL;
   return head;
}
void FreeList(Node *head)//将链表空间释放
{
	if(head==NULL)
	{
		return ;
	}
	else
	{
		Node *temp=head->next;
		delete head;
		head=temp;
		FreeList(head);
	}
}
void VisitList(Node *head)//遍历链表中的元素,用递归的方法遍历
{
	if(!head) return ;
	Node *p=head;
	while(p)
	{
		cout<<"("<<p->value;
		if(p->any)//记住NULL永远没有NULL
		{
			cout<<","<<p->any->value<<")";
		}
		else
		{
			cout<<",nil)";
		}
		if(p->next)
		{
			cout<<"->";
		}
		p=p->next;
	}
	cout<<endl;
}
void ConnectNode(Node *head)//将每个节点依次复制,并连接使得1->1->2->2->3->3->4->4->5->5->6->6
{
	if(!head) return;
	Node *p=head;
	while(p)
	{
		Node *temp=new Node(p->value);//将当前结点复制
		temp->next=p->next;//连接后继结点
		p->next=temp;//重新设置当前结点的后继结点
		p=p->next->next;
	}
}
void ConnectAny(Node *head)//复制每一个结点的any指针
{
	if(!head) return ;
	Node *p=head;
	while(p)
	{
		if(p->any)//必须保证any指针指向的结点不为NULL,否则会报错,因为NULL永远没有next指针
		{
			p->next->any=p->any->next;
		}
		p=p->next->next;//p每次走两格
	}
}
Node *Separate(Node *head)//将原型结点与复制结点分开
{
	if(!head) return NULL;
	Node *p=head;
	Node *head1=head->next;
	while(p->next)//倒数第二个结点对应原型链表的最后一个结点
	{
		Node *temp=p->next;
		p->next=p->next->next;//这个能够保证间隔连接
		p=temp;//继续扫描吧
	}
	return head1;
}
Node *Clone(Node *head)//用hash法保存any指针
{
	if(!head) return NULL;
	ConnectNode(head);
	ConnectAny(head);
	return Separate(head);
}

int main()
{
	Node *head=CreateList();
	cout<<"原链表输出为:";
	VisitList(head);

	cout<<endl<<"复制并连接每个结点:"<<endl;
	ConnectNode(head);
	VisitList(head);

	cout<<endl<<"复制原来每个结点的any指针:"<<endl;
	ConnectAny(head);
	VisitList(head);

        cout<<endl<<"--将复制链表与原型链表分开--"<<endl;
	Node *head1=Separate(head);
	cout<<"输出原型链表:"<<endl;
	VisitList(head);
	cout<<"输出复制链表:"<<endl;
	VisitList(head1);

	cout<<"将以上步骤组合起来,输出复制后的链表:"<<endl;
	head1=Clone(head);
	VisitList(head1);
	FreeList(head);//释放链表空间
	return 0;
}

测试结果如下:

参考资料---------《剑指offer》

算法题:复制复杂链表之复制连接法,布布扣,bubuko.com

时间: 2024-08-05 11:18:19

算法题:复制复杂链表之复制连接法的相关文章

算法题:求链表倒数第K个结点

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:给出一个单链表,返回倒数第K个结点,最后一个结点为倒数第1个. <剑指offer>上面给的解法是设置两个指针,这里记为p1.p2,先让p2走(k-1)步,然后p1.p2同时走,当p2走到最后一个结点时,p1所指向的结点就是倒数第k个结点. 我觉得按照这样的逻辑写代码反而更容易出错,因为我们需要把我两件重要的问题:(1).p2先走(k-1)步:(2)循环结束的条件是p2到达最后一个结点,即p2->next==NULL.显然这样不太

笔试算法题(25):复制拥有多个指针的链表 &amp; 判断二元树B是否为A的子树

出题:定义一个复杂链表:在单向链表的基础上,每个节点附加一个指向链表中其他任意节点的指针sibling,实现CNode* Clone(Cnode *head)函数复制这个复杂链表: 分析: 解法1:将head复制到CHead中,第一次遍历创建CHead中对应head的各个节点(next),第二次遍历创建CHead中对应head各个节 点的sibling链接,由于需要在CHead中找到对应head中的sibling节点,所以需要遍历CHead链表,但是可以用空间换时间的方法:使 用Hash Tab

常见算法题:单链表二路归并

题目:现有两个递增的单链表L1和L2,设计一个算法将L1与L2的所有结点归并到递增的单链表L3中.要求:空间复杂度为O(1). 思路:本题可采用二路归并思路,但题目要求空间复杂度为O(1),因此不能复制结点,只能破坏L1和L2将结点插入到L3中. 代码: void Merge(LinkList &L1,LinkList &L2,LinkList &L3) { LinkList *p=L1.head->next, *q=L2.head->next; LinkList *p

算法题——回文链表

欢迎转载,请附出处: http://blog.csdn.net/as02446418/article/details/47137745 请编写一个函数,检查链表是否为回文. 给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文. 测试样例: {1,2,3,2,1} 返回:true {1,2,3,2,3} 返回:false import java.util.*; /* public class ListNode { int val; ListNode next = n

力扣算法题—092反转链表2

反转从位置 m 到 n 的链表.请使用一趟扫描完成反转. 说明:1 ≤ m ≤ n ≤ 链表长度. 示例: 输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL 1 #include "_000库函数.h" 2 3 4 struct ListNode { 5 int val; 6 ListNode *next; 7 ListNode(int x) : val

算法题:复制复杂链表之空间换时间法

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:复制一个复杂链表,所谓复杂链表指的是每个节点含有两个指针,一个指向单链表的下一个结点,一个指向单链表中的任意某个结点,或者该指针为空. 为了方便起见,我们将待复制的链表称为原型链表,将复制后的新链表称为复制链表,将指向下一个结点的指针定义为next指针,指向其他位置的指针定义为any指针.<剑指offer>上给出了三种解决方法:(1)常规法:(2)空间换时间法:(3)紧随复制法.书上并给出了第三种方法的实现代码.这里我根据书上的提示,

剑指offer之【复杂链表的复制】

题目: 复杂链表的复制 链接: https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?tpId=13&tqId=11178&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为

19--复杂链表的复制。

/* 题目: 复杂链表的复制. struct ComplexListNode { int m_vlaue; ComplexListNode *m_next; ComplexListNode *m_pSibling; }: m_next,连接下一个结点,m_pSibling随便链接结点其他节点. 这样复制结点就有难度,一次遍历明显不可能全部解决. 策略: 第一种方法: 先复制一遍链表,让m_pnext把结点连接起来.第二轮在复制另一个指针,复杂度为O(n*n); 第二种方法: 先复制一遍链表,然后

剑指Offer--026-复杂链表的复制

链接 牛客OJ:复杂链表的复制 九度OJ:http://ac.jobdu.com/problem.php?pid=1524 GitHub代码: 026-复杂链表的复制 CSDN题解:剑指Offer–026-复杂链表的复制 牛客OJ 九度OJ CSDN题解 GitHub代码 复杂链表的复制 1524-复杂链表的复制 剑指Offer–026-复杂链表的复制 026-复杂链表的复制 题意 题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)