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

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

 题目:复制一个复杂链表,所谓复杂链表指的是每个节点含有两个指针,一个指向单链表的下一个结点,一个指向单链表中的任意某个结点,或者该指针为空。

为了方便起见,我们将待复制的链表称为原型链表,将复制后的新链表称为复制链表,将指向下一个结点的指针定义为next指针,指向其他位置的指针定义为any指针。《剑指offer》上给出了三种解决方法:(1)常规法;(2)空间换时间法;(3)紧随复制法。书上并给出了第三种方法的实现代码。这里我根据书上的提示,给出第二种方法的代码

在给出代码之前我们先理解下实现的算法思想。我们知道,如果没有any指针,我们可以很容易得完成复制任务。但是有了any指针,我们就需要考虑如何复制每一个结点的any指针。算法2给出的思想是在构建一个单链表的过程中,设置复制结点与原型结点的一一映射关系,这样在创建完新的单链表之后,我们可以通过原型结点的any指针指向的结点位置,通过查询映射表来获得复制结点的any指针的指向,显然我们可以用hash表或者其他具有映射思想的数据结构,如红黑树。在C++STL中,我们可以采用map容器来实现这一映射。

为了更清晰地理解该复制过程,我们给出如下复杂链表:

 该复制链表的创建代码如下:

#include<iostream>
#include<map>
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)
		{
			cout<<","<<p->any->value<<")";
		}
		else
		{
			cout<<",nil)";
		}
		if(p->next)
		{
			cout<<"->";
		}
		p=p->next;
	}
	cout<<endl;
}

  复制复杂链表的实现代码如下:

Node *Clone(Node *head)//用hash法保存any指针
{
	if(head==NULL)return NULL;
	Node *p=head;//p用于扫描原链表
	Node *head1=NULL,*p1=NULL;//head1指向复制链表,p1用于扫描复制链表
	map<Node*,Node*>m;
	while(p)//依次复制将结点值和next指针
	{
		if(!head1)
		{
			p1=new Node(p->value);
			head1=p1;
		}
		else
		{
			p1->next=new Node(p->value);
			p1=p1->next;
		}
		m[p]=p1;//建立原结点与新结点直接的映射关系
		p=p->next;
	}
	p=head;
	p1=head1;
	while(p)//依次复制每个结点的any指针
	{
		p1->any=m[p->any];
		p=p->next;
		p1=p1->next;
	}
	return head1;
}

 测试代码如下:

int main()
{
	Node *head=CreateList();
	cout<<"原链表输出为:";
	VisitList(head);
	Node *head1=Clone(head);
	cout<<"复制链表输出为:";
	VisitList(head1);
	FreeList(head);//释放链表空间
	return 0;
}

测试结果如下:

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

算法题:复制复杂链表之空间换时间法,布布扣,bubuko.com

时间: 2024-10-26 19:25:00

算法题:复制复杂链表之空间换时间法的相关文章

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

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

递归小题中的空间换时间思想

题目: 如数: 1  1  2  3   5   8   13   21  34  55 ...... 序号: 0  1  2  3   4   5   6     7    8    9 ...... 由用户输入序号,输出对应的数值. 效果: 实现代码: #include <stdio.h> int bian(int num); //static int shu[100]={1,1}; int main() { int num; while ( printf("请输入编号数:&qu

用空间换时间,内存数据库不止于快

近年来随着内存价格的下跌内存数据库正变得日益流行起来,内存数据库的性能也有了飞跃式的发展.然而很多开发人员在考虑内存数据库时只想到了速度,这无疑忽视了内存技术真正的潜力. 内存提供的不仅仅是更快的速度,它也是一种以存储空间换时间的方式.很多开发人员对于内存数据库的使用有一些疑虑,下面我们就来一一说明: 1.内存数据库运行比较快.除了快还有什么别的吗?我们知道内存的读写比硬盘快得多,所以将表全都加载到内存中就可以达到很高的读写速度.虚拟内存的大小受到交换分区的限制而通常交换分区的大小是内存的一到两

求质数数量 - 空间换时间

质数:被自己本身和1整出的数 int getPrimeCount(int value){ int count = 0; int arr[301] = {0};// 0 - is prime , 1 - is not prime int num = (int)sqrt((float)value); for(int i = 2; i <= num ; ++i){ if (!arr[i]){ for(int j = i; i * j < value; ++j){ arr[i * j] = 1; }

代码重构,空间换时间,dictionary 不要用object ,需明确指定类型

代码重构时,因为修改数据库成本很大,于是,可以在缓存中存储一份期待状态的数据结构: 例如,状态转换: 目标状态,中间件状态,原状态,三个状态之间转换时, 原来的逻辑是:目标状态<--中间件状态<--原状态,可以改为<原状态,中间件状态>-->目标状态, 一般情况下,服务器搭建在虚拟机上时,一般是存储位置大小不再考虑范围之内,cpu的计算能力是共享的,所以一个原则是::用"空间"换"时间",, 貌似: hashtable 和 dictio

Elasticsearch实战 | 必要的时候,还得空间换时间!

1.应用场景 实时数据流通过kafka后,根据业务需求,一部分直接借助kafka-connector入Elasticsearch不同的索引中. 另外一部分,则需要先做聚类.分类处理,将聚合出的分类结果存入ES集群的聚类索引中.如下图所示: 业务系统的分层结构可分为:接入层.数据处理层.数据存储层.接口层. 那么问题来了? 我们需要基于聚合(数据处理层)的结果实现检索和聚合分析操作,如何实现更快的检索和更高效的聚合分析效果呢? 2.方案选型 方案一: 只建立一个索引,aggs_index. 数据处

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

题目:现有两个递增的单链表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

R语言空间换时间算法、Hash键值对在字符串处理中的应用

最近一直在处理交通数据,有时间.车牌,经过的路口地址,数据量较大,本篇针对各车经过的路口时间先后顺序,生成贵阳交通的可通行有向图,即相连的交通路口间是否是双向通行.单向通行. 一.关于数据的说明 车牌号,路口地址都是字符串 时间是日期时间格式 数据量大概有680万 二.原始算法代码 rm(list=ls(all=TRUE)) gc() library(RODBC) channel=odbcConnect("transport-connector-R", uid="transp

算法题——回文链表

欢迎转载,请附出处: 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